master
Niko PLP 5 months ago
parent 01816d000b
commit 8396f30975
  1. 37
      ng-app/src-tauri/src/lib.rs
  2. 1
      ng-app/src/api.ts
  3. 31
      ng-app/src/apps/ContainerView.svelte
  4. 0
      ng-app/src/apps/JsonLdViewer.svelte
  5. 0
      ng-app/src/apps/ProseMirrorEditor.svelte
  6. 0
      ng-app/src/apps/ProseMirrorViewer.svelte
  7. 2
      ng-app/src/apps/SparqlQueryEditor.svelte
  8. 4
      ng-app/src/apps/TurtleViewer.svelte
  9. 7
      ng-app/src/lib/Document.svelte
  10. 136
      ng-app/src/lib/FullLayout.svelte
  11. 14
      ng-app/src/lib/components/NavBar.svelte
  12. 2
      ng-app/src/lib/icons/DataClassIcon.svelte
  13. 3
      ng-app/src/lib/icons/GraphQLIcon.svelte
  14. 3
      ng-app/src/lib/icons/ZeraIcon.svelte
  15. 4
      ng-app/src/lib/panes/Files.svelte
  16. 4
      ng-app/src/routes/NURI.svelte
  17. 12
      ng-app/src/store.ts
  18. 77
      ng-app/src/tab.ts
  19. 62
      ng-app/src/zeras.ts
  20. 55
      ng-net/src/app_protocol.rs
  21. 2
      ng-repo/src/block.rs
  22. 11
      ng-repo/src/commit.rs
  23. 10
      ng-repo/src/errors.rs
  24. 1
      ng-repo/src/event.rs
  25. 9
      ng-repo/src/repo.rs
  26. 16
      ng-repo/src/store.rs
  27. 26
      ng-repo/src/types.rs
  28. 46
      ng-sdk-js/src/lib.rs
  29. 13
      ng-verifier/src/commits/mod.rs
  30. 40
      ng-verifier/src/request_processor.rs
  31. 1
      ng-verifier/src/rocksdb_user_storage.rs
  32. 2
      ng-verifier/src/user_storage/branch.rs
  33. 17
      ng-verifier/src/user_storage/repo.rs
  34. 192
      ng-verifier/src/verifier.rs

