master
Niko PLP 3 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. 116
      ng-verifier/src/verifier.rs

@ -584,6 +584,42 @@ async fn app_request(request: AppRequest) -> Result<AppResponse, 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")]
async fn app_request_with_nuri_command(
nuri: String,
@ -826,6 +862,7 @@ impl AppBuilder {
client_info_rust,
doc_fetch_private_subscribe,
doc_fetch_repo_subscribe,
doc_create,
cancel_stream,
app_request_stream,
file_get,

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

@ -13,25 +13,28 @@
import {
} from "../store";
import { link } from "svelte-spa-router";
import { Button, Progressbar, Spinner, Alert } from "flowbite-svelte";
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>
<div class="flex-col">
<h2>ListView</h2>
{#if Array.isArray(commits.history.commits)}
{#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>
<div class="flex-col p-5">
{#each contained(commits.graph) as doc}
<div class="flex font-mono"> <a use:link href="/{doc.nuri}">{doc.hash}</a> </div>
{/each}
</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"
>
<Sun class="mr-2 focus:outline-none" tabindex="-1" />
View Graph
View as Turtle
</button>
{#if results!==undefined}
<div>

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

@ -24,7 +24,7 @@
import { t } from "svelte-i18n";
import { Button, Progressbar, Spinner, Alert } from "flowbite-svelte";
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";
export let nuri = "";
@ -32,6 +32,7 @@
let width;
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);
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) => {
const { inView, entry, scrollDirection, observer, node} = event.detail;
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 ">
@ -67,7 +68,7 @@
class:"w-8 h-8 mr-2 mb-2 flex-none focus:outline-none"
}}/>
{/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)}>
<Pencil tabindex=-1 class="w-5 h-5 focus:outline-none" />

@ -35,13 +35,18 @@
// @ts-ignore
import { t } from "svelte-i18n";
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,
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 {
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";
import ZeraIcon from "./icons/ZeraIcon.svelte";
import ng from "../api";
import {
Home,
@ -144,24 +149,24 @@
pane_left1_used = false;
pane_left2_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;
}
}
$: if (panes_available > 0) {
if ($show_modal_menu && !$cur_tab.show_menu) {
if ($show_modal_menu && !$cur_tab_show_menu) {
$show_modal_menu = false;
}
if (panes_available == 1) {
if ($cur_tab.right_pane) {
pane_right_used = $cur_tab.right_pane;
if ($cur_tab_right_pane) {
pane_right_used = $cur_tab_right_pane;
pane_left1_used = false;
pane_left2_used = false;
} else if ($cur_tab.folders_pane) {
} else if ($cur_tab_folders_pane) {
pane_left1_used = "folders";
pane_right_used = false;
pane_left2_used = false;
} else if ($cur_tab.toc_pane) {
} else if ($cur_tab_toc_pane) {
pane_left1_used = "toc";
pane_right_used = false;
pane_left2_used = false;
@ -171,26 +176,26 @@
pane_right_used = false;
}
} else if (panes_available == 2) {
if ($cur_tab.right_pane) {
pane_right_used = $cur_tab.right_pane;
if ($cur_tab_right_pane) {
pane_right_used = $cur_tab_right_pane;
pane_left2_used = false;
if ($cur_tab.folders_pane) {
if ($cur_tab_folders_pane) {
pane_left1_used = "folders";
} else if ($cur_tab.toc_pane) {
} else if ($cur_tab_toc_pane) {
pane_left1_used = "toc";
} else {
pane_left1_used = false;
}
} else {
pane_right_used = false;
if ($cur_tab.folders_pane) {
if ($cur_tab_folders_pane) {
pane_left1_used = "folders";
if ($cur_tab.toc_pane) {
if ($cur_tab_toc_pane) {
pane_left2_used = "toc";
} else {
pane_left2_used = false;
}
} else if ($cur_tab.toc_pane) {
} else if ($cur_tab_toc_pane) {
pane_left1_used = "toc";
pane_left2_used = false;
} else {
@ -199,19 +204,19 @@
}
}
} else if (panes_available == 3) {
if ($cur_tab.right_pane) {
pane_right_used = $cur_tab.right_pane;
if ($cur_tab_right_pane) {
pane_right_used = $cur_tab_right_pane;
} else {
pane_right_used = false;
}
if ($cur_tab.folders_pane) {
if ($cur_tab_folders_pane) {
pane_left1_used = "folders";
if ($cur_tab.toc_pane) {
if ($cur_tab_toc_pane) {
pane_left2_used = "toc";
} else {
pane_left2_used = false;
}
} else if ($cur_tab.toc_pane) {
} else if ($cur_tab_toc_pane) {
pane_left1_used = "toc";
pane_left2_used = false;
} else {
@ -539,15 +544,26 @@
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",
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();
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 = () => {
@ -601,7 +617,7 @@
tabindex="0">
<XMark class="w-10 h-10 text-gray-700 focus:outline-none dark:text-white"/>
</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"
on:click={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>
</div>
{/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">
<div class="bg-gray-60 overflow-y-auto dark:bg-gray-800">
<ul class="mb-10">
{#if $cur_tab.branch.has_discrete}
{#if $cur_tab_branch_has_discrete}
<li>
<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")}
</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")}
</button>
</div>
</li>
{/if}
{#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
tabindex="-1"
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>
{#if open_view_as && $available_viewers.length > 1 }
{#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
zera={viewer["ng:u"]}
config={{
@ -649,18 +665,18 @@
{/each}
{/if}
{/if}
{#if $cur_tab.doc.can_edit}
{#if $cur_tab_doc_can_edit}
{#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
tabindex="-1"
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>
{#if open_edit_with && $available_editors.length > 1 }
{#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
zera={editor["ng:u"]}
config={{
@ -685,11 +701,11 @@
<span class="ml-3">{get_app("n:g:z:upload_file")["ng:n"]}</span>
</MenuItem>
{/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">
<Toggle
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>
</Toggle>
</li>
@ -706,7 +722,7 @@
{/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") }>
<PlusCircle
tabindex="-1"
@ -716,22 +732,22 @@
</MenuItem>
{/if}
{#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"]} />
<span class="ml-3">{$t("doc.menu.items.editor_chat.label")}</span>
</MenuItem>
{/if}
{#if $cur_tab.branch.id}
<MenuItem title={$t("doc.menu.items.folders.desc")} selected={$cur_tab.folders_pane} clickable={ ()=> openPane("folders") }>
{#if $cur_tab_branch_nuri}
<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"]} />
<span class="ml-3">{$t("doc.menu.items.folders.label")}</span>
</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"]} />
<span class="ml-3">{$t("doc.menu.items.toc.label")}</span>
</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"]} />
<span class="ml-3">{$t("doc.menu.items.files.label")} {$all_files_count}</span>
</MenuItem>
@ -752,19 +768,19 @@
{/each}
{/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"]} />
<span class="ml-3">{$t("doc.menu.items.comments.label")} {$all_comments_count}</span>
</MenuItem>
{#if $cur_tab.doc.is_member}
<MenuItem title={$t("doc.menu.items.branches.desc")} selected={$cur_tab.right_pane == "branches"} clickable={ ()=> openPane("branches") }>
{#if $cur_tab_doc_is_member}
<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"]} />
<span class="ml-3">{$t("doc.menu.items.branches.label")}</span>
</MenuItem>
{/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"]} />
<span class="ml-3">{$t("doc.menu.items.history.label")}</span>
</MenuItem>
@ -793,7 +809,7 @@
<span class="ml-3">{$t("doc.menu.items.annotate.label")}</span>
</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"]} />
<span class="ml-3">{$t("doc.menu.items.info.label")}</span>
</MenuItem>
@ -805,7 +821,7 @@
/>
<span class="ml-3">{$t("doc.menu.items.notifs.label")}</span>
</MenuItem>
{#if $cur_tab.doc.is_member}
{#if $cur_tab_doc_is_member}
<MenuItem title={$t("doc.menu.items.permissions.desc")} clickable={ ()=> openAction("permissions") }>
<LockOpen
tabindex="-1"
@ -838,11 +854,11 @@
{/each}
{/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"]} />
<span class="ml-3">{$t("doc.menu.items.mc.label")}</span>
</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
tabindex="-1"
class="w-7 h-7 text-gray-700 focus:outline-none dark:text-white"
@ -852,19 +868,19 @@
</ul>
</div>
</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">
<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>
<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>
</div>
<Pane pane_name={$cur_tab.right_pane}/>
{:else if $cur_tab.folders_pane}
<Pane pane_name={$cur_tab_right_pane}/>
{:else if $cur_tab_folders_pane}
<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"]} />
<span class="ml-2 inline-block text-gray-500 select-none dark:text-white">{$t("doc.menu.items.folders.label")}</span>
</div>
<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">
<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>
@ -893,11 +909,11 @@
<div class="bg-gray-60 overflow-y-auto dark:bg-gray-800">
<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" />
{$t("doc.destination.store")}
</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" />
{#if $cur_tab.store.store_type !== "dialog"}{$t("doc.destination.stream")}{:else}{$t("doc.destination.dialog")}{/if}
</Radio>

@ -24,7 +24,7 @@
Popover,
} 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 = () => {};
@ -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}>
<span class="inline-block truncate" > {$cur_tab_store_name_override || $nav_bar.title} </span>
</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 class="flex items-center grow pr-2">
<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>
{/if}
{#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"}>
{#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"}>
<ExclamationTriangle variation="outline" tabindex="-1" strokeWidth="2" class="w-9 h-9 mt-1 text-red-700 focus:outline-none"/>
</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}
>{@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>
</Popover>
{:else if $nav_bar.save !== undefined}

@ -87,6 +87,7 @@
import RustIcon from "./RustIcon.svelte";
import SvelteIcon from "./SvelteIcon.svelte";
import ReactIcon from "./ReactIcon.svelte";
import GraphQLIcon from "./GraphQLIcon.svelte";
export let config = {};
export let dataClass: string;
@ -100,6 +101,7 @@
contract: ClipboardDocumentCheck,
"query:text": MagnifyingGlass,
"query:web": MagnifyingGlass,
"query:graphql": GraphQLIcon,
"data:graph": Sun,
"data:json": JsonIcon,
"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 RdfIcon from "./RdfIcon.svelte";
import TurtleIcon from "./TurtleIcon.svelte";
import GraphQLIcon from "./GraphQLIcon.svelte";
export let config = {};
export let zera: string;
@ -91,7 +92,7 @@
compose: QueueList,
sparql_query: RocketLaunch,
sparnatural: CursorArrowRays,
graphql: Cube,
graphql: GraphQLIcon,
invoke: Play,
ontology_viewer: ArrowsPointingOut,
download: DocumentArrowDown,

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

@ -20,7 +20,7 @@
active_session,
} from "../store";
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";
import {
Square3Stack3d,
@ -42,7 +42,7 @@
</script>
<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="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>

@ -17,7 +17,7 @@ import {
} from "svelte/store";
import { register, init, locale, format } from "svelte-i18n";
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";
let all_branches = {};
@ -45,7 +45,7 @@ init({
});
export const display_error = (error: string) => {
if (e.message) return e.message;
if (error.message) return error.message;
//console.log(error);
// TODO: Check, if error tranlsation does not exist
const parts = error.split(":");
@ -141,6 +141,11 @@ export const 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 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) {
$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 (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:w"]) graph_editors.push(class_def["ng:w"]);
}
graph_viewers.push.apply(graph_viewers, find_viewers_for_class("data:graph"));
graph_editors.push.apply(graph_editors, find_editors_for_class("data:graph"));
for (const additional_g_v of find_viewers_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_editor = graph_editors[0];
@ -197,10 +201,6 @@ export const show_modal_menu = 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_discrete = writable("");
@ -216,6 +216,7 @@ export const reset_in_memory = () => {
export const all_tabs = writable({
"":{
store: {
repo: false, // a StoreRepo serialization
overlay: "", // "v:"
has_outer: "", // "l:"
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_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) => {
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) => {
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 = () => {
show_modal_menu.set(true);
cur_tab_update(ct => {
@ -409,6 +461,17 @@ export const nav_bar = writable({
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) => {
nav_bar.update((old) => {
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"
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": {
"ng:n": "JSON-LD Editor",
"ng:a": "Edit the RDF Graph as JSON-LD",
@ -48,6 +58,26 @@ export const official_apps = {
"ng:b": "TripleEditor",
"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": {
"ng:n": "JSON-LD",
"ng:a": "View the RDF Graph as JSON-LD",
@ -85,16 +115,6 @@ export const official_apps = {
"ng:b": "TripleViewer",
"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": {
"ng:n": "SPARNatural Query",
"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: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": { // ?
"ng:n": "N3",
"ng:a": "View the RDF Graph in N3 format",
@ -312,7 +312,7 @@ export const official_apps = {
"ng:c": "app",
"ng:u": "post",//favicon. can be a did:ng:j
"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:w": [],
},

@ -187,6 +187,19 @@ pub struct 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) {
self.target = nuri.target.clone();
}
@ -198,6 +211,20 @@ impl NuriV0 {
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 {
format!("{DID_PREFIX}:o:{repo_id}:v:{overlay_id}")
}
@ -439,6 +466,9 @@ impl AppRequestCommandV0 {
pub fn new_history() -> Self {
AppRequestCommandV0::Fetch(AppFetchContentV0::History)
}
pub fn new_create() -> Self {
AppRequestCommandV0::Create
}
}
#[derive(Clone, Debug, Serialize, Deserialize)]
@ -599,10 +629,29 @@ pub struct DocAddFile {
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)]
pub struct DocCreate {
store: StoreRepo,
class: String,
pub store: StoreRepo,
pub class: BranchCrdt,
pub destination: DocCreateDestination,
}
#[derive(Clone, Debug, Serialize, Deserialize)]
@ -757,6 +806,7 @@ pub struct FileMetaV0 {
#[derive(Clone, Debug, Serialize, Deserialize)]
pub struct AppTabStoreInfo {
pub repo: Option<StoreRepo>, //+
pub overlay: Option<String>, //+
pub has_outer: Option<String>,
pub store_type: Option<String>, //+
@ -822,6 +872,7 @@ pub enum AppResponseV0 {
False,
Error(String),
EndOfStream,
Nuri(String),
}
#[derive(Clone, Debug, Serialize, Deserialize)]

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

@ -37,6 +37,7 @@ pub enum CommitLoadError {
SingletonCannotHaveHeader,
MalformedHeader,
BodyTypeMismatch,
ContentParseError(ObjectParseError),
}
#[derive(Debug, PartialEq, Eq, Clone)]
@ -316,10 +317,11 @@ impl Commit {
let (id, key) = (commit_ref.id, commit_ref.key);
match Object::load(id, Some(key.clone()), store) {
Err(ObjectParseError::MissingHeaderBlocks((obj, mut missing))) => {
//log_debug!("MISSING {:?}", missing);
if with_body {
let content = obj
.content()
.map_err(|_e| CommitLoadError::ObjectParseError)?;
.map_err(|e| CommitLoadError::ContentParseError(e))?;
let mut commit = match content {
ObjectContent::V0(ObjectContentV0::Commit(c)) => c,
_ => return Err(CommitLoadError::NotACommit),
@ -341,7 +343,7 @@ impl Commit {
Ok(obj) => {
let content = obj
.content()
.map_err(|_e| CommitLoadError::ObjectParseError)?;
.map_err(|e| CommitLoadError::ContentParseError(e))?;
let mut commit = match content {
ObjectContent::V0(ObjectContentV0::Commit(c)) => c,
_ => return Err(CommitLoadError::NotACommit),
@ -359,7 +361,10 @@ impl Commit {
Err(ObjectParseError::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,
NotARendezVous,
IncompatibleQrCode,
InvalidClass,
}
impl Error for NgError {}
@ -224,6 +225,7 @@ pub enum StorageError {
Abort,
NotEmpty,
ServerAlreadyRunningInOtherProcess,
NgError(String),
}
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)]
#[repr(u16)]
pub enum ServerError {
@ -358,6 +366,7 @@ pub enum VerifierError {
InvalidNamedGraph,
OxigraphError(String),
CannotRemoveTriplesWhenNewBranch,
PermissionDenied,
}
impl Error for VerifierError {}
@ -381,6 +390,7 @@ impl From<NgError> for VerifierError {
NgError::RepoNotFound => VerifierError::RepoNotFound,
NgError::BranchNotFound => VerifierError::BranchNotFound,
NgError::SerializationError => VerifierError::SerializationError,
NgError::PermissionDenied => VerifierError::PermissionDenied,
// NgError::JsStorageReadError
// NgError::JsStorageWriteError(String)
// NgError::JsStorageKeyNotFound

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

@ -609,6 +609,15 @@ impl Repo {
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> {
for (_, branch) in self.branches.iter() {
if branch.branch_type == BranchType::Root {

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

@ -1249,6 +1249,11 @@ impl RootBranch {
Self::V0(v0) => &v0.topic,
}
}
pub fn repo_id(&self) -> &RepoId {
match self {
Self::V0(v0) => &v0.id,
}
}
pub fn owners(&self) -> &Vec<UserId> {
match self {
Self::V0(v0) => &v0.owners,
@ -1386,8 +1391,8 @@ impl BranchCrdt {
BranchCrdt::None => panic!("BranchCrdt::None does not have a class"),
}
}
pub fn from(name: String, class: String) -> Self {
match name.as_str() {
pub fn from(name: String, class: String) -> Result<Self, NgError> {
Ok(match name.as_str() {
"Graph" => BranchCrdt::Graph(class),
"YMap" => BranchCrdt::YMap(class),
"YArray" => BranchCrdt::YArray(class),
@ -1395,8 +1400,8 @@ impl BranchCrdt {
"YText" => BranchCrdt::YText(class),
"Automerge" => BranchCrdt::Automerge(class),
"Elmer" => BranchCrdt::Elmer(class),
_ => panic!("Invalid CRDT name"),
}
_ => return Err(NgError::InvalidClass),
})
}
}
@ -1480,8 +1485,8 @@ pub enum BranchType {
Context,
//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.
Root, // only used for BranchInfo
//Unknown, // only used temporarily when loading a branch info from commits (Branch commit, then AddBranch commit)
Root, // only used for BranchInfo//Unknown, // only used temporarily when loading a branch info from commits (Branch commit, then AddBranch commit)
Header,
}
impl BranchType {
@ -1500,6 +1505,7 @@ impl fmt::Display for BranchType {
"{}",
match self {
Self::Main => "Main",
Self::Header => "Header",
Self::Store => "Store",
Self::Overlay => "Overlay",
Self::User => "User",
@ -1817,6 +1823,14 @@ pub enum AddRepo {
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.
///
/// 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)
}
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)
}
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())
}
#[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]
pub async fn file_get_from_private_store(
session_id: JsValue,

@ -14,6 +14,7 @@ pub mod transaction;
use std::collections::HashMap;
use std::sync::Arc;
use ng_net::broker::BROKER;
use ng_repo::errors::VerifierError;
#[allow(unused_imports)]
use ng_repo::log::*;
@ -87,7 +88,7 @@ impl CommitVerifier for RootBranch {
let user_priv = verifier.user_privkey();
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())
} else if let Some(pos) = root_branch.owners.iter().position(|o| o == user_id) {
let cryptobox = &root_branch.owners_write_cap[pos];
@ -156,7 +157,7 @@ impl CommitVerifier for Branch {
//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
.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
let branch_info = BranchInfo {
id: v0.branch_id,
branch_type: v0.branch_type.clone(),
@ -570,6 +570,13 @@ impl CommitVerifier for AddRepo {
repo_id: &RepoId,
store: Arc<Store>,
) -> 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(())
}
}

@ -244,6 +244,46 @@ impl Verifier {
payload: Option<AppRequestPayload>,
) -> Result<AppResponse, NgError> {
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 {
AppFetchContentV0::ReadQuery => {
if let Some(AppRequestPayload::V0(AppRequestPayloadV0::Query(DocQuery::V0(

@ -138,6 +138,7 @@ impl UserStorage for RocksDbUserStorage {
};
let store_tab_info = AppTabStoreInfo {
repo: Some(store.clone()),
overlay: Some(format!(
"v:{}",
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() {
BranchCrdt::None
} else {
BranchCrdt::from(crdt_name.unwrap(), class.unwrap())
BranchCrdt::from(crdt_name.unwrap(), class.unwrap())?
};
let bs = BranchInfo {

@ -237,11 +237,15 @@ impl<'a> RepoStorage<'a> {
let branch_ids = Self::get_all_branches(id, storage)?;
let mut branches = HashMap::new();
let mut overlay_branch_read_cap = None;
let mut store_branch_id = None;
for branch in branch_ids {
let info = BranchStorage::load(&branch, storage)?;
if info.branch_type == BranchType::Overlay {
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!("TOPIC {}", info.topic);
let _ = branches.insert(branch, info);
@ -258,7 +262,10 @@ impl<'a> RepoStorage<'a> {
Left(s) => s,
Right(bs) => {
// 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 =
prop(Self::STORE_REPO, &props).map_err(|_| StorageError::NotAStoreRepo)?;
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 {
id: id.clone(),
repo_def: prop(Self::DEFINITION, &props)?,
@ -285,7 +298,7 @@ impl<'a> RepoStorage<'a> {
//TODO: members
members: HashMap::new(),
branches,
opened_branches: HashMap::new(),
opened_branches,
store,
};
Ok(repo)

@ -260,6 +260,7 @@ impl Verifier {
};
let store_tab_info = AppTabStoreInfo {
repo: Some(repo.store.get_store_repo().clone()),
overlay: Some(format!("v:{}", repo.store.outer_overlay().to_string())),
store_type: Some(repo.store.get_store_repo().store_type_for_app()),
has_outer: None, //TODO
@ -1081,7 +1082,7 @@ impl Verifier {
as_publisher: bool,
) -> Result<(), NgError> {
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);
return Ok(());
}
@ -1405,6 +1406,7 @@ impl Verifier {
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::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) => {
Box::pin(self.verify_async_transaction(a, commit, branch_id, repo_id, store))
}
@ -1689,6 +1691,39 @@ impl Verifier {
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>(
&mut self,
broker: &RwLockReadGuard<'static, Broker>,
@ -1696,9 +1731,40 @@ impl Verifier {
remote: &Option<DirectPeerId>,
store: Arc<Store>,
) -> 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.
let root_branch_commit = Self::get_commit(
store.get_store_readcap().clone(),
read_cap.clone(),
None,
&store.overlay_for_read_on_client_protocol(),
&broker,
@ -1717,25 +1783,31 @@ impl Verifier {
let topic = root_branch.topic();
let repo_id = store.id();
let repo_id = root_branch.repo_id();
self.do_sync_req(
&broker,
user,
remote,
topic,
repo_id,
store.get_store_readcap_secret(),
&read_cap.key,
repo_id,
Arc::clone(&store),
)
.await
.map_err(|e| NgError::BootstrapError(e.to_string()))?;
let mut store_branch = None;
if load_branches {
let other_branches: Vec<(PubKey, PubKey, SymKey)> = self
.get_repo(repo_id, store.get_store_repo())?
.branches
.iter()
.map(|(branch_id, branch)| {
if branch.branch_type == BranchType::Store {
store_branch = Some(branch_id.clone());
}
(
branch_id.clone(),
branch.topic.clone().unwrap(),
@ -1763,15 +1835,16 @@ impl Verifier {
.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
return Ok((repo_id.clone(), store_branch));
}
_ => return Err(VerifierError::RootBranchNotFound.into()),
},
}
Ok(())
}
async fn get_commit(
@ -2405,7 +2478,7 @@ impl Verifier {
priv_key,
store_repo.repo_id().clone(),
repo_write_cap_secret,
true,
None,
private,
)?;
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
#[allow(dead_code)]
async fn new_repo_default<'a>(
pub(crate) async fn new_repo_default<'a>(
&'a mut self,
creator: &UserId,
creator_priv_key: &PrivKey,
store_repo: &StoreRepo,
) -> Result<&'a Repo, NgError> {
branch_crdt: BranchCrdt,
) -> Result<RepoId, NgError> {
let (repo_id, proto_events) = {
let store = self.get_store_or_load(store_repo);
let repo_write_cap_secret = SymKey::random();
let (repo, proto_events) = store.create_repo_default(
creator,
creator_priv_key,
repo_write_cap_secret,
false,
false,
branch_crdt,
)?;
self.populate_topics(&repo);
self.new_events_with_repo(proto_events, &repo).await?;
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)]
@ -2457,12 +2534,15 @@ mod test {
verifier.add_store(store);
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
.expect("new_default");
log_debug!("REPO OBJECT {}", repo);
assert_eq!(verifier.last_seq_num, 5);
}
}

Loading…
Cancel
Save