@ -584,6 +584,42 @@ async fn app_request(request: AppRequest) -> Result<AppResponse, String> {
.map_err(|e| e.to_string()) .map_err(|e| e.to_string())
} }
#[tauri::command(rename_all = "snake_case")]
async fn doc_create(
session_id: u64,
crdt: String,
class_name: String,
store_repo: StoreRepo,
destination: String,
) -> Result<String, String> {
let class = BranchCrdt::from(crdt, class_name).map_err(|e| e.to_string())?;
let destination = DocCreateDestination::from(destination).map_err(|e| e.to_string())?;
let request = AppRequest::V0(AppRequestV0 {
session_id,
command: AppRequestCommandV0::new_create(),
nuri: NuriV0::new_empty(),
payload: Some(AppRequestPayload::V0(AppRequestPayloadV0::Create(
DocCreate {
store: store_repo,
class,
destination,
},
))),
});
let response = nextgraph::local_broker::app_request(request)
.await
.map_err(|e: NgError| e.to_string())?;
if let AppResponse::V0(AppResponseV0::Nuri(nuri)) = response {
Ok(nuri)
} else {
Err("invalid response".to_string())
}
}
#[tauri::command(rename_all = "snake_case")] #[tauri::command(rename_all = "snake_case")]
async fn app_request_with_nuri_command( async fn app_request_with_nuri_command(
nuri: String, nuri: String,
@ -826,6 +862,7 @@ impl AppBuilder {
client_info_rust, client_info_rust,
doc_fetch_private_subscribe, doc_fetch_private_subscribe,
doc_fetch_repo_subscribe, doc_fetch_repo_subscribe,
doc_create,
cancel_stream, cancel_stream,
app_request_stream, app_request_stream,
file_get, file_get,

@ -44,6 +44,7 @@ const mapping = {
"sparql_update": ["session_id","sparql","nuri"], "sparql_update": ["session_id","sparql","nuri"],
"test": [ ], "test": [ ],
"get_device_name": [], "get_device_name": [],
"doc_create": [ "session_id", "crdt", "class_name", "store_repo", "destination" ],
"doc_fetch_private_subscribe": [], "doc_fetch_private_subscribe": [],
"doc_fetch_repo_subscribe": ["repo_o"], "doc_fetch_repo_subscribe": ["repo_o"],
"branch_history": ["session_id", "nuri"], "branch_history": ["session_id", "nuri"],

@ -13,25 +13,28 @@
import { import {
} from "../store"; } from "../store";
import { link } from "svelte-spa-router";
import { Button, Progressbar, Spinner, Alert } from "flowbite-svelte"; import { Button, Progressbar, Spinner, Alert } from "flowbite-svelte";
export let commits; export let commits;
function contained(graph) {
let ret = [];
for (const g of graph) {
console.log(g)
if (g.substring(104,137) === "http://www.w3.org/ns/ldp#contains") {
let nuri = g.substring(140,240);
let hash = nuri.substring(9,16);
ret.push({nuri,hash});
}
}
return ret;
}
</script> </script>
<div class="flex-col"> <div class="flex-col p-5">
<h2>ListView</h2> {#each contained(commits.graph) as doc}
{#if Array.isArray(commits.history.commits)} <div class="flex font-mono"> <a use:link href="/{doc.nuri}">{doc.hash}</a> </div>
{#each commits.history.commits as c}
<div class="flex"> {c[0]} {JSON.stringify(c[1])}</div>
{/each}
{/if}
<div class="flex">
HEADS: {#each commits.heads as head} {head} , {/each}
</div>
TRIPLES:
{#each commits.graph as triple}
<div class="flex"> {triple}</div>
{/each} {/each}
</div> </div>

@ -87,7 +87,7 @@
class="select-none ml-2 mt-2 mb-10 text-gray-600 focus:ring-4 focus:ring-primary-500/50 rounded-lg text-base p-2 text-center inline-flex items-center dark:focus:ring-primary-700/55" class="select-none ml-2 mt-2 mb-10 text-gray-600 focus:ring-4 focus:ring-primary-500/50 rounded-lg text-base p-2 text-center inline-flex items-center dark:focus:ring-primary-700/55"
> >
<Sun class="mr-2 focus:outline-none" tabindex="-1" /> <Sun class="mr-2 focus:outline-none" tabindex="-1" />
View Graph View as Turtle
</button> </button>
{#if results!==undefined} {#if results!==undefined}
<div> <div>

@ -17,7 +17,7 @@
toast_success toast_success
} from "../store"; } from "../store";
import { import {
in_memory_discrete, open_viewer, set_viewer, set_editor, set_view_or_edit, cur_tab in_memory_discrete, open_viewer, set_viewer, set_editor, set_view_or_edit, cur_tab_doc_can_edit
} from "../tab"; } from "../tab";
import{ PencilSquare, RocketLaunch } from "svelte-heros-v2"; import{ PencilSquare, RocketLaunch } from "svelte-heros-v2";
import { t } from "svelte-i18n"; import { t } from "svelte-i18n";
@ -61,7 +61,7 @@
<RocketLaunch tabindex="-1" class="mr-2 focus:outline-none" /> <RocketLaunch tabindex="-1" class="mr-2 focus:outline-none" />
SPARQL Query SPARQL Query
</button> </button>
{#if $cur_tab.doc.can_edit} {#if $cur_tab_doc_can_edit}
<button <button
on:click={openUpdate} on:click={openUpdate}
on:keypress={openUpdate} on:keypress={openUpdate}

@ -24,7 +24,7 @@
import { t } from "svelte-i18n"; import { t } from "svelte-i18n";
import { Button, Progressbar, Spinner, Alert } from "flowbite-svelte"; import { Button, Progressbar, Spinner, Alert } from "flowbite-svelte";
import { inview } from 'svelte-inview'; import { inview } from 'svelte-inview';
import { cur_tab, nav_bar, can_have_header, header_icon, header_title, header_description, cur_branch, set_header_in_view, edit_header_button, cur_app, load_official_app } from "../tab"; import { cur_tab_doc_can_edit, nav_bar, can_have_header, header_icon, header_title, header_description, cur_branch, set_header_in_view, edit_header_button, cur_app, load_official_app, nav_bar_reset_newest } from "../tab";
import NavIcon from "./icons/NavIcon.svelte"; import NavIcon from "./icons/NavIcon.svelte";
export let nuri = ""; export let nuri = "";
@ -32,6 +32,7 @@
let width; let width;
let commits; let commits;
// TODO deals with cases when nuri has :r :w :l (remove them from nuri that should only have :o:v format , and add them in cur_tab)
$: commits = $active_session && nuri && branch_subscribe(nuri, true); $: commits = $active_session && nuri && branch_subscribe(nuri, true);
const inview_options = {};//{rootMargin: "-44px"}; const inview_options = {};//{rootMargin: "-44px"};
@ -54,7 +55,7 @@
<div class="flex justify-left" class:justify-center={width>1024} use:inview={inview_options} on:inview_change={(event) => { <div class="flex justify-left" class:justify-center={width>1024} use:inview={inview_options} on:inview_change={(event) => {
const { inView, entry, scrollDirection, observer, node} = event.detail; const { inView, entry, scrollDirection, observer, node} = event.detail;
if ($cur_branch) { set_header_in_view(inView); } if ($cur_branch) { set_header_in_view(inView); }
if (inView) $nav_bar.newest = 0; if (inView) nav_bar_reset_newest();
}}> }}>
<div class="flex flex-col "> <div class="flex flex-col ">
@ -67,7 +68,7 @@
class:"w-8 h-8 mr-2 mb-2 flex-none focus:outline-none" class:"w-8 h-8 mr-2 mb-2 flex-none focus:outline-none"
}}/> }}/>
{/if} {/if}
{#if $cur_tab.doc.can_edit} {#if $cur_tab_doc_can_edit}
<button class="p-1 mr-2 mb-2 w-8 h-8 flex-none" on:click={openEditHeader} title={$t($edit_header_button)}> <button class="p-1 mr-2 mb-2 w-8 h-8 flex-none" on:click={openEditHeader} title={$t($edit_header_button)}>
<Pencil tabindex=-1 class="w-5 h-5 focus:outline-none" /> <Pencil tabindex=-1 class="w-5 h-5 focus:outline-none" />

@ -35,13 +35,18 @@
// @ts-ignore // @ts-ignore
import { t } from "svelte-i18n"; import { t } from "svelte-i18n";
import { onMount, onDestroy, tick } from "svelte"; import { onMount, onDestroy, tick } from "svelte";
import { cur_tab, cur_viewer, cur_editor, toggle_graph_discrete, cur_tab_update, get_class, get_app, import { cur_tab, cur_viewer, cur_editor, toggle_graph_discrete, cur_tab_update, get_class, get_app, all_tabs, live_editing,
available_editors, available_viewers, set_editor, set_viewer, set_view_or_edit, toggle_live_edit, available_editors, available_viewers, set_editor, set_viewer, set_view_or_edit, toggle_live_edit,
has_editor_chat, all_files_count, all_comments_count, nav_bar, save, hideMenu, show_modal_menu, show_modal_create, openModalCreate } from "../tab"; has_editor_chat, all_files_count, all_comments_count, nav_bar, save, hideMenu, show_modal_menu, show_modal_create,
cur_tab_branch_nuri, cur_tab_doc_can_edit, cur_tab_doc_is_member, cur_tab_right_pane, cur_tab_folders_pane,
cur_tab_toc_pane, cur_tab_show_menu, cur_tab_branch_has_discrete, cur_tab_graph_or_discrete, cur_tab_view_or_edit } from "../tab";
import { import {
active_session, redirect_after_login, toasts, check_has_camera active_session, redirect_after_login, toasts, check_has_camera, toast_error,
reset_toasts,
display_error, openModalCreate
} from "../store"; } from "../store";
import ZeraIcon from "./icons/ZeraIcon.svelte"; import ZeraIcon from "./icons/ZeraIcon.svelte";
import ng from "../api";
import { import {
Home, Home,
@ -144,24 +149,24 @@
pane_left1_used = false; pane_left1_used = false;
pane_left2_used = false; pane_left2_used = false;
pane_right_used = false; pane_right_used = false;
if ($cur_tab.right_pane || $cur_tab.folders_pane || $cur_tab.toc_pane) { if ($cur_tab_right_pane || $cur_tab_folders_pane || $cur_tab_toc_pane) {
$show_modal_menu = true; $show_modal_menu = true;
} }
} }
$: if (panes_available > 0) { $: if (panes_available > 0) {
if ($show_modal_menu && !$cur_tab.show_menu) { if ($show_modal_menu && !$cur_tab_show_menu) {
$show_modal_menu = false; $show_modal_menu = false;
} }
if (panes_available == 1) { if (panes_available == 1) {
if ($cur_tab.right_pane) { if ($cur_tab_right_pane) {
pane_right_used = $cur_tab.right_pane; pane_right_used = $cur_tab_right_pane;
pane_left1_used = false; pane_left1_used = false;
pane_left2_used = false; pane_left2_used = false;
} else if ($cur_tab.folders_pane) { } else if ($cur_tab_folders_pane) {
pane_left1_used = "folders"; pane_left1_used = "folders";
pane_right_used = false; pane_right_used = false;
pane_left2_used = false; pane_left2_used = false;
} else if ($cur_tab.toc_pane) { } else if ($cur_tab_toc_pane) {
pane_left1_used = "toc"; pane_left1_used = "toc";
pane_right_used = false; pane_right_used = false;
pane_left2_used = false; pane_left2_used = false;
@ -171,26 +176,26 @@
pane_right_used = false; pane_right_used = false;
} }
} else if (panes_available == 2) { } else if (panes_available == 2) {
if ($cur_tab.right_pane) { if ($cur_tab_right_pane) {
pane_right_used = $cur_tab.right_pane; pane_right_used = $cur_tab_right_pane;
pane_left2_used = false; pane_left2_used = false;
if ($cur_tab.folders_pane) { if ($cur_tab_folders_pane) {
pane_left1_used = "folders"; pane_left1_used = "folders";
} else if ($cur_tab.toc_pane) { } else if ($cur_tab_toc_pane) {
pane_left1_used = "toc"; pane_left1_used = "toc";
} else { } else {
pane_left1_used = false; pane_left1_used = false;
} }
} else { } else {
pane_right_used = false; pane_right_used = false;
if ($cur_tab.folders_pane) { if ($cur_tab_folders_pane) {
pane_left1_used = "folders"; pane_left1_used = "folders";
if ($cur_tab.toc_pane) { if ($cur_tab_toc_pane) {
pane_left2_used = "toc"; pane_left2_used = "toc";
} else { } else {
pane_left2_used = false; pane_left2_used = false;
} }
} else if ($cur_tab.toc_pane) { } else if ($cur_tab_toc_pane) {
pane_left1_used = "toc"; pane_left1_used = "toc";
pane_left2_used = false; pane_left2_used = false;
} else { } else {
@ -199,19 +204,19 @@
} }
} }
} else if (panes_available == 3) { } else if (panes_available == 3) {
if ($cur_tab.right_pane) { if ($cur_tab_right_pane) {
pane_right_used = $cur_tab.right_pane; pane_right_used = $cur_tab_right_pane;
} else { } else {
pane_right_used = false; pane_right_used = false;
} }
if ($cur_tab.folders_pane) { if ($cur_tab_folders_pane) {
pane_left1_used = "folders"; pane_left1_used = "folders";
if ($cur_tab.toc_pane) { if ($cur_tab_toc_pane) {
pane_left2_used = "toc"; pane_left2_used = "toc";
} else { } else {
pane_left2_used = false; pane_left2_used = false;
} }
} else if ($cur_tab.toc_pane) { } else if ($cur_tab_toc_pane) {
pane_left1_used = "toc"; pane_left1_used = "toc";
pane_left2_used = false; pane_left2_used = false;
} else { } else {
@ -539,15 +544,26 @@
let destination = "store"; let destination = "store";
$: destination = $cur_tab.branch.id === "" ? "mc" : destination == "mc" ? "store" : destination; $: destination = $cur_tab_branch_nuri === "" ? "mc" : destination == "mc" ? "store" : destination;
let config = { tabindex:"-1", let config = { tabindex:"-1",
class:"w-7 h-7 text-gray-700 focus:outline-none dark:text-white" class:"w-7 h-7 text-gray-700 focus:outline-none dark:text-white"
}; };
const new_document = (class_name) => { const new_document = async (class_name) => {
closeModalCreate(); closeModalCreate();
try {
await reset_toasts();
let store_repo = $cur_tab.store.repo;
if (!store_repo) {
store_repo = $all_tabs["o:"+$active_session.private_store_id].store.repo
}
let nuri = await ng.doc_create($active_session.session_id, get_class(class_name)["ng:crdt"], class_name, store_repo, destination);
push("#/"+nuri);
} catch (e) {
toast_error(display_error(e));
}
} }
const new_group = () => { const new_group = () => {
@ -601,7 +617,7 @@
tabindex="0"> tabindex="0">
<XMark class="w-10 h-10 text-gray-700 focus:outline-none dark:text-white"/> <XMark class="w-10 h-10 text-gray-700 focus:outline-none dark:text-white"/>
</div> </div>
{#if !$cur_tab.show_menu} {#if !$cur_tab_show_menu}
<div class="m-3 flex items-center" role="button" aria-label="Back to menu" title="Back to menu" <div class="m-3 flex items-center" role="button" aria-label="Back to menu" title="Back to menu"
on:click={closePaneInModal} on:click={closePaneInModal}
on:keypress={closePaneInModal} on:keypress={closePaneInModal}
@ -610,33 +626,33 @@
<span class="ml-2 inline-block text-gray-700 select-none dark:text-white">Back to menu</span> <span class="ml-2 inline-block text-gray-700 select-none dark:text-white">Back to menu</span>
</div> </div>
{/if} {/if}
{#if $cur_tab.show_menu || (!$cur_tab.folders_pane && !$cur_tab.toc_pane && !$cur_tab.right_pane)} {#if $cur_tab_show_menu || (!$cur_tab_folders_pane && !$cur_tab_toc_pane && !$cur_tab_right_pane)}
<aside style="width:305px; padding:5px;" class="bg-white" aria-label="Sidebar"> <aside style="width:305px; padding:5px;" class="bg-white" aria-label="Sidebar">
<div class="bg-gray-60 overflow-y-auto dark:bg-gray-800"> <div class="bg-gray-60 overflow-y-auto dark:bg-gray-800">
<ul class="mb-10"> <ul class="mb-10">
{#if $cur_tab.branch.has_discrete} {#if $cur_tab_branch_has_discrete}
<li> <li>
<div class="inline-flex graph-discrete-toggle mb-2 ml-2" role="group"> <div class="inline-flex graph-discrete-toggle mb-2 ml-2" role="group">
<button on:click={toggle_graph_discrete} disabled={$cur_tab.graph_or_discrete} type="button" style="border-top-left-radius: 0.375rem;border-bottom-left-radius: 0.375rem;" class:selected-toggle={$cur_tab.graph_or_discrete} class:unselected-toggle={!$cur_tab.graph_or_discrete} class="common-toggle" > <button on:click={toggle_graph_discrete} disabled={$cur_tab_graph_or_discrete} type="button" style="border-top-left-radius: 0.375rem;border-bottom-left-radius: 0.375rem;" class:selected-toggle={$cur_tab_graph_or_discrete} class:unselected-toggle={!$cur_tab_graph_or_discrete} class="common-toggle" >
<Sun class="mr-2 focus:outline-none"/> {$t("doc.graph")} <Sun class="mr-2 focus:outline-none"/> {$t("doc.graph")}
</button> </button>
<button on:click={toggle_graph_discrete} disabled={!$cur_tab.graph_or_discrete} type="button" style="border-top-right-radius: 0.375rem;border-bottom-right-radius: 0.375rem;" class:selected-toggle={!$cur_tab.graph_or_discrete} class:unselected-toggle={$cur_tab.graph_or_discrete} class="common-toggle"> <button on:click={toggle_graph_discrete} disabled={!$cur_tab_graph_or_discrete} type="button" style="border-top-right-radius: 0.375rem;border-bottom-right-radius: 0.375rem;" class:selected-toggle={!$cur_tab_graph_or_discrete} class:unselected-toggle={$cur_tab_graph_or_discrete} class="common-toggle">
<Cloud class="mr-2 focus:outline-none"/> {$t("doc.discrete")} <Cloud class="mr-2 focus:outline-none"/> {$t("doc.discrete")}
</button> </button>
</div> </div>
</li> </li>
{/if} {/if}
{#if $cur_viewer} {#if $cur_viewer}
<MenuItem selected={$cur_tab.view_or_edit} title={$cur_viewer["ng:a"]} clickable={($available_viewers.length > 1 || !$cur_tab.view_or_edit) && function () { if ($available_viewers.length > 1) { open_view_as = !open_view_as; } else { set_view_or_edit(true); hideMenu(); } open_edit_with=false;} }> <MenuItem selected={$cur_tab_view_or_edit} title={$cur_viewer["ng:a"]} clickable={($available_viewers.length > 1 || !$cur_tab_view_or_edit) && function () { if ($available_viewers.length > 1) { open_view_as = !open_view_as; } else { set_view_or_edit(true); hideMenu(); } open_edit_with=false;} }>
<Eye <Eye
tabindex="-1" tabindex="-1"
class="w-7 h-7 text-gray-700 focus:outline-none dark:text-white " class="w-7 h-7 text-gray-700 focus:outline-none dark:text-white "
/> />
<span class="ml-3">{$t("doc.menu.view_as")} {#if $cur_tab.view_or_edit || $available_viewers.length == 1 }{$cur_viewer["ng:n"]}{/if}</span> <span class="ml-3">{$t("doc.menu.view_as")} {#if $cur_tab_view_or_edit || $available_viewers.length == 1 }{$cur_viewer["ng:n"]}{/if}</span>
</MenuItem> </MenuItem>
{#if open_view_as && $available_viewers.length > 1 } {#if open_view_as && $available_viewers.length > 1 }
{#each $available_viewers as viewer} {#each $available_viewers as viewer}
<MenuItem title={viewer["ng:a"]} extraClass="submenu" clickable={(viewer["ng:g"] !== $cur_viewer["ng:g"] || !$cur_tab.view_or_edit) && function () { set_view_or_edit(true); set_viewer(viewer["ng:g"]); hideMenu(); open_view_as = false} }> <MenuItem title={viewer["ng:a"]} extraClass="submenu" clickable={(viewer["ng:g"] !== $cur_viewer["ng:g"] || !$cur_tab_view_or_edit) && function () { set_view_or_edit(true); set_viewer(viewer["ng:g"]); hideMenu(); open_view_as = false} }>
<ZeraIcon <ZeraIcon
zera={viewer["ng:u"]} zera={viewer["ng:u"]}
config={{ config={{
@ -649,18 +665,18 @@
{/each} {/each}
{/if} {/if}
{/if} {/if}
{#if $cur_tab.doc.can_edit} {#if $cur_tab_doc_can_edit}
{#if $cur_editor} {#if $cur_editor}
<MenuItem title={$cur_editor["ng:a"]} selected={!$cur_tab.view_or_edit} clickable={ ($available_editors.length > 1 || $cur_tab.view_or_edit) && function () { if ($available_editors.length > 1) { open_edit_with = !open_edit_with; } else { set_view_or_edit(false); hideMenu(); } open_view_as=false;} }> <MenuItem title={$cur_editor["ng:a"]} selected={!$cur_tab_view_or_edit} clickable={ ($available_editors.length > 1 || $cur_tab_view_or_edit) && function () { if ($available_editors.length > 1) { open_edit_with = !open_edit_with; } else { set_view_or_edit(false); hideMenu(); } open_view_as=false;} }>
<PencilSquare <PencilSquare
tabindex="-1" tabindex="-1"
class="w-7 h-7 text-gray-700 focus:outline-none dark:text-white " class="w-7 h-7 text-gray-700 focus:outline-none dark:text-white "
/> />
<span class="ml-3">{$t("doc.menu.edit_with")} {#if !$cur_tab.view_or_edit || $available_editors.length == 1 }{$cur_editor["ng:n"]}{/if}</span> <span class="ml-3">{$t("doc.menu.edit_with")} {#if !$cur_tab_view_or_edit || $available_editors.length == 1 }{$cur_editor["ng:n"]}{/if}</span>
</MenuItem> </MenuItem>
{#if open_edit_with && $available_editors.length > 1 } {#if open_edit_with && $available_editors.length > 1 }
{#each $available_editors as editor} {#each $available_editors as editor}
<MenuItem title={editor["ng:a"]} extraClass="submenu" clickable={(editor["ng:g"] !== $cur_editor["ng:g"] || $cur_tab.view_or_edit) && function () { set_view_or_edit(false); set_editor(editor["ng:g"]); hideMenu(); open_edit_with = false} }> <MenuItem title={editor["ng:a"]} extraClass="submenu" clickable={(editor["ng:g"] !== $cur_editor["ng:g"] || $cur_tab_view_or_edit) && function () { set_view_or_edit(false); set_editor(editor["ng:g"]); hideMenu(); open_edit_with = false} }>
<ZeraIcon <ZeraIcon
zera={editor["ng:u"]} zera={editor["ng:u"]}
config={{ config={{
@ -685,11 +701,11 @@
<span class="ml-3">{get_app("n:g:z:upload_file")["ng:n"]}</span> <span class="ml-3">{get_app("n:g:z:upload_file")["ng:n"]}</span>
</MenuItem> </MenuItem>
{/if} {/if}
{#if !$cur_tab.view_or_edit || open_edit_with } {#if !$cur_tab_view_or_edit || open_edit_with }
<li title={$t("doc.menu.live_editing_description")} style="margin: 7px 0; padding-left: 32px;" class="toggle"> <li title={$t("doc.menu.live_editing_description")} style="margin: 7px 0; padding-left: 32px;" class="toggle">
<Toggle <Toggle
on:change={ toggle_live_edit } on:change={ toggle_live_edit }
checked={ $cur_tab.doc.live_edit } checked={ $live_editing }
><span class="text-gray-700 text-base">{$t("doc.menu.live_editing")}</span> ><span class="text-gray-700 text-base">{$t("doc.menu.live_editing")}</span>
</Toggle> </Toggle>
</li> </li>
@ -706,7 +722,7 @@
{/if} {/if}
{/if} {/if}
{#if $cur_tab.doc.can_edit} {#if $cur_tab_doc_can_edit}
<MenuItem title={$t("doc.menu.items.new_block.desc")} clickable={ ()=> openAction("new_block") }> <MenuItem title={$t("doc.menu.items.new_block.desc")} clickable={ ()=> openAction("new_block") }>
<PlusCircle <PlusCircle
tabindex="-1" tabindex="-1"
@ -716,22 +732,22 @@
</MenuItem> </MenuItem>
{/if} {/if}
{#if $has_editor_chat} {#if $has_editor_chat}
<MenuItem title={$t("doc.menu.items.editor_chat.desc")} selected={$cur_tab.right_pane == "chat"} clickable={ ()=> openPane("chat") }> <MenuItem title={$t("doc.menu.items.editor_chat.desc")} selected={$cur_tab_right_pane == "chat"} clickable={ ()=> openPane("chat") }>
<Icon tabindex="-1" class="w-7 h-7 text-gray-700 focus:outline-none dark:text-white" variation="outline" color="currentColor" icon={pane_items["chat"]} /> <Icon tabindex="-1" class="w-7 h-7 text-gray-700 focus:outline-none dark:text-white" variation="outline" color="currentColor" icon={pane_items["chat"]} />
<span class="ml-3">{$t("doc.menu.items.editor_chat.label")}</span> <span class="ml-3">{$t("doc.menu.items.editor_chat.label")}</span>
</MenuItem> </MenuItem>
{/if} {/if}
{#if $cur_tab.branch.id} {#if $cur_tab_branch_nuri}
<MenuItem title={$t("doc.menu.items.folders.desc")} selected={$cur_tab.folders_pane} clickable={ ()=> openPane("folders") }> <MenuItem title={$t("doc.menu.items.folders.desc")} selected={$cur_tab_folders_pane} clickable={ ()=> openPane("folders") }>
<Icon tabindex="-1" class="w-7 h-7 text-gray-700 focus:outline-none dark:text-white" variation="outline" color="currentColor" icon={pane_items["folders"]} /> <Icon tabindex="-1" class="w-7 h-7 text-gray-700 focus:outline-none dark:text-white" variation="outline" color="currentColor" icon={pane_items["folders"]} />
<span class="ml-3">{$t("doc.menu.items.folders.label")}</span> <span class="ml-3">{$t("doc.menu.items.folders.label")}</span>
</MenuItem> </MenuItem>
<MenuItem title={$t("doc.menu.items.toc.desc")} selected={$cur_tab.toc_pane} clickable={ ()=> openPane("toc") }> <MenuItem title={$t("doc.menu.items.toc.desc")} selected={$cur_tab_toc_pane} clickable={ ()=> openPane("toc") }>
<Icon tabindex="-1" class="w-7 h-7 text-gray-700 focus:outline-none dark:text-white" variation="outline" color="currentColor" icon={pane_items["toc"]} /> <Icon tabindex="-1" class="w-7 h-7 text-gray-700 focus:outline-none dark:text-white" variation="outline" color="currentColor" icon={pane_items["toc"]} />
<span class="ml-3">{$t("doc.menu.items.toc.label")}</span> <span class="ml-3">{$t("doc.menu.items.toc.label")}</span>
</MenuItem> </MenuItem>
<MenuItem title={$t("doc.menu.items.files.desc")} selected={$cur_tab.right_pane == "files"} clickable={ ()=> openPane("files") }> <MenuItem title={$t("doc.menu.items.files.desc")} selected={$cur_tab_right_pane == "files"} clickable={ ()=> openPane("files") }>
<Icon tabindex="-1" class="w-7 h-7 text-gray-700 focus:outline-none dark:text-white" variation="outline" color="currentColor" icon={pane_items["files"]} /> <Icon tabindex="-1" class="w-7 h-7 text-gray-700 focus:outline-none dark:text-white" variation="outline" color="currentColor" icon={pane_items["files"]} />
<span class="ml-3">{$t("doc.menu.items.files.label")} {$all_files_count}</span> <span class="ml-3">{$t("doc.menu.items.files.label")} {$all_files_count}</span>
</MenuItem> </MenuItem>
@ -752,19 +768,19 @@
{/each} {/each}
{/if} {/if}
<MenuItem title={$t("doc.menu.items.comments.desc")} selected={$cur_tab.right_pane == "comments"} clickable={ ()=> openPane("comments") }> <MenuItem title={$t("doc.menu.items.comments.desc")} selected={$cur_tab_right_pane == "comments"} clickable={ ()=> openPane("comments") }>
<Icon tabindex="-1" class="w-7 h-7 text-gray-700 focus:outline-none dark:text-white" variation="outline" color="currentColor" icon={pane_items["comments"]} /> <Icon tabindex="-1" class="w-7 h-7 text-gray-700 focus:outline-none dark:text-white" variation="outline" color="currentColor" icon={pane_items["comments"]} />
<span class="ml-3">{$t("doc.menu.items.comments.label")} {$all_comments_count}</span> <span class="ml-3">{$t("doc.menu.items.comments.label")} {$all_comments_count}</span>
</MenuItem> </MenuItem>
{#if $cur_tab.doc.is_member} {#if $cur_tab_doc_is_member}
<MenuItem title={$t("doc.menu.items.branches.desc")} selected={$cur_tab.right_pane == "branches"} clickable={ ()=> openPane("branches") }> <MenuItem title={$t("doc.menu.items.branches.desc")} selected={$cur_tab_right_pane == "branches"} clickable={ ()=> openPane("branches") }>
<Icon tabindex="-1" class="w-7 h-7 text-gray-700 focus:outline-none dark:text-white" variation="outline" color="currentColor" icon={pane_items["branches"]} /> <Icon tabindex="-1" class="w-7 h-7 text-gray-700 focus:outline-none dark:text-white" variation="outline" color="currentColor" icon={pane_items["branches"]} />
<span class="ml-3">{$t("doc.menu.items.branches.label")}</span> <span class="ml-3">{$t("doc.menu.items.branches.label")}</span>
</MenuItem> </MenuItem>
{/if} {/if}
<MenuItem title={$t("doc.menu.items.history.desc")} selected={$cur_tab.right_pane == "history"} clickable={ ()=> openPane("history") }> <MenuItem title={$t("doc.menu.items.history.desc")} selected={$cur_tab_right_pane == "history"} clickable={ ()=> openPane("history") }>
<Icon tabindex="-1" class="w-7 h-7 text-gray-700 focus:outline-none dark:text-white" variation="outline" color="currentColor" icon={pane_items["history"]} /> <Icon tabindex="-1" class="w-7 h-7 text-gray-700 focus:outline-none dark:text-white" variation="outline" color="currentColor" icon={pane_items["history"]} />
<span class="ml-3">{$t("doc.menu.items.history.label")}</span> <span class="ml-3">{$t("doc.menu.items.history.label")}</span>
</MenuItem> </MenuItem>
@ -793,7 +809,7 @@
<span class="ml-3">{$t("doc.menu.items.annotate.label")}</span> <span class="ml-3">{$t("doc.menu.items.annotate.label")}</span>
</MenuItem> </MenuItem>
<MenuItem title={$t("doc.menu.items.info.desc")} selected={$cur_tab.right_pane == "info"} clickable={ ()=> openPane("info") }> <MenuItem title={$t("doc.menu.items.info.desc")} selected={$cur_tab_right_pane == "info"} clickable={ ()=> openPane("info") }>
<Icon tabindex="-1" class="w-7 h-7 text-gray-700 focus:outline-none dark:text-white" variation="outline" color="currentColor" icon={pane_items["info"]} /> <Icon tabindex="-1" class="w-7 h-7 text-gray-700 focus:outline-none dark:text-white" variation="outline" color="currentColor" icon={pane_items["info"]} />
<span class="ml-3">{$t("doc.menu.items.info.label")}</span> <span class="ml-3">{$t("doc.menu.items.info.label")}</span>
</MenuItem> </MenuItem>
@ -805,7 +821,7 @@
/> />
<span class="ml-3">{$t("doc.menu.items.notifs.label")}</span> <span class="ml-3">{$t("doc.menu.items.notifs.label")}</span>
</MenuItem> </MenuItem>
{#if $cur_tab.doc.is_member} {#if $cur_tab_doc_is_member}
<MenuItem title={$t("doc.menu.items.permissions.desc")} clickable={ ()=> openAction("permissions") }> <MenuItem title={$t("doc.menu.items.permissions.desc")} clickable={ ()=> openAction("permissions") }>
<LockOpen <LockOpen
tabindex="-1" tabindex="-1"
@ -838,11 +854,11 @@
{/each} {/each}
{/if} {/if}
{/if} {/if}
<MenuItem title={$t("doc.menu.items.mc.desc")} selected={$cur_tab.right_pane == "mc"} clickable={ ()=> openPane("mc") }> <MenuItem title={$t("doc.menu.items.mc.desc")} selected={$cur_tab_right_pane == "mc"} clickable={ ()=> openPane("mc") }>
<Icon tabindex="-1" class="w-7 h-7 text-gray-700 focus:outline-none dark:text-white" variation="outline" color="currentColor" icon={pane_items["mc"]} /> <Icon tabindex="-1" class="w-7 h-7 text-gray-700 focus:outline-none dark:text-white" variation="outline" color="currentColor" icon={pane_items["mc"]} />
<span class="ml-3">{$t("doc.menu.items.mc.label")}</span> <span class="ml-3">{$t("doc.menu.items.mc.label")}</span>
</MenuItem> </MenuItem>
<MenuItem title={$t("doc.menu.items.archive.desc")} selected={$cur_tab.right_pane == "mc"} clickable={ ()=> openArchive() }> <MenuItem title={$t("doc.menu.items.archive.desc")} selected={$cur_tab_right_pane == "mc"} clickable={ ()=> openArchive() }>
<ArchiveBox <ArchiveBox
tabindex="-1" tabindex="-1"
class="w-7 h-7 text-gray-700 focus:outline-none dark:text-white" class="w-7 h-7 text-gray-700 focus:outline-none dark:text-white"
@ -852,19 +868,19 @@
</ul> </ul>
</div> </div>
</aside> </aside>
{:else if $cur_tab.right_pane} {:else if $cur_tab_right_pane}
<div style="height:44px; background-color: rgb(251, 251, 251);" class="flex items-center"> <div style="height:44px; background-color: rgb(251, 251, 251);" class="flex items-center">
<Icon tabindex="-1" class="ml-3 w-8 h-8 text-gray-400 dark:text-white focus:outline-none " variation="outline" color="currentColor" icon={pane_items[$cur_tab.right_pane]} /> <Icon tabindex="-1" class="ml-3 w-8 h-8 text-gray-400 dark:text-white focus:outline-none " variation="outline" color="currentColor" icon={pane_items[$cur_tab_right_pane]} />
<span class="ml-2 inline-block text-gray-500 select-none dark:text-white">{$t(`doc.menu.items.${$cur_tab.right_pane}.label`)}</span> <span class="ml-2 inline-block text-gray-500 select-none dark:text-white">{$t(`doc.menu.items.${$cur_tab_right_pane}.label`)}</span>
</div> </div>
<Pane pane_name={$cur_tab.right_pane}/> <Pane pane_name={$cur_tab_right_pane}/>
{:else if $cur_tab.folders_pane} {:else if $cur_tab_folders_pane}
<div style="height:44px; background-color: rgb(251, 251, 251);" class="flex items-center"> <div style="height:44px; background-color: rgb(251, 251, 251);" class="flex items-center">
<Icon tabindex="-1" class="ml-3 w-8 h-8 text-gray-400 dark:text-white focus:outline-none " variation="outline" color="currentColor" icon={pane_items["folders"]} /> <Icon tabindex="-1" class="ml-3 w-8 h-8 text-gray-400 dark:text-white focus:outline-none " variation="outline" color="currentColor" icon={pane_items["folders"]} />
<span class="ml-2 inline-block text-gray-500 select-none dark:text-white">{$t("doc.menu.items.folders.label")}</span> <span class="ml-2 inline-block text-gray-500 select-none dark:text-white">{$t("doc.menu.items.folders.label")}</span>
</div> </div>
<Pane pane_name="folders"/> <Pane pane_name="folders"/>
{:else if $cur_tab.toc_pane} {:else if $cur_tab_toc_pane}
<div style="height:44px; background-color: rgb(251, 251, 251);" class="flex items-center"> <div style="height:44px; background-color: rgb(251, 251, 251);" class="flex items-center">
<Icon tabindex="-1" class="ml-3 w-8 h-8 text-gray-400 dark:text-white focus:outline-none " variation="outline" color="currentColor" icon={pane_items["toc"]} /> <Icon tabindex="-1" class="ml-3 w-8 h-8 text-gray-400 dark:text-white focus:outline-none " variation="outline" color="currentColor" icon={pane_items["toc"]} />
<span class="ml-2 inline-block text-gray-500 select-none dark:text-white">{$t("doc.menu.items.toc.label")}</span> <span class="ml-2 inline-block text-gray-500 select-none dark:text-white">{$t("doc.menu.items.toc.label")}</span>
@ -893,11 +909,11 @@
<div class="bg-gray-60 overflow-y-auto dark:bg-gray-800"> <div class="bg-gray-60 overflow-y-auto dark:bg-gray-800">
<ul class="mb-10"> <ul class="mb-10">
<Radio class="clickable m-2 text-base font-normal" name="destination" disabled={!$cur_tab.branch.id} value="store" bind:group={destination}> <Radio class="clickable m-2 text-base font-normal" name="destination" disabled={!$cur_tab_branch_nuri} value="store" bind:group={destination}>
<Square3Stack3d class="w-7 h-7 text-gray-700 focus:outline-none dark:text-white mr-2" /> <Square3Stack3d class="w-7 h-7 text-gray-700 focus:outline-none dark:text-white mr-2" />
{$t("doc.destination.store")} {$t("doc.destination.store")}
</Radio> </Radio>
<Radio class="clickable m-2 text-base font-normal" name="destination" disabled={!$cur_tab.branch.id} value="stream" bind:group={destination}> <Radio class="clickable m-2 text-base font-normal" name="destination" disabled={!$cur_tab_branch_nuri} value="stream" bind:group={destination}>
<Bolt class="w-7 h-7 text-gray-700 focus:outline-none dark:text-white mr-2" /> <Bolt class="w-7 h-7 text-gray-700 focus:outline-none dark:text-white mr-2" />
{#if $cur_tab.store.store_type !== "dialog"}{$t("doc.destination.stream")}{:else}{$t("doc.destination.dialog")}{/if} {#if $cur_tab.store.store_type !== "dialog"}{$t("doc.destination.stream")}{:else}{$t("doc.destination.dialog")}{/if}
</Radio> </Radio>

@ -24,7 +24,7 @@
Popover, Popover,
} from "flowbite-svelte"; } from "flowbite-svelte";
import {save, nav_bar, showMenu, cur_tab, cur_tab_store_name_override, cur_tab_store_icon_override} from "../../tab"; import {nav_bar_newest, save, nav_bar, showMenu, cur_tab_header_in_view, cur_tab_store_name_override, cur_tab_store_icon_override, cur_tab_persistent_error} from "../../tab";
export let scrollToTop = () => {}; export let scrollToTop = () => {};
@ -56,22 +56,22 @@
<div style="cursor:pointer;" class:pl-3={!$nav_bar.back && !$nav_bar.icon} class="grow w-10 items-center flex px-1" on:click={scrollToTop} on:keypress={scrollToTop}> <div style="cursor:pointer;" class:pl-3={!$nav_bar.back && !$nav_bar.icon} class="grow w-10 items-center flex px-1" on:click={scrollToTop} on:keypress={scrollToTop}>
<span class="inline-block truncate" > {$cur_tab_store_name_override || $nav_bar.title} </span> <span class="inline-block truncate" > {$cur_tab_store_name_override || $nav_bar.title} </span>
</div> </div>
{#if $nav_bar.newest && !$cur_tab.header_in_view} {#if $nav_bar_newest && !$cur_tab_header_in_view}
<div role="button" tabindex="0" class="flex-none m-1 rounded-full bg-primary-700 text-white dark:bg-primary-700" on:click={scrollToTop} on:keypress={scrollToTop}> <div role="button" tabindex="0" class="flex-none m-1 rounded-full bg-primary-700 text-white dark:bg-primary-700" on:click={scrollToTop} on:keypress={scrollToTop}>
<div class="flex items-center grow pr-2"> <div class="flex items-center grow pr-2">
<ChevronDoubleUp tabindex="-1" class="w-6 h-6 m-1 focus:outline-none"/> <ChevronDoubleUp tabindex="-1" class="w-6 h-6 m-1 focus:outline-none"/>
<span class="inline-block">{@html $nav_bar.newest < 100 ? "+"+$nav_bar.newest : "<span class=\"text-xl\">&infin;</span>"}</span> <span class="inline-block">{@html $nav_bar_newest < 100 ? "+"+$nav_bar_newest : "<span class=\"text-xl\">&infin;</span>"}</span>
</div> </div>
</div> </div>
{/if} {/if}
{#if $cur_tab.persistent_error} {#if $cur_tab_persistent_error}
<div id="error_popover_btn" tabindex="0" class="flex-none w-10" role="button" title={$cur_tab.persistent_error.title + ". Click for more details"}> <div id="error_popover_btn" tabindex="0" class="flex-none w-10" role="button" title={$cur_tab_persistent_error.title + ". Click for more details"}>
<ExclamationTriangle variation="outline" tabindex="-1" strokeWidth="2" class="w-9 h-9 mt-1 text-red-700 focus:outline-none"/> <ExclamationTriangle variation="outline" tabindex="-1" strokeWidth="2" class="w-9 h-9 mt-1 text-red-700 focus:outline-none"/>
</div> </div>
<Popover class="text-left text-black w-[300px] text-sm error-popover" title={$cur_tab.persistent_error.title} triggeredBy="#error_popover_btn" trigger="click" placement = 'bottom' <Popover class="text-left text-black w-[300px] text-sm error-popover" title={$cur_tab_persistent_error.title} triggeredBy="#error_popover_btn" trigger="click" placement = 'bottom'
open={true} open={true}
>{@html $cur_tab.persistent_error.desc} >{@html $cur_tab_persistent_error.desc}
<br/><br/><span class="text-primary-700" on:click={closeErrorPopup} on:keypress={closeErrorPopup} role="button" tabindex="0">Dismiss</span> <br/><br/><span class="text-primary-700" on:click={closeErrorPopup} on:keypress={closeErrorPopup} role="button" tabindex="0">Dismiss</span>
</Popover> </Popover>
{:else if $nav_bar.save !== undefined} {:else if $nav_bar.save !== undefined}

@ -87,6 +87,7 @@
import RustIcon from "./RustIcon.svelte"; import RustIcon from "./RustIcon.svelte";
import SvelteIcon from "./SvelteIcon.svelte"; import SvelteIcon from "./SvelteIcon.svelte";
import ReactIcon from "./ReactIcon.svelte"; import ReactIcon from "./ReactIcon.svelte";
import GraphQLIcon from "./GraphQLIcon.svelte";
export let config = {}; export let config = {};
export let dataClass: string; export let dataClass: string;
@ -100,6 +101,7 @@
contract: ClipboardDocumentCheck, contract: ClipboardDocumentCheck,
"query:text": MagnifyingGlass, "query:text": MagnifyingGlass,
"query:web": MagnifyingGlass, "query:web": MagnifyingGlass,
"query:graphql": GraphQLIcon,
"data:graph": Sun, "data:graph": Sun,
"data:json": JsonIcon, "data:json": JsonIcon,
"data:table": TableCells, "data:table": TableCells,

@ -0,0 +1,3 @@
<svg viewBox="0 0 32 32" fill="currentColor" width="24" height="24" tabindex="-1" class={$$props.class || ''} style={$$props.style || ''} xmlns="http://www.w3.org/2000/svg">
<path d="M18.734 3.667l6.578 3.802c1.089-1.146 2.901-1.193 4.047-0.104 0.193 0.188 0.365 0.401 0.5 0.635 0.786 1.37 0.313 3.12-1.063 3.906-0.229 0.13-0.479 0.234-0.745 0.297v7.599c1.531 0.365 2.474 1.896 2.109 3.427-0.063 0.271-0.172 0.531-0.307 0.771-0.792 1.365-2.536 1.833-3.906 1.042-0.26-0.146-0.5-0.344-0.698-0.568l-6.542 3.776c0.495 1.495-0.318 3.109-1.813 3.604-0.292 0.099-0.594 0.146-0.896 0.146-1.573 0-2.854-1.271-2.854-2.849 0-0.271 0.042-0.547 0.12-0.813l-6.583-3.797c-1.089 1.141-2.896 1.188-4.036 0.094-1.135-1.089-1.177-2.891-0.094-4.031 0.38-0.396 0.865-0.677 1.396-0.807v-7.599c-1.531-0.365-2.479-1.906-2.109-3.443 0.063-0.266 0.167-0.521 0.302-0.755 0.786-1.365 2.536-1.833 3.901-1.042 0.234 0.135 0.453 0.302 0.641 0.5l6.583-3.797c-0.448-1.51 0.417-3.099 1.922-3.542 0.26-0.083 0.536-0.12 0.813-0.12 1.573 0 2.854 1.271 2.854 2.844 0 0.281-0.042 0.557-0.12 0.823zM18.047 4.839c-0.026 0.026-0.047 0.052-0.078 0.078l8.615 14.917c0.036-0.010 0.078-0.021 0.109-0.031v-7.609c-1.526-0.375-2.453-1.922-2.073-3.448 0.005-0.031 0.016-0.068 0.021-0.099zM14.026 4.917l-0.078-0.078-6.594 3.802c0.438 1.51-0.438 3.089-1.948 3.526-0.036 0.010-0.068 0.016-0.104 0.026v7.609l0.115 0.031 8.615-14.917zM16.797 5.594c-0.521 0.146-1.073 0.146-1.589 0l-8.615 14.917c0.391 0.375 0.667 0.859 0.802 1.391h17.214c0.13-0.531 0.406-1.016 0.802-1.396zM18.109 27.229l6.552-3.786c-0.021-0.063-0.036-0.125-0.052-0.188h-17.219l-0.031 0.109 6.589 3.802c0.516-0.536 1.245-0.87 2.052-0.87 0.839 0 1.589 0.359 2.109 0.932z"/>
</svg>

After

Width:  |  Height:  |  Size: 1.7 KiB

@ -77,6 +77,7 @@
import JsonLdIcon from "./JsonLdIcon.svelte"; import JsonLdIcon from "./JsonLdIcon.svelte";
import RdfIcon from "./RdfIcon.svelte"; import RdfIcon from "./RdfIcon.svelte";
import TurtleIcon from "./TurtleIcon.svelte"; import TurtleIcon from "./TurtleIcon.svelte";
import GraphQLIcon from "./GraphQLIcon.svelte";
export let config = {}; export let config = {};
export let zera: string; export let zera: string;
@ -91,7 +92,7 @@
compose: QueueList, compose: QueueList,
sparql_query: RocketLaunch, sparql_query: RocketLaunch,
sparnatural: CursorArrowRays, sparnatural: CursorArrowRays,
graphql: Cube, graphql: GraphQLIcon,
invoke: Play, invoke: Play,
ontology_viewer: ArrowsPointingOut, ontology_viewer: ArrowsPointingOut,
download: DocumentArrowDown, download: DocumentArrowDown,

@ -17,7 +17,7 @@
online, online,
get_blob, get_blob,
} from "../../store"; } from "../../store";
import { cur_tab } from "../../tab"; import { cur_tab, cur_tab_doc_can_edit } from "../../tab";
import { import {
ExclamationTriangle, ExclamationTriangle,
ArrowDownTray, ArrowDownTray,
@ -166,7 +166,7 @@
<div class="w-full"> <div class="w-full">
{#if $cur_tab.doc.can_edit} {#if $cur_tab_doc_can_edit}
<div class="row pt-2 w-full"> <div class="row pt-2 w-full">
<Button <Button

@ -20,7 +20,7 @@
active_session, active_session,
} from "../store"; } from "../store";
import { import {
change_nav_bar, cur_tab, reset_in_memory change_nav_bar, cur_tab, reset_in_memory, cur_tab_doc_is_store, cur_tab_store_type
} from "../tab"; } from "../tab";
import { import {
Square3Stack3d, Square3Stack3d,
@ -42,7 +42,7 @@
</script> </script>
<FullLayout> <FullLayout>
{#if nuri && $cur_tab.doc.is_store && $cur_tab.store.store_type === "group"} {#if nuri && $cur_tab_doc_is_store && $cur_tab_store_type === "group"}
<div class="bg-gray-100 flex p-1 justify-around md:justify-start h-11 gap-0 xs:gap-3 md:gap-10 text-gray-500"> <div class="bg-gray-100 flex p-1 justify-around md:justify-start h-11 gap-0 xs:gap-3 md:gap-10 text-gray-500">
<div class="overflow-hidden w-16 xs:ml-3 flex justify-start" role="button" tabindex="0"> <div class="overflow-hidden w-16 xs:ml-3 flex justify-start" role="button" tabindex="0">
<ChatBubbleLeftRight tabindex="-1" class="mt-1 flex-none w-7 h-7 mr-1 focus:outline-none "/><div class="text-xs xs:text-sm flex items-center"><div style="overflow-wrap: anywhere;" class="max-h-8 xs:max-h-10">{$t("doc.header.buttons.chat")}</div></div> <ChatBubbleLeftRight tabindex="-1" class="mt-1 flex-none w-7 h-7 mr-1 focus:outline-none "/><div class="text-xs xs:text-sm flex items-center"><div style="overflow-wrap: anywhere;" class="max-h-8 xs:max-h-10">{$t("doc.header.buttons.chat")}</div></div>

@ -17,7 +17,7 @@ import {
} from "svelte/store"; } from "svelte/store";
import { register, init, locale, format } from "svelte-i18n"; import { register, init, locale, format } from "svelte-i18n";
import ng from "./api"; import ng from "./api";
import { persistent_error, update_class, update_branch_display, open_branch, tab_update, change_nav_bar, cur_branch, cur_tab } from "./tab"; import { persistent_error, update_class, update_branch_display, open_branch, tab_update, change_nav_bar, cur_branch, cur_tab, show_modal_create } from "./tab";
import { encode } from "./base64url"; import { encode } from "./base64url";
let all_branches = {}; let all_branches = {};
@ -45,7 +45,7 @@ init({
}); });
export const display_error = (error: string) => { export const display_error = (error: string) => {
if (e.message) return e.message; if (error.message) return error.message;
//console.log(error); //console.log(error);
// TODO: Check, if error tranlsation does not exist // TODO: Check, if error tranlsation does not exist
const parts = error.split(":"); const parts = error.split(":");
@ -141,6 +141,11 @@ export const toast_success = (text) => {
toast("success", text); toast("success", text);
} }
export const openModalCreate = async () => {
await reset_toasts()
show_modal_create.set(true);
}
export const scanned_qr_code = writable(""); export const scanned_qr_code = writable("");
export const wallet_from_import = writable<null | object>(null); export const wallet_from_import = writable<null | object>(null);
@ -525,6 +530,9 @@ export const branch_subscribe = function(nuri:string, in_tab:boolean) {
if (response.V0.TabInfo.store?.overlay) { if (response.V0.TabInfo.store?.overlay) {
$cur_tab.store.overlay = response.V0.TabInfo.store.overlay; $cur_tab.store.overlay = response.V0.TabInfo.store.overlay;
} }
if (response.V0.TabInfo.store?.repo) {
$cur_tab.store.repo = response.V0.TabInfo.store.repo;
}
if (response.V0.TabInfo.store?.store_type) { if (response.V0.TabInfo.store?.store_type) {
if (get(cur_branch) == nuri) { if (get(cur_branch) == nuri) {

@ -127,8 +127,12 @@ const class_to_viewers_editors = (class_name: string) => {
if (class_def["ng:o"]) graph_viewers.push(class_def["ng:o"]); if (class_def["ng:o"]) graph_viewers.push(class_def["ng:o"]);
if (class_def["ng:w"]) graph_editors.push(class_def["ng:w"]); if (class_def["ng:w"]) graph_editors.push(class_def["ng:w"]);
} }
graph_viewers.push.apply(graph_viewers, find_viewers_for_class("data:graph")); for (const additional_g_v of find_viewers_for_class("data:graph")){
graph_editors.push.apply(graph_editors, find_editors_for_class("data:graph")); if (!graph_viewers.includes(additional_g_v)) graph_viewers.push(additional_g_v);
}
for (const additional_g_e of find_editors_for_class("data:graph")){
if (!graph_editors.includes(additional_g_e)) graph_editors.push(additional_g_e);
}
let graph_viewer = graph_viewers[0]; let graph_viewer = graph_viewers[0];
let graph_editor = graph_editors[0]; let graph_editor = graph_editors[0];
@ -197,10 +201,6 @@ export const show_modal_menu = writable(false);
export const show_modal_create = writable(false); export const show_modal_create = writable(false);
export const openModalCreate = () => {
show_modal_create.set(true);
}
export const in_memory_graph = writable(""); export const in_memory_graph = writable("");
export const in_memory_discrete = writable(""); export const in_memory_discrete = writable("");
@ -216,6 +216,7 @@ export const reset_in_memory = () => {
export const all_tabs = writable({ export const all_tabs = writable({
"":{ "":{
store: { store: {
repo: false, // a StoreRepo serialization
overlay: "", // "v:" overlay: "", // "v:"
has_outer: "", // "l:" has_outer: "", // "l:"
store_type: "", //"public" "protected", "private", "group", "dialog", store_type: "", //"public" "protected", "private", "group", "dialog",
@ -309,11 +310,53 @@ export const set_header_in_view = function(val) {
export const cur_branch = writable(""); export const cur_branch = writable("");
export const cur_tab = derived([cur_branch, all_tabs], ([cb, all]) => all[cb]); export const cur_tab = derived([cur_branch, all_tabs], ([cb, all]) => {return all[cb];});
export const can_have_header = derived(cur_tab, ($cur_tab) => { export const can_have_header = derived(cur_tab, ($cur_tab) => {
return !($cur_tab.doc.is_store && ( $cur_tab.store.store_type === "private" || $cur_tab.store.store_type === "dialog")); return !($cur_tab.doc.is_store && ( $cur_tab.store.store_type === "private" || $cur_tab.store.store_type === "dialog"));
}); });
export const cur_tab_branch_nuri = derived(cur_tab, ($cur_tab) => {
return $cur_tab.branch.nuri;
});
export const cur_tab_doc_can_edit = derived(cur_tab, ($cur_tab) => {
return $cur_tab.doc.can_edit;
});
export const cur_tab_doc_is_store = derived(cur_tab, ($cur_tab) => {
return $cur_tab.doc.is_store;
});
export const cur_tab_doc_is_member = derived(cur_tab, ($cur_tab) => {
return $cur_tab.doc.is_member;
});
export const cur_tab_store_type = derived(cur_tab, ($cur_tab) => {
return $cur_tab.store.store_type;
});
export const cur_tab_persistent_error = derived(cur_tab, ($cur_tab) => {
return $cur_tab.persistent_error;
});
export const cur_tab_header_in_view = derived(cur_tab, ($cur_tab) => {
return $cur_tab.header_in_view;
});
export const cur_tab_right_pane = derived(cur_tab, ($cur_tab) => {
return $cur_tab.right_pane;
});
export const cur_tab_folders_pane = derived(cur_tab, ($cur_tab) => {
return $cur_tab.folders_pane;
});
export const cur_tab_toc_pane = derived(cur_tab, ($cur_tab) => {
return $cur_tab.toc_pane;
});
export const cur_tab_show_menu = derived(cur_tab, ($cur_tab) => {
return $cur_tab.show_menu;
});
export const cur_tab_branch_has_discrete = derived(cur_tab, ($cur_tab) => {
return $cur_tab.branch.has_discrete;
});
export const cur_tab_graph_or_discrete = derived(cur_tab, ($cur_tab) => {
return $cur_tab.graph_or_discrete;
});
export const cur_tab_view_or_edit = derived(cur_tab, ($cur_tab) => {
return $cur_tab.view_or_edit;
});
export const edit_header_button = derived(cur_tab, ($cur_tab) => { export const edit_header_button = derived(cur_tab, ($cur_tab) => {
return ($cur_tab.doc.is_store && ( $cur_tab.store.store_type === "public" || $cur_tab.store.store_type === "protected"))? "doc.header.buttons.edit_profile" : "doc.header.buttons.edit"; return ($cur_tab.doc.is_store && ( $cur_tab.store.store_type === "public" || $cur_tab.store.store_type === "protected"))? "doc.header.buttons.edit_profile" : "doc.header.buttons.edit";
@ -382,6 +425,15 @@ export const cur_tab_update = function( fn ) {
}); });
}; };
export const live_editing = writable(false);
live_editing.subscribe((val) => {
cur_tab_update((old)=> {
old.doc.live_edit = val;
return old;
});
});
export const showMenu = () => { export const showMenu = () => {
show_modal_menu.set(true); show_modal_menu.set(true);
cur_tab_update(ct => { cur_tab_update(ct => {
@ -409,6 +461,17 @@ export const nav_bar = writable({
toasts: [], toasts: [],
}); });
export const nav_bar_newest = derived(nav_bar, ($nav_bar) => {
return $nav_bar.newest;
});
export const nav_bar_reset_newest = () => {
nav_bar.update((old) => {
old.newest = 0;
return old;
});
}
export const change_nav_bar = (icon, title, back) => { export const change_nav_bar = (icon, title, back) => {
nav_bar.update((old) => { nav_bar.update((old) => {
if (icon !== undefined) { if (icon !== undefined) {

@ -21,6 +21,16 @@
//"n:g:z:app_store", "n:g:z:app_editor", "n:xxx.xx.xx:yy", "o:xx:yy:zz" //"n:g:z:app_store", "n:g:z:app_editor", "n:xxx.xx.xx:yy", "o:xx:yy:zz"
export const official_apps = { export const official_apps = {
"n:g:z:sparql_update": {
"ng:n": "SPARQL Update",
"ng:a": "View, edit and invoke a Graph SPARQL Update",
"ng:c": "app",
"ng:u": "sparql_query",//favicon. can be a did:ng:j
"ng:g": "n:g:z:sparql_update",
"ng:b": "SparqlUpdateEditor", // YASGUI of Zazuko https://github.com/zazuko/trifid/tree/main/packages/yasgui
"ng:o": [],
"ng:w": ["query:sparql_update","data:graph"],
},
"n:g:z:json_ld_editor": { "n:g:z:json_ld_editor": {
"ng:n": "JSON-LD Editor", "ng:n": "JSON-LD Editor",
"ng:a": "Edit the RDF Graph as JSON-LD", "ng:a": "Edit the RDF Graph as JSON-LD",
@ -48,6 +58,26 @@ export const official_apps = {
"ng:b": "TripleEditor", "ng:b": "TripleEditor",
"ng:w": ["data:graph"], "ng:w": ["data:graph"],
}, },
"n:g:z:sparql_query": {
"ng:n": "SPARQL Query",
"ng:a": "View, edit and invoke a Graph SPARQL query",
"ng:c": "app",
"ng:u": "sparql_query",//favicon. can be a did:ng:j
"ng:g": "n:g:z:sparql_query",
"ng:b": "SparqlQueryEditor", // YASGUI of Zazuko https://github.com/zazuko/trifid/tree/main/packages/yasgui
"ng:o": ["data:graph"],
"ng:w": ["query:sparql"],
},
"n:g:z:rdf_viewer:turtle": { // https://github.com/highlightjs/highlightjs-turtle/tree/master
"ng:n": "Turtle",
"ng:a": "View the RDF Graph in Turtle format",
"ng:c": "app",
"ng:u": "turtle_viewer",//favicon. can be a did:ng:j
"ng:g": "n:g:z:rdf_viewer:turtle",
"ng:b": "TurtleViewer",
"ng:o": ["data:graph"],
"ng:w": [],
},
"n:g:z:json_ld_viewer": { "n:g:z:json_ld_viewer": {
"ng:n": "JSON-LD", "ng:n": "JSON-LD",
"ng:a": "View the RDF Graph as JSON-LD", "ng:a": "View the RDF Graph as JSON-LD",
@ -85,16 +115,6 @@ export const official_apps = {
"ng:b": "TripleViewer", "ng:b": "TripleViewer",
"ng:o": ["data:graph"], "ng:o": ["data:graph"],
}, },
"n:g:z:sparql_query": {
"ng:n": "SPARQL Query",
"ng:a": "View, edit and invoke a Graph SPARQL query",
"ng:c": "app",
"ng:u": "sparql_query",//favicon. can be a did:ng:j
"ng:g": "n:g:z:sparql_query",
"ng:b": "SparqlQueryEditor", // YASGUI of Zazuko https://github.com/zazuko/trifid/tree/main/packages/yasgui
"ng:o": ["data:graph"],
"ng:w": ["query:sparql"],
},
"n:g:z:sparql_query:sparnatural": { "n:g:z:sparql_query:sparnatural": {
"ng:n": "SPARNatural Query", "ng:n": "SPARNatural Query",
"ng:a": "View, edit and invoke a Graph SPARQL query with SPARnatural tool", "ng:a": "View, edit and invoke a Graph SPARQL query with SPARnatural tool",
@ -115,26 +135,6 @@ export const official_apps = {
"ng:o": ["data:graph"], "ng:o": ["data:graph"],
"ng:w": ["query:graphql"], "ng:w": ["query:graphql"],
}, },
"n:g:z:sparql_update": {
"ng:n": "SPARQL Update",
"ng:a": "View, edit and invoke a Graph SPARQL Update",
"ng:c": "app",
"ng:u": "sparql_query",//favicon. can be a did:ng:j
"ng:g": "n:g:z:sparql_update",
"ng:b": "SparqlUpdateEditor", // YASGUI of Zazuko https://github.com/zazuko/trifid/tree/main/packages/yasgui
"ng:o": [],
"ng:w": ["query:sparql_update","data:graph"],
},
"n:g:z:rdf_viewer:turtle": { // https://github.com/highlightjs/highlightjs-turtle/tree/master
"ng:n": "Turtle",
"ng:a": "View the RDF Graph in Turtle format",
"ng:c": "app",
"ng:u": "turtle_viewer",//favicon. can be a did:ng:j
"ng:g": "n:g:z:rdf_viewer:turtle",
"ng:b": "TurtleViewer",
"ng:o": ["data:graph"],
"ng:w": [],
},
"n:g:z:rdf_viewer:n3": { // ? "n:g:z:rdf_viewer:n3": { // ?
"ng:n": "N3", "ng:n": "N3",
"ng:a": "View the RDF Graph in N3 format", "ng:a": "View the RDF Graph in N3 format",
@ -312,7 +312,7 @@ export const official_apps = {
"ng:c": "app", "ng:c": "app",
"ng:u": "post",//favicon. can be a did:ng:j "ng:u": "post",//favicon. can be a did:ng:j
"ng:g": "n:g:z:post:rich", "ng:g": "n:g:z:post:rich",
"ng:b": "PostRichViewer", // https://www.npmjs.com/package/prosemirror-to-html-js or https://prosemirror.net/docs/ref/version/0.4.0.html#toDOM https://prosemirror.net/docs/ref/version/0.4.0.html#toHTML "ng:b": "ProseMirrorViewer", // https://www.npmjs.com/package/prosemirror-to-html-js or https://prosemirror.net/docs/ref/version/0.4.0.html#toDOM https://prosemirror.net/docs/ref/version/0.4.0.html#toHTML
"ng:o": ["post:rich"], "ng:o": ["post:rich"],
"ng:w": [], "ng:w": [],
}, },

@ -187,6 +187,19 @@ pub struct NuriV0 {
} }
impl NuriV0 { impl NuriV0 {
pub fn new_empty() -> Self {
NuriV0 {
identity: None,
target: NuriTargetV0::None,
entire_store: false,
object: None,
branch: None,
overlay: None,
access: vec![],
topic: None,
locator: vec![],
}
}
pub fn copy_target_from(&mut self, nuri: &NuriV0) { pub fn copy_target_from(&mut self, nuri: &NuriV0) {
self.target = nuri.target.clone(); self.target = nuri.target.clone();
} }
@ -198,6 +211,20 @@ impl NuriV0 {
format!("{DID_PREFIX}:c:{commit_base64}:v:{overlay_id}") format!("{DID_PREFIX}:c:{commit_base64}:v:{overlay_id}")
} }
pub fn from_store_repo(store_repo: &StoreRepo) -> Self {
NuriV0 {
identity: None,
target: NuriTargetV0::Repo(store_repo.repo_id().clone()),
entire_store: false,
object: None,
branch: None,
overlay: None,
access: vec![],
topic: None,
locator: vec![],
}
}
pub fn repo_graph_name(repo_id: &RepoId, overlay_id: &OverlayId) -> String { pub fn repo_graph_name(repo_id: &RepoId, overlay_id: &OverlayId) -> String {
format!("{DID_PREFIX}:o:{repo_id}:v:{overlay_id}") format!("{DID_PREFIX}:o:{repo_id}:v:{overlay_id}")
} }
@ -439,6 +466,9 @@ impl AppRequestCommandV0 {
pub fn new_history() -> Self { pub fn new_history() -> Self {
AppRequestCommandV0::Fetch(AppFetchContentV0::History) AppRequestCommandV0::Fetch(AppFetchContentV0::History)
} }
pub fn new_create() -> Self {
AppRequestCommandV0::Create
}
} }
#[derive(Clone, Debug, Serialize, Deserialize)] #[derive(Clone, Debug, Serialize, Deserialize)]
@ -599,10 +629,29 @@ pub struct DocAddFile {
pub object: ObjectRef, pub object: ObjectRef,
} }
#[derive(Clone, Debug, Serialize, Deserialize)]
pub enum DocCreateDestination {
Store,
Stream,
MagicCarpet,
}
impl DocCreateDestination {
pub fn from(s: String) -> Result<Self, NgError> {
Ok(match s.as_str() {
"store" => Self::Store,
"stream" => Self::Stream,
"mc" => Self::MagicCarpet,
_ => return Err(NgError::InvalidArgument),
})
}
}
#[derive(Clone, Debug, Serialize, Deserialize)] #[derive(Clone, Debug, Serialize, Deserialize)]
pub struct DocCreate { pub struct DocCreate {
store: StoreRepo, pub store: StoreRepo,
class: String, pub class: BranchCrdt,
pub destination: DocCreateDestination,
} }
#[derive(Clone, Debug, Serialize, Deserialize)] #[derive(Clone, Debug, Serialize, Deserialize)]
@ -757,6 +806,7 @@ pub struct FileMetaV0 {
#[derive(Clone, Debug, Serialize, Deserialize)] #[derive(Clone, Debug, Serialize, Deserialize)]
pub struct AppTabStoreInfo { pub struct AppTabStoreInfo {
pub repo: Option<StoreRepo>, //+
pub overlay: Option<String>, //+ pub overlay: Option<String>, //+
pub has_outer: Option<String>, pub has_outer: Option<String>,
pub store_type: Option<String>, //+ pub store_type: Option<String>, //+
@ -822,6 +872,7 @@ pub enum AppResponseV0 {
False, False,
Error(String), Error(String),
EndOfStream, EndOfStream,
Nuri(String),
} }
#[derive(Clone, Debug, Serialize, Deserialize)] #[derive(Clone, Debug, Serialize, Deserialize)]

@ -247,7 +247,7 @@ impl Block {
match serde_bare::from_slice(content_dec.as_slice()) { match serde_bare::from_slice(content_dec.as_slice()) {
Ok(c) => content = c, Ok(c) => content = c,
Err(_e) => { Err(_e) => {
//log_debug!("Block deserialize error: {}", e); //log_debug!("Block deserialize error: {}", _e);
return Err(ObjectParseError::BlockDeserializeError); return Err(ObjectParseError::BlockDeserializeError);
} }
} }

@ -37,6 +37,7 @@ pub enum CommitLoadError {
SingletonCannotHaveHeader, SingletonCannotHaveHeader,
MalformedHeader, MalformedHeader,
BodyTypeMismatch, BodyTypeMismatch,
ContentParseError(ObjectParseError),
} }
#[derive(Debug, PartialEq, Eq, Clone)] #[derive(Debug, PartialEq, Eq, Clone)]
@ -316,10 +317,11 @@ impl Commit {
let (id, key) = (commit_ref.id, commit_ref.key); let (id, key) = (commit_ref.id, commit_ref.key);
match Object::load(id, Some(key.clone()), store) { match Object::load(id, Some(key.clone()), store) {
Err(ObjectParseError::MissingHeaderBlocks((obj, mut missing))) => { Err(ObjectParseError::MissingHeaderBlocks((obj, mut missing))) => {
//log_debug!("MISSING {:?}", missing);
if with_body { if with_body {
let content = obj let content = obj
.content() .content()
.map_err(|_e| CommitLoadError::ObjectParseError)?; .map_err(|e| CommitLoadError::ContentParseError(e))?;
let mut commit = match content { let mut commit = match content {
ObjectContent::V0(ObjectContentV0::Commit(c)) => c, ObjectContent::V0(ObjectContentV0::Commit(c)) => c,
_ => return Err(CommitLoadError::NotACommit), _ => return Err(CommitLoadError::NotACommit),
@ -341,7 +343,7 @@ impl Commit {
Ok(obj) => { Ok(obj) => {
let content = obj let content = obj
.content() .content()
.map_err(|_e| CommitLoadError::ObjectParseError)?; .map_err(|e| CommitLoadError::ContentParseError(e))?;
let mut commit = match content { let mut commit = match content {
ObjectContent::V0(ObjectContentV0::Commit(c)) => c, ObjectContent::V0(ObjectContentV0::Commit(c)) => c,
_ => return Err(CommitLoadError::NotACommit), _ => return Err(CommitLoadError::NotACommit),
@ -359,7 +361,10 @@ impl Commit {
Err(ObjectParseError::MissingBlocks(missing)) => { Err(ObjectParseError::MissingBlocks(missing)) => {
Err(CommitLoadError::MissingBlocks(missing)) Err(CommitLoadError::MissingBlocks(missing))
} }
Err(_) => Err(CommitLoadError::ObjectParseError), Err(_e) => {
log_err!("{:?}", _e);
Err(CommitLoadError::ObjectParseError)
}
} }
} }

@ -88,6 +88,7 @@ pub enum NgError {
NotImplemented, NotImplemented,
NotARendezVous, NotARendezVous,
IncompatibleQrCode, IncompatibleQrCode,
InvalidClass,
} }
impl Error for NgError {} impl Error for NgError {}
@ -224,6 +225,7 @@ pub enum StorageError {
Abort, Abort,
NotEmpty, NotEmpty,
ServerAlreadyRunningInOtherProcess, ServerAlreadyRunningInOtherProcess,
NgError(String),
} }
impl core::fmt::Display for StorageError { impl core::fmt::Display for StorageError {
@ -238,6 +240,12 @@ impl From<serde_bare::error::Error> for StorageError {
} }
} }
impl From<NgError> for StorageError {
fn from(e: NgError) -> Self {
StorageError::NgError(e.to_string())
}
}
#[derive(Debug, Eq, PartialEq, TryFromPrimitive, IntoPrimitive, Clone)] #[derive(Debug, Eq, PartialEq, TryFromPrimitive, IntoPrimitive, Clone)]
#[repr(u16)] #[repr(u16)]
pub enum ServerError { pub enum ServerError {
@ -358,6 +366,7 @@ pub enum VerifierError {
InvalidNamedGraph, InvalidNamedGraph,
OxigraphError(String), OxigraphError(String),
CannotRemoveTriplesWhenNewBranch, CannotRemoveTriplesWhenNewBranch,
PermissionDenied,
} }
impl Error for VerifierError {} impl Error for VerifierError {}
@ -381,6 +390,7 @@ impl From<NgError> for VerifierError {
NgError::RepoNotFound => VerifierError::RepoNotFound, NgError::RepoNotFound => VerifierError::RepoNotFound,
NgError::BranchNotFound => VerifierError::BranchNotFound, NgError::BranchNotFound => VerifierError::BranchNotFound,
NgError::SerializationError => VerifierError::SerializationError, NgError::SerializationError => VerifierError::SerializationError,
NgError::PermissionDenied => VerifierError::PermissionDenied,
// NgError::JsStorageReadError // NgError::JsStorageReadError
// NgError::JsStorageWriteError(String) // NgError::JsStorageWriteError(String)
// NgError::JsStorageKeyNotFound // NgError::JsStorageKeyNotFound

@ -16,6 +16,7 @@ use chacha20::ChaCha20;
use zeroize::Zeroize; use zeroize::Zeroize;
use crate::errors::*; use crate::errors::*;
use crate::log::*;
use crate::repo::{BranchInfo, Repo}; use crate::repo::{BranchInfo, Repo};
use crate::store::Store; use crate::store::Store;
use crate::types::*; use crate::types::*;

@ -609,6 +609,15 @@ impl Repo {
None None
} }
pub fn store_branch(&self) -> Option<&BranchInfo> {
for (_, branch) in self.branches.iter() {
if branch.branch_type == BranchType::Store {
return Some(branch);
}
}
None
}
pub fn root_branch(&self) -> Option<&BranchInfo> { pub fn root_branch(&self) -> Option<&BranchInfo> {
for (_, branch) in self.branches.iter() { for (_, branch) in self.branches.iter() {
if branch.branch_type == BranchType::Root { if branch.branch_type == BranchType::Root {

@ -274,8 +274,7 @@ impl Store {
creator: &UserId, creator: &UserId,
creator_priv_key: &PrivKey, creator_priv_key: &PrivKey,
repo_write_cap_secret: SymKey, repo_write_cap_secret: SymKey,
is_store: bool, branch_crdt: BranchCrdt,
is_private_store: bool,
) -> Result<(Repo, Vec<(Commit, Vec<Digest>)>), NgError> { ) -> Result<(Repo, Vec<(Commit, Vec<Digest>)>), NgError> {
let (repo_priv_key, repo_pub_key) = generate_keypair(); let (repo_priv_key, repo_pub_key) = generate_keypair();
@ -285,8 +284,8 @@ impl Store {
repo_priv_key, repo_priv_key,
repo_pub_key, repo_pub_key,
repo_write_cap_secret, repo_write_cap_secret,
is_store, Some(branch_crdt),
is_private_store, false,
) )
} }
@ -297,9 +296,14 @@ impl Store {
repo_priv_key: PrivKey, repo_priv_key: PrivKey,
repo_pub_key: PubKey, repo_pub_key: PubKey,
repo_write_cap_secret: SymKey, repo_write_cap_secret: SymKey,
is_store: bool, mut branch_crdt: Option<BranchCrdt>,
is_private_store: bool, is_private_store: bool,
) -> Result<(Repo, Vec<(Commit, Vec<Digest>)>), NgError> { ) -> Result<(Repo, Vec<(Commit, Vec<Digest>)>), NgError> {
let is_store = branch_crdt.is_none();
if is_store {
branch_crdt = Some(BranchCrdt::Graph("data:container".to_string()));
}
let mut events = Vec::with_capacity(9); let mut events = Vec::with_capacity(9);
let mut events_postponed = Vec::with_capacity(6); let mut events_postponed = Vec::with_capacity(6);
@ -377,7 +381,7 @@ impl Store {
let (main_branch_commit, main_add_branch_commit, main_branch_info) = let (main_branch_commit, main_add_branch_commit, main_branch_info) =
self.as_ref().create_branch( self.as_ref().create_branch(
BranchType::Main, BranchType::Main,
BranchCrdt::Graph("data:container".to_string()), branch_crdt.unwrap(),
creator, creator,
creator_priv_key, creator_priv_key,
repo_pub_key, repo_pub_key,

@ -1249,6 +1249,11 @@ impl RootBranch {
Self::V0(v0) => &v0.topic, Self::V0(v0) => &v0.topic,
} }
} }
pub fn repo_id(&self) -> &RepoId {
match self {
Self::V0(v0) => &v0.id,
}
}
pub fn owners(&self) -> &Vec<UserId> { pub fn owners(&self) -> &Vec<UserId> {
match self { match self {
Self::V0(v0) => &v0.owners, Self::V0(v0) => &v0.owners,
@ -1386,8 +1391,8 @@ impl BranchCrdt {
BranchCrdt::None => panic!("BranchCrdt::None does not have a class"), BranchCrdt::None => panic!("BranchCrdt::None does not have a class"),
} }
} }
pub fn from(name: String, class: String) -> Self { pub fn from(name: String, class: String) -> Result<Self, NgError> {
match name.as_str() { Ok(match name.as_str() {
"Graph" => BranchCrdt::Graph(class), "Graph" => BranchCrdt::Graph(class),
"YMap" => BranchCrdt::YMap(class), "YMap" => BranchCrdt::YMap(class),
"YArray" => BranchCrdt::YArray(class), "YArray" => BranchCrdt::YArray(class),
@ -1395,8 +1400,8 @@ impl BranchCrdt {
"YText" => BranchCrdt::YText(class), "YText" => BranchCrdt::YText(class),
"Automerge" => BranchCrdt::Automerge(class), "Automerge" => BranchCrdt::Automerge(class),
"Elmer" => BranchCrdt::Elmer(class), "Elmer" => BranchCrdt::Elmer(class),
_ => panic!("Invalid CRDT name"), _ => return Err(NgError::InvalidClass),
} })
} }
} }
@ -1480,8 +1485,8 @@ pub enum BranchType {
Context, Context,
//Ontology, //Ontology,
Transactional, // this could have been called OtherTransactional, but for the sake of simplicity, we use Transactional for any branch that is not the Main one. Transactional, // this could have been called OtherTransactional, but for the sake of simplicity, we use Transactional for any branch that is not the Main one.
Root, // only used for BranchInfo Root, // only used for BranchInfo//Unknown, // only used temporarily when loading a branch info from commits (Branch commit, then AddBranch commit)
//Unknown, // only used temporarily when loading a branch info from commits (Branch commit, then AddBranch commit) Header,
} }
impl BranchType { impl BranchType {
@ -1500,6 +1505,7 @@ impl fmt::Display for BranchType {
"{}", "{}",
match self { match self {
Self::Main => "Main", Self::Main => "Main",
Self::Header => "Header",
Self::Store => "Store", Self::Store => "Store",
Self::Overlay => "Overlay", Self::Overlay => "Overlay",
Self::User => "User", Self::User => "User",
@ -1817,6 +1823,14 @@ pub enum AddRepo {
V0(AddRepoV0), V0(AddRepoV0),
} }
impl AddRepo {
pub fn read_cap(&self) -> &ReadCap {
match self {
Self::V0(v0) => &v0.read_cap,
}
}
}
/// Removes a repo from the store branch. /// Removes a repo from the store branch.
/// ///
/// DEPS to the previous AddRepo commit(s) (ORset logic) with matching repo_id /// DEPS to the previous AddRepo commit(s) (ORset logic) with matching repo_id

@ -310,7 +310,7 @@ pub async fn sparql_query(
js_sys::JSON::parse(&string) js_sys::JSON::parse(&string)
} }
AppResponseV0::Error(e) => Err(e.to_string().into()), AppResponseV0::Error(e) => Err(e.to_string().into()),
_ => Err("invalid AppResponse".to_string().into()), _ => Err("invalid response".to_string().into()),
} }
} }
@ -388,7 +388,7 @@ pub async fn sparql_query(
js_sys::JSON::parse(&string) js_sys::JSON::parse(&string)
} }
AppResponseV0::Error(e) => Err(e.to_string().into()), AppResponseV0::Error(e) => Err(e.to_string().into()),
_ => Err("invalid AppResponse".to_string().into()), _ => Err("invalid response".to_string().into()),
} }
} }
@ -1041,6 +1041,48 @@ pub async fn app_request_with_nuri_command(
Ok(serde_wasm_bindgen::to_value(&response).unwrap()) Ok(serde_wasm_bindgen::to_value(&response).unwrap())
} }
#[wasm_bindgen]
pub async fn doc_create(
session_id: JsValue,
crdt: String,
class_name: String,
store_repo: JsValue,
destination: String,
) -> Result<JsValue, String> {
let session_id: u64 = serde_wasm_bindgen::from_value::<u64>(session_id)
.map_err(|_| "Deserialization error of session_id".to_string())?;
let class = BranchCrdt::from(crdt, class_name).map_err(|e| e.to_string())?;
let store = serde_wasm_bindgen::from_value::<StoreRepo>(store_repo)
.map_err(|_| "Deserialization error of store_repo".to_string())?;
let destination = DocCreateDestination::from(destination).map_err(|e| e.to_string())?;
let request = AppRequest::V0(AppRequestV0 {
session_id,
command: AppRequestCommandV0::new_create(),
nuri: NuriV0::new_empty(),
payload: Some(AppRequestPayload::V0(AppRequestPayloadV0::Create(
DocCreate {
store,
class,
destination,
},
))),
});
let response = nextgraph::local_broker::app_request(request)
.await
.map_err(|e: NgError| e.to_string())?;
if let AppResponse::V0(AppResponseV0::Nuri(nuri)) = response {
Ok(serde_wasm_bindgen::to_value(&nuri).unwrap())
} else {
Err("invalid response".to_string())
}
}
#[wasm_bindgen] #[wasm_bindgen]
pub async fn file_get_from_private_store( pub async fn file_get_from_private_store(
session_id: JsValue, session_id: JsValue,

@ -14,6 +14,7 @@ pub mod transaction;
use std::collections::HashMap; use std::collections::HashMap;
use std::sync::Arc; use std::sync::Arc;
use ng_net::broker::BROKER;
use ng_repo::errors::VerifierError; use ng_repo::errors::VerifierError;
#[allow(unused_imports)] #[allow(unused_imports)]
use ng_repo::log::*; use ng_repo::log::*;
@ -87,7 +88,7 @@ impl CommitVerifier for RootBranch {
let user_priv = verifier.user_privkey(); let user_priv = verifier.user_privkey();
let user_id = verifier.user_id(); let user_id = verifier.user_id();
let repo_write_cap_secret = if store.is_private() { let repo_write_cap_secret = if store.id() == &root_branch.id && store.is_private() {
Some(SymKey::nil()) Some(SymKey::nil())
} else if let Some(pos) = root_branch.owners.iter().position(|o| o == user_id) { } else if let Some(pos) = root_branch.owners.iter().position(|o| o == user_id) {
let cryptobox = &root_branch.owners_write_cap[pos]; let cryptobox = &root_branch.owners_write_cap[pos];
@ -156,7 +157,7 @@ impl CommitVerifier for Branch {
//TODO: deal with quorum_type (verify signature) //TODO: deal with quorum_type (verify signature)
let repository_commit = Commit::load(branch.repo.clone(), &store, true)?; let repository_commit: Commit = Commit::load(branch.repo.clone(), &store, true)?;
let repository = match repository_commit let repository = match repository_commit
.body() .body()
@ -252,7 +253,6 @@ impl CommitVerifier for AddBranch {
} }
// TODO fetch the readcap and verify that crdt and other infos in Branch definition are the same as in AddBranch commit // TODO fetch the readcap and verify that crdt and other infos in Branch definition are the same as in AddBranch commit
let branch_info = BranchInfo { let branch_info = BranchInfo {
id: v0.branch_id, id: v0.branch_id,
branch_type: v0.branch_type.clone(), branch_type: v0.branch_type.clone(),
@ -570,6 +570,13 @@ impl CommitVerifier for AddRepo {
repo_id: &RepoId, repo_id: &RepoId,
store: Arc<Store>, store: Arc<Store>,
) -> Result<(), VerifierError> { ) -> Result<(), VerifierError> {
let broker = BROKER.read().await;
let remote = (&verifier.connected_broker).into();
let user = Some(verifier.user_id().clone());
let read_cap = self.read_cap();
verifier
.load_repo_from_read_cap(read_cap, &broker, &user, &remote, store, true)
.await?;
Ok(()) Ok(())
} }
} }

@ -244,6 +244,46 @@ impl Verifier {
payload: Option<AppRequestPayload>, payload: Option<AppRequestPayload>,
) -> Result<AppResponse, NgError> { ) -> Result<AppResponse, NgError> {
match command { match command {
AppRequestCommandV0::Create => {
if let Some(AppRequestPayload::V0(AppRequestPayloadV0::Create(doc_create))) =
payload
{
//TODO: deal with doc_create.destination
let user_id = self.user_id().clone();
let user_priv_key = self.user_privkey().clone();
let repo_id = self
.new_repo_default(
&user_id,
&user_priv_key,
&doc_create.store,
doc_create.class,
)
.await?;
// adding an AddRepo commit to the Store branch of store.
self.send_add_repo_to_store(&repo_id, &doc_create.store)
.await?;
// adding an ldp:contains triple to the store main branch
let nuri = NuriV0::repo_graph_name(&repo_id, &doc_create.store.outer_overlay());
let store_nuri = NuriV0::from_store_repo(&doc_create.store);
let store_nuri_string = NuriV0::repo_graph_name(
doc_create.store.repo_id(),
&doc_create.store.outer_overlay(),
);
let query = format!("INSERT DATA {{ <{store_nuri_string}> <http://www.w3.org/ns/ldp#contains> <{nuri}>. }}");
let ret = self.process_sparql_update(&store_nuri, &query).await;
if let Err(e) = ret {
return Ok(AppResponse::error(e));
}
return Ok(AppResponse::V0(AppResponseV0::Nuri(nuri)));
} else {
return Err(NgError::InvalidPayload);
}
}
AppRequestCommandV0::Fetch(fetch) => match fetch { AppRequestCommandV0::Fetch(fetch) => match fetch {
AppFetchContentV0::ReadQuery => { AppFetchContentV0::ReadQuery => {
if let Some(AppRequestPayload::V0(AppRequestPayloadV0::Query(DocQuery::V0( if let Some(AppRequestPayload::V0(AppRequestPayloadV0::Query(DocQuery::V0(

@ -138,6 +138,7 @@ impl UserStorage for RocksDbUserStorage {
}; };
let store_tab_info = AppTabStoreInfo { let store_tab_info = AppTabStoreInfo {
repo: Some(store.clone()),
overlay: Some(format!( overlay: Some(format!(
"v:{}", "v:{}",
store.overlay_id_for_read_purpose().to_string() store.overlay_id_for_read_purpose().to_string()

@ -178,7 +178,7 @@ impl<'a> BranchStorage<'a> {
let crdt: BranchCrdt = if crdt_name.is_none() || class.is_none() { let crdt: BranchCrdt = if crdt_name.is_none() || class.is_none() {
BranchCrdt::None BranchCrdt::None
} else { } else {
BranchCrdt::from(crdt_name.unwrap(), class.unwrap()) BranchCrdt::from(crdt_name.unwrap(), class.unwrap())?
}; };
let bs = BranchInfo { let bs = BranchInfo {

@ -237,11 +237,15 @@ impl<'a> RepoStorage<'a> {
let branch_ids = Self::get_all_branches(id, storage)?; let branch_ids = Self::get_all_branches(id, storage)?;
let mut branches = HashMap::new(); let mut branches = HashMap::new();
let mut overlay_branch_read_cap = None; let mut overlay_branch_read_cap = None;
let mut store_branch_id = None;
for branch in branch_ids { for branch in branch_ids {
let info = BranchStorage::load(&branch, storage)?; let info = BranchStorage::load(&branch, storage)?;
if info.branch_type == BranchType::Overlay { if info.branch_type == BranchType::Overlay {
overlay_branch_read_cap = Some(info.read_cap.clone().unwrap()); overlay_branch_read_cap = Some(info.read_cap.clone().unwrap());
} }
if info.branch_type == BranchType::Store {
store_branch_id = Some(info.id.clone());
}
//log_info!("LOADING BRANCH INFO {}", branch); //log_info!("LOADING BRANCH INFO {}", branch);
//log_info!("TOPIC {}", info.topic); //log_info!("TOPIC {}", info.topic);
let _ = branches.insert(branch, info); let _ = branches.insert(branch, info);
@ -258,7 +262,10 @@ impl<'a> RepoStorage<'a> {
Left(s) => s, Left(s) => s,
Right(bs) => { Right(bs) => {
// we want to load a store. let's start by retrieving the store repo // we want to load a store. let's start by retrieving the store repo
// TODO: check that it has a STORE_BRANCH // check that it has a STORE_BRANCH
if store_branch_id.is_none() {
return Err(StorageError::NotAStoreRepo);
}
let store_repo: StoreRepo = let store_repo: StoreRepo =
prop(Self::STORE_REPO, &props).map_err(|_| StorageError::NotAStoreRepo)?; prop(Self::STORE_REPO, &props).map_err(|_| StorageError::NotAStoreRepo)?;
let store_info = branches.get(id).ok_or(StorageError::NotFound)?; let store_info = branches.get(id).ok_or(StorageError::NotFound)?;
@ -276,6 +283,12 @@ impl<'a> RepoStorage<'a> {
} }
}; };
let opened_branches = if let Some(store_branch) = store_branch_id {
HashMap::from([(store_branch, true)])
} else {
HashMap::new()
};
let repo = Repo { let repo = Repo {
id: id.clone(), id: id.clone(),
repo_def: prop(Self::DEFINITION, &props)?, repo_def: prop(Self::DEFINITION, &props)?,
@ -285,7 +298,7 @@ impl<'a> RepoStorage<'a> {
//TODO: members //TODO: members
members: HashMap::new(), members: HashMap::new(),
branches, branches,
opened_branches: HashMap::new(), opened_branches,
store, store,
}; };
Ok(repo) Ok(repo)

@ -260,6 +260,7 @@ impl Verifier {
}; };
let store_tab_info = AppTabStoreInfo { let store_tab_info = AppTabStoreInfo {
repo: Some(repo.store.get_store_repo().clone()),
overlay: Some(format!("v:{}", repo.store.outer_overlay().to_string())), overlay: Some(format!("v:{}", repo.store.outer_overlay().to_string())),
store_type: Some(repo.store.get_store_repo().store_type_for_app()), store_type: Some(repo.store.get_store_repo().store_type_for_app()),
has_outer: None, //TODO has_outer: None, //TODO
@ -1081,7 +1082,7 @@ impl Verifier {
as_publisher: bool, as_publisher: bool,
) -> Result<(), NgError> { ) -> Result<(), NgError> {
if !self.connected_broker.is_some() { if !self.connected_broker.is_some() {
let repo = self.repos.get_mut(repo_id).ok_or(NgError::RepoNotFound)?; let repo: &mut Repo = self.repos.get_mut(repo_id).ok_or(NgError::RepoNotFound)?;
repo.opened_branches.insert(*branch, as_publisher); repo.opened_branches.insert(*branch, as_publisher);
return Ok(()); return Ok(());
} }
@ -1405,6 +1406,7 @@ impl Verifier {
CommitBodyV0::StoreUpdate(a) => a.verify(commit, self, branch_id, repo_id, store), CommitBodyV0::StoreUpdate(a) => a.verify(commit, self, branch_id, repo_id, store),
CommitBodyV0::AddSignerCap(a) => a.verify(commit, self, branch_id, repo_id, store), CommitBodyV0::AddSignerCap(a) => a.verify(commit, self, branch_id, repo_id, store),
CommitBodyV0::AddFile(a) => a.verify(commit, self, branch_id, repo_id, store), CommitBodyV0::AddFile(a) => a.verify(commit, self, branch_id, repo_id, store),
CommitBodyV0::AddRepo(a) => a.verify(commit, self, branch_id, repo_id, store),
CommitBodyV0::AsyncTransaction(a) => { CommitBodyV0::AsyncTransaction(a) => {
Box::pin(self.verify_async_transaction(a, commit, branch_id, repo_id, store)) Box::pin(self.verify_async_transaction(a, commit, branch_id, repo_id, store))
} }
@ -1689,6 +1691,39 @@ impl Verifier {
Ok(()) Ok(())
} }
pub(crate) async fn send_add_repo_to_store(
&mut self,
repo_id: &RepoId,
store_repo: &StoreRepo,
) -> Result<(), VerifierError> {
let repo = self.get_repo(repo_id, store_repo)?;
let transaction_commit_body = CommitBodyV0::AddRepo(AddRepo::V0(AddRepoV0 {
read_cap: repo.read_cap.clone().ok_or(VerifierError::RepoNotFound)?,
metadata: vec![],
}));
let store_id = store_repo.repo_id();
let store_branch_id = {
let store = self.get_repo(store_id, store_repo)?;
let store_branch = store.store_branch().ok_or(VerifierError::StoreNotFound)?;
store_branch.id.clone()
};
let _commit = self
.new_transaction_commit(
transaction_commit_body,
store_id,
&store_branch_id,
&store_repo,
vec![],
vec![],
)
.await?;
Ok(())
}
async fn load_store_from_read_cap<'a>( async fn load_store_from_read_cap<'a>(
&mut self, &mut self,
broker: &RwLockReadGuard<'static, Broker>, broker: &RwLockReadGuard<'static, Broker>,
@ -1696,9 +1731,40 @@ impl Verifier {
remote: &Option<DirectPeerId>, remote: &Option<DirectPeerId>,
store: Arc<Store>, store: Arc<Store>,
) -> Result<(), NgError> { ) -> Result<(), NgError> {
let (repo_id, store_branch) = self
.load_repo_from_read_cap(
store.get_store_readcap(),
broker,
user,
remote,
Arc::clone(&store),
true,
)
.await?;
// adding the Store branch to the opened_branches
// TODO: only do it if the Store is 3P.
if let Some(store_branch_id) = store_branch {
let repo = self.get_repo_mut(&repo_id, store.get_store_repo())?;
let _ = repo.opened_branches.insert(store_branch_id, true);
}
Ok(())
}
/// return the repo_id and an option branch_id of the Store branch, if any
pub(crate) async fn load_repo_from_read_cap<'a>(
&mut self,
read_cap: &ReadCap,
broker: &RwLockReadGuard<'static, Broker>,
user: &Option<UserId>,
remote: &Option<DirectPeerId>,
store: Arc<Store>,
load_branches: bool,
) -> Result<(RepoId, Option<BranchId>), NgError> {
// first we fetch the read_cap commit of private store repo. // first we fetch the read_cap commit of private store repo.
let root_branch_commit = Self::get_commit( let root_branch_commit = Self::get_commit(
store.get_store_readcap().clone(), read_cap.clone(),
None, None,
&store.overlay_for_read_on_client_protocol(), &store.overlay_for_read_on_client_protocol(),
&broker, &broker,
@ -1717,61 +1783,68 @@ impl Verifier {
let topic = root_branch.topic(); let topic = root_branch.topic();
let repo_id = store.id(); let repo_id = root_branch.repo_id();
self.do_sync_req( self.do_sync_req(
&broker, &broker,
user, user,
remote, remote,
topic, topic,
repo_id, repo_id,
store.get_store_readcap_secret(), &read_cap.key,
repo_id, repo_id,
Arc::clone(&store), Arc::clone(&store),
) )
.await .await
.map_err(|e| NgError::BootstrapError(e.to_string()))?; .map_err(|e| NgError::BootstrapError(e.to_string()))?;
let other_branches: Vec<(PubKey, PubKey, SymKey)> = self let mut store_branch = None;
.get_repo(repo_id, store.get_store_repo())?
.branches if load_branches {
.iter() let other_branches: Vec<(PubKey, PubKey, SymKey)> = self
.map(|(branch_id, branch)| { .get_repo(repo_id, store.get_store_repo())?
( .branches
branch_id.clone(), .iter()
branch.topic.clone().unwrap(), .map(|(branch_id, branch)| {
branch.read_cap.as_ref().unwrap().key.clone(), if branch.branch_type == BranchType::Store {
store_branch = Some(branch_id.clone());
}
(
branch_id.clone(),
branch.topic.clone().unwrap(),
branch.read_cap.as_ref().unwrap().key.clone(),
)
})
.collect();
// loading the other Branches of store
for (branch_id, topic, secret) in other_branches {
if branch_id == *repo_id {
// root branch of store is already synced
continue;
}
self.do_sync_req(
&broker,
user,
remote,
&topic,
&branch_id,
&secret,
repo_id,
Arc::clone(&store),
) )
}) .await
.collect(); .map_err(|e| NgError::BootstrapError(e.to_string()))?;
// loading the other Branches of store
for (branch_id, topic, secret) in other_branches {
if branch_id == *repo_id {
// root branch of store is already synced
continue;
} }
self.do_sync_req(
&broker,
user,
remote,
&topic,
&branch_id,
&secret,
repo_id,
Arc::clone(&store),
)
.await
.map_err(|e| NgError::BootstrapError(e.to_string()))?;
} }
log_info!("STORE loaded from read_cap {}", repo_id); log_info!("loaded from read_cap {}", repo_id);
// TODO: deal with AddSignerCap that are saved on rocksdb for now, but do not make it to the Verifier.repos // TODO: deal with AddSignerCap that are saved on rocksdb for now, but do not make it to the Verifier.repos
return Ok((repo_id.clone(), store_branch));
} }
_ => return Err(VerifierError::RootBranchNotFound.into()), _ => return Err(VerifierError::RootBranchNotFound.into()),
}, },
} }
Ok(())
} }
async fn get_commit( async fn get_commit(
@ -2405,7 +2478,7 @@ impl Verifier {
priv_key, priv_key,
store_repo.repo_id().clone(), store_repo.repo_id().clone(),
repo_write_cap_secret, repo_write_cap_secret,
true, None,
private, private,
)?; )?;
let repo = self.complete_site_store(store_repo, repo)?; let repo = self.complete_site_store(store_repo, repo)?;
@ -2416,26 +2489,30 @@ impl Verifier {
} }
/// returns the Repo and the last seq_num of the peer /// returns the Repo and the last seq_num of the peer
#[allow(dead_code)] pub(crate) async fn new_repo_default<'a>(
async fn new_repo_default<'a>(
&'a mut self, &'a mut self,
creator: &UserId, creator: &UserId,
creator_priv_key: &PrivKey, creator_priv_key: &PrivKey,
store_repo: &StoreRepo, store_repo: &StoreRepo,
) -> Result<&'a Repo, NgError> { branch_crdt: BranchCrdt,
let store = self.get_store_or_load(store_repo); ) -> Result<RepoId, NgError> {
let repo_write_cap_secret = SymKey::random(); let (repo_id, proto_events) = {
let (repo, proto_events) = store.create_repo_default( let store = self.get_store_or_load(store_repo);
creator, let repo_write_cap_secret = SymKey::random();
creator_priv_key, let (repo, proto_events) = store.create_repo_default(
repo_write_cap_secret, creator,
false, creator_priv_key,
false, repo_write_cap_secret,
)?; branch_crdt,
self.populate_topics(&repo); )?;
self.new_events_with_repo(proto_events, &repo).await?; self.populate_topics(&repo);
let repo_ref = self.add_repo_and_save(repo); let repo_ref = self.add_repo_and_save(repo);
Ok(repo_ref) (repo_ref.id, proto_events)
};
self.new_events(proto_events, repo_id, store_repo).await?;
//let repo_ref = self.add_repo_and_save(repo);
Ok(repo_id)
} }
} }
#[cfg(test)] #[cfg(test)]
@ -2457,12 +2534,15 @@ mod test {
verifier.add_store(store); verifier.add_store(store);
let repo = verifier let repo = verifier
.new_repo_default(&creator_pub_key, &creator_priv_key, &store_repo) .new_repo_default(
&creator_pub_key,
&creator_priv_key,
&store_repo,
BranchCrdt::Graph("test".to_string()),
)
.await .await
.expect("new_default"); .expect("new_default");
log_debug!("REPO OBJECT {}", repo);
assert_eq!(verifier.last_seq_num, 5); assert_eq!(verifier.last_seq_num, 5);
} }
} }

Loading…
Cancel
Save