Compare commits

..

9 Commits

  1. 6
      .github/FUNDING.yml
  2. 16
      CHANGELOG.md
  3. 31
      Cargo.lock
  4. 2
      Cargo.toml
  5. 17
      RELEASE-NOTE.md
  6. 14
      nextgraph/Cargo.toml
  7. 2
      nextgraph/README.md
  8. 2
      nextgraph/src/local_broker.rs
  9. 11
      ng-app/index-web.html
  10. 4
      ng-app/package.json
  11. 49
      ng-app/src-tauri/src/lib.rs
  12. 2
      ng-app/src-tauri/tauri.conf.json
  13. 2
      ng-app/src/api.ts
  14. 34
      ng-app/src/apps/ContainerView.svelte
  15. 2
      ng-app/src/apps/MdSource.svelte
  16. 3
      ng-app/src/apps/MilkDownEditor.svelte
  17. 2
      ng-app/src/apps/PostMdViewer.svelte
  18. 4
      ng-app/src/apps/SparqlQueryEditor.svelte
  19. 1
      ng-app/src/apps/YMapEditor.svelte
  20. 1
      ng-app/src/apps/YMapViewer.svelte
  21. 77
      ng-app/src/classes.ts
  22. 4
      ng-app/src/lib/Document.svelte
  23. 123
      ng-app/src/lib/FullLayout.svelte
  24. 10
      ng-app/src/lib/icons/DataClassIcon.svelte
  25. 70
      ng-app/src/lib/popups/Header.svelte
  26. 17
      ng-app/src/locales/en.json
  27. 4
      ng-app/src/routes/WalletInfo.svelte
  28. 42
      ng-app/src/routes/WalletLogin.svelte
  29. 85
      ng-app/src/store.ts
  30. 6
      ng-app/src/styles.css
  31. 16
      ng-app/src/tab.ts
  32. 2
      ng-app/src/workertest.js
  33. 32
      ng-app/src/zeras.ts
  34. 12
      ng-broker/Cargo.toml
  35. 4
      ng-client-ws/Cargo.toml
  36. 2
      ng-net/Cargo.toml
  37. 66
      ng-net/src/app_protocol.rs
  38. 4
      ng-net/src/types.rs
  39. 4
      ng-oxigraph/Cargo.toml
  40. 26
      ng-oxigraph/src/oxigraph/sparql/dataset.rs
  41. 12
      ng-oxigraph/src/oxigraph/storage/mod.rs
  42. 1
      ng-repo/src/errors.rs
  43. 11
      ng-repo/src/repo.rs
  44. 90
      ng-repo/src/store.rs
  45. 24
      ng-repo/src/types.rs
  46. 64
      ng-sdk-js/app-node/index.js
  47. 110
      ng-sdk-js/src/lib.rs
  48. 4
      ng-storage-rocksdb/Cargo.toml
  49. 15
      ng-verifier/Cargo.toml
  50. 104
      ng-verifier/src/commits/transaction.rs
  51. 159
      ng-verifier/src/request_processor.rs
  52. 2
      ng-verifier/src/site.rs
  53. 13
      ng-verifier/src/types.rs
  54. 107
      ng-verifier/src/verifier.rs
  55. 12
      ng-wallet/Cargo.toml
  56. 6
      ngaccount/Cargo.toml
  57. 2
      ngaccount/web/src/routes/Create.svelte
  58. 6
      ngcli/Cargo.toml
  59. 2
      ngcli/src/main.rs
  60. 6
      ngd/Cargo.toml

@ -1,3 +1,7 @@
liberapay: nextgraph liberapay: nextgraph
ko_fi: nextgraph ko_fi: nextgraph
custom: ["https://donate.stripe.com/8wMcOE3NI2B69NKeUU", "https://pay.vivawallet.com/par-le-peuple", "https://nextgraph.org/donate"] custom:
[
"https://donate.stripe.com/8wMcOE3NI2B69NKeUU",
"https://nextgraph.org/donate",
]

@ -6,6 +6,16 @@ Access the sub-sections directly :
## App ## App
### App [0.1.1-alpha] - 2024-09-02
#### Added
- edit title and intro
#### Fixed
- bug doc not saved when back navigation
### App [0.1.0-preview.8] - 2024-08-21 ### App [0.1.0-preview.8] - 2024-08-21
#### Added #### Added
@ -64,6 +74,8 @@ Access the sub-sections directly :
#### Added #### Added
- js & nodejs : fetch_header
- js & nodejs : update_header
- js & nodejs : signature_status - js & nodejs : signature_status
- js & nodejs : signed_snapshot_request - js & nodejs : signed_snapshot_request
- js & nodejs : signature_request - js & nodejs : signature_request
@ -116,6 +128,8 @@ Access the sub-sections directly :
## Broker ## Broker
### Broker [0.1.1-alpha] - 2024-09-02
### Broker [0.1.0-preview.8] - 2024-08-21 ### Broker [0.1.0-preview.8] - 2024-08-21
#### Added #### Added
@ -156,6 +170,8 @@ Access the sub-sections directly :
## CLI ## CLI
### CLI [0.1.1-alpha] - 2024-09-02
### CLI [0.1.0-preview.8] - 2024-08-21 ### CLI [0.1.0-preview.8] - 2024-08-21
#### Added #### Added

31
Cargo.lock generated

@ -3224,7 +3224,7 @@ checksum = "e4a24736216ec316047a1fc4252e27dabb04218aa4a3f37c6e7ddbf1f9782b54"
[[package]] [[package]]
name = "nextgraph" name = "nextgraph"
version = "0.1.0-preview.8" version = "0.1.1-alpha"
dependencies = [ dependencies = [
"async-once-cell", "async-once-cell",
"async-std", "async-std",
@ -3252,7 +3252,7 @@ dependencies = [
[[package]] [[package]]
name = "ng-app" name = "ng-app"
version = "0.1.0-preview.8" version = "0.1.1-alpha"
dependencies = [ dependencies = [
"async-std", "async-std",
"nextgraph", "nextgraph",
@ -3290,7 +3290,7 @@ dependencies = [
[[package]] [[package]]
name = "ng-broker" name = "ng-broker"
version = "0.1.0-preview.8" version = "0.1.1-alpha"
dependencies = [ dependencies = [
"async-std", "async-std",
"async-trait", "async-trait",
@ -3315,7 +3315,7 @@ dependencies = [
[[package]] [[package]]
name = "ng-client-ws" name = "ng-client-ws"
version = "0.1.0-preview.8" version = "0.1.1-alpha"
dependencies = [ dependencies = [
"async-std", "async-std",
"async-trait", "async-trait",
@ -3334,7 +3334,7 @@ dependencies = [
[[package]] [[package]]
name = "ng-net" name = "ng-net"
version = "0.1.0-preview.8" version = "0.1.1-alpha"
dependencies = [ dependencies = [
"async-recursion", "async-recursion",
"async-std", "async-std",
@ -3364,7 +3364,7 @@ dependencies = [
[[package]] [[package]]
name = "ng-oxigraph" name = "ng-oxigraph"
version = "0.4.0-alpha.7-ngpreview7" version = "0.4.0-alpha.7-ngalpha"
dependencies = [ dependencies = [
"base64-url", "base64-url",
"codspeed-criterion-compat", "codspeed-criterion-compat",
@ -3395,7 +3395,7 @@ dependencies = [
[[package]] [[package]]
name = "ng-repo" name = "ng-repo"
version = "0.1.0-preview.8" version = "0.1.1-alpha"
dependencies = [ dependencies = [
"base64-url", "base64-url",
"blake3", "blake3",
@ -3444,7 +3444,7 @@ dependencies = [
[[package]] [[package]]
name = "ng-sdk-js" name = "ng-sdk-js"
version = "0.1.0-preview.8" version = "0.1.1-alpha"
dependencies = [ dependencies = [
"async-std", "async-std",
"futures", "futures",
@ -3471,7 +3471,7 @@ dependencies = [
[[package]] [[package]]
name = "ng-storage-rocksdb" name = "ng-storage-rocksdb"
version = "0.1.0-preview.8" version = "0.1.1-alpha"
dependencies = [ dependencies = [
"ng-repo", "ng-repo",
"ng-rocksdb", "ng-rocksdb",
@ -3499,7 +3499,7 @@ dependencies = [
[[package]] [[package]]
name = "ng-verifier" name = "ng-verifier"
version = "0.1.0-preview.8" version = "0.1.1-alpha"
dependencies = [ dependencies = [
"async-std", "async-std",
"async-trait", "async-trait",
@ -3507,6 +3507,7 @@ dependencies = [
"either", "either",
"futures", "futures",
"getrandom 0.2.10", "getrandom 0.2.10",
"lazy_static",
"ng-net", "ng-net",
"ng-oxigraph", "ng-oxigraph",
"ng-repo", "ng-repo",
@ -3523,7 +3524,7 @@ dependencies = [
[[package]] [[package]]
name = "ng-wallet" name = "ng-wallet"
version = "0.1.0-preview.8" version = "0.1.1-alpha"
dependencies = [ dependencies = [
"aes-gcm-siv", "aes-gcm-siv",
"argon2", "argon2",
@ -3550,7 +3551,7 @@ dependencies = [
[[package]] [[package]]
name = "ngaccount" name = "ngaccount"
version = "0.1.0-preview.8" version = "0.1.1-alpha"
dependencies = [ dependencies = [
"anyhow", "anyhow",
"duration-str", "duration-str",
@ -3568,7 +3569,7 @@ dependencies = [
[[package]] [[package]]
name = "ngcli" name = "ngcli"
version = "0.1.0-preview.8" version = "0.1.1-alpha"
dependencies = [ dependencies = [
"async-std", "async-std",
"blake3", "blake3",
@ -3588,7 +3589,7 @@ dependencies = [
[[package]] [[package]]
name = "ngd" name = "ngd"
version = "0.1.0-preview.8" version = "0.1.1-alpha"
dependencies = [ dependencies = [
"addr", "addr",
"async-std", "async-std",
@ -3607,7 +3608,7 @@ dependencies = [
[[package]] [[package]]
name = "ngone" name = "ngone"
version = "0.1.0-preview.8" version = "0.1.1-alpha"
dependencies = [ dependencies = [
"base64-url", "base64-url",
"bytes", "bytes",

@ -19,7 +19,7 @@ members = [
default-members = [ "nextgraph", "ngcli", "ngd" ] default-members = [ "nextgraph", "ngcli", "ngd" ]
[workspace.package] [workspace.package]
version = "0.1.0-preview.8" version = "0.1.1-alpha"
edition = "2021" edition = "2021"
rust-version = "1.74.0" rust-version = "1.74.0"
license = "MIT/Apache-2.0" license = "MIT/Apache-2.0"

@ -1,6 +1,6 @@
# Release 0.1.0-preview.8 # Release 0.1.1-alpha
_21 August 2024_ _02 September 2024_
This release is not stable and should not be used for any productive work or to store personal documents. This release is meant as a **preview** of what NextGraph can do as of today and hints at its future potential. This release is not stable and should not be used for any productive work or to store personal documents. This release is meant as a **preview** of what NextGraph can do as of today and hints at its future potential.
@ -10,13 +10,9 @@ If you previously installed any NextGraph app on your device, please uninstall i
## App ## App
Please read the : Please read the [Getting started](https://docs.nextgraph.org/en/getting-started) guide.
- [Getting started](https://docs.nextgraph.org/en/getting-started) guide. [changelog](CHANGELOG.md#app-0-1-1-alpha-2024-09-02)
- list of [features](https://docs.nextgraph.org/en/features).
- the [CRDTs page](https://docs.nextgraph.org/en/framework/crdts) in the framework docs.
[changelog](CHANGELOG.md#app-0-1-0-preview-8-2024-08-21)
## SDK ## SDK
@ -28,18 +24,17 @@ The SDK for is not documented yet.
The `ngd` daemon is release with the basic features listed in `ngd --help`. More documentation will come soon The `ngd` daemon is release with the basic features listed in `ngd --help`. More documentation will come soon
[changelog](CHANGELOG.md#broker-0-1-0-preview-8-2024-08-21) [changelog](CHANGELOG.md#broker-0-1-1-alpha-2024-09-02)
## CLI ## CLI
The `ngcli` daemon is release with the basic features listed in `ngcli --help`. More documentation will come soon. The `ngcli` daemon is release with the basic features listed in `ngcli --help`. More documentation will come soon.
[changelog](CHANGELOG.md#cli-0-1-0-preview-8-2024-08-21) [changelog](CHANGELOG.md#cli-0-1-1-alpha-2024-09-02)
## Limitations of this release ## Limitations of this release
- you cannot share documents with other users. Everything is ready for this internally, but there is still some wiring to do that will take some more time. - you cannot share documents with other users. Everything is ready for this internally, but there is still some wiring to do that will take some more time.
- the Rich text editors (both for normal Post/Article and in Markdown) do not let you insert images nor links to other documents. - the Rich text editors (both for normal Post/Article and in Markdown) do not let you insert images nor links to other documents.
- your documents listed in your 3 stores do not display any title or content type, making it difficult to understand which document is which by just reading the 7-character ID of the documents. This will be addressed very quickly, as soon as the "Header branch" feature will be implemented. For the same reason (lack of this feature), and in the web-app only, when you will have created many docs with many modifications, the loading of your app can take some time because it is loading all the content of all the docs at startup. The native apps are already working well and do not suffer from this caveat. For the web-app, it is not the intended behaviour of course, but we need the "Header branch" feature to fix this.
- The webapp has some limitation for now when it is offline, because it doesn't have a UserStorage. it works differently than the native apps, as it has to replay all the commits at every load. This will stay like that for now, as the feature "Web UserStorage" based on IndexedDB will take some time to be coded. - The webapp has some limitation for now when it is offline, because it doesn't have a UserStorage. it works differently than the native apps, as it has to replay all the commits at every load. This will stay like that for now, as the feature "Web UserStorage" based on IndexedDB will take some time to be coded.
- JSON-LD isn't ready yet as we need the "Context branch" feature in order to enter the list of ontologies each document is based on. - JSON-LD isn't ready yet as we need the "Context branch" feature in order to enter the list of ontologies each document is based on.

@ -2,7 +2,7 @@
name = "nextgraph" name = "nextgraph"
description = "NextGraph client library. Nextgraph is a decentralized, secure and local-first web 3.0 ecosystem based on Semantic Web and CRDTs" description = "NextGraph client library. Nextgraph is a decentralized, secure and local-first web 3.0 ecosystem based on Semantic Web and CRDTs"
categories = ["asynchronous","text-editors","web-programming","development-tools","database-implementations"] categories = ["asynchronous","text-editors","web-programming","development-tools","database-implementations"]
version = "0.1.0-preview.8" version = "0.1.1-alpha"
edition.workspace = true edition.workspace = true
license.workspace = true license.workspace = true
authors.workspace = true authors.workspace = true
@ -32,14 +32,14 @@ whoami = "1.5.1"
qrcode = { version = "0.14.1", default-features = false, features = ["svg"] } qrcode = { version = "0.14.1", default-features = false, features = ["svg"] }
svg2pdf = { version = "0.11.0", default-features = false } svg2pdf = { version = "0.11.0", default-features = false }
pdf-writer = "0.10.0" pdf-writer = "0.10.0"
ng-repo = { path = "../ng-repo", version = "0.1.0-preview.8" } ng-repo = { path = "../ng-repo", version = "0.1.1-alpha" }
ng-net = { path = "../ng-net", version = "0.1.0-preview.8" } ng-net = { path = "../ng-net", version = "0.1.1-alpha" }
ng-wallet = { path = "../ng-wallet", version = "0.1.0-preview.8" } ng-wallet = { path = "../ng-wallet", version = "0.1.1-alpha" }
ng-client-ws = { path = "../ng-client-ws", version = "0.1.0-preview.8" } ng-client-ws = { path = "../ng-client-ws", version = "0.1.1-alpha" }
ng-verifier = { path = "../ng-verifier", version = "0.1.0-preview.8" } ng-verifier = { path = "../ng-verifier", version = "0.1.1-alpha" }
[target.'cfg(all(not(target_family = "wasm"),not(docsrs)))'.dependencies] [target.'cfg(all(not(target_family = "wasm"),not(docsrs)))'.dependencies]
ng-storage-rocksdb = { path = "../ng-storage-rocksdb", version = "0.1.0-preview.8" } ng-storage-rocksdb = { path = "../ng-storage-rocksdb", version = "0.1.1-alpha" }
[[example]] [[example]]
name = "in_memory" name = "in_memory"

@ -43,7 +43,7 @@ A tokio-based version (as a feature) might be available in the future.
```toml ```toml
[dependencies] [dependencies]
nextgraph = "0.1.0-preview.8" nextgraph = "0.1.1-alpha"
async-std = "1.12.0" async-std = "1.12.0"
``` ```

@ -1819,7 +1819,7 @@ lazy_static! {
server_type: BrokerServerTypeV0::Domain("nextgraph.eu".to_string()), server_type: BrokerServerTypeV0::Domain("nextgraph.eu".to_string()),
can_verify: false, can_verify: false,
can_forward: false, can_forward: false,
peer_id: ng_repo::utils::decode_key("BVboIbTZzSgRzjtNSc0do8Uw2YlKk8m-4ePZ6CJkjgEA") peer_id: ng_repo::utils::decode_key("qCDCdmh39BccRrIzuxiyGY7r2012mFeUmMV57-RbB-cA")
.unwrap(), .unwrap(),
}; };
} }

@ -116,19 +116,24 @@
</div> </div>
<script> <script>
const supported = (() => { const supported = (() => {
if (RegExp().hasIndices === undefined) return false; if (RegExp().hasIndices === undefined) {console.log("no RegExp().hasIndices");return false;}
try { try {
if (Worker === undefined) return false; if (Worker === undefined) {console.log("no Worker");return false;}
new Worker(URL.createObjectURL(new Blob(['console.log("webworker ok");'], {type: 'application/javascript'}))); new Worker(URL.createObjectURL(new Blob([';'], {type: 'application/javascript'})));
if (typeof WebAssembly === "object" if (typeof WebAssembly === "object"
&& typeof WebAssembly.instantiate === "function") { && typeof WebAssembly.instantiate === "function") {
const module = new WebAssembly.Module(Uint8Array.of(0x0, 0x61, 0x73, 0x6d, 0x01, 0x00, 0x00, 0x00)); const module = new WebAssembly.Module(Uint8Array.of(0x0, 0x61, 0x73, 0x6d, 0x01, 0x00, 0x00, 0x00));
if (module instanceof WebAssembly.Module) if (module instanceof WebAssembly.Module)
return new WebAssembly.Instance(module) instanceof WebAssembly.Instance; return new WebAssembly.Instance(module) instanceof WebAssembly.Instance;
else {
console.log("no WebAssembly module");
}
} }
} catch (e) { } catch (e) {
{console.log(e);return false;}
} }
console.log("no WebAssembly");
return false; return false;
})(); })();
if (!supported ) { if (!supported ) {

@ -1,7 +1,7 @@
{ {
"name": "ng-app", "name": "ng-app",
"private": true, "private": true,
"version": "0.1.0-preview.8", "version": "0.1.1-alpha",
"type": "module", "type": "module",
"scripts": { "scripts": {
"dev": "shx cp index-native.html index.html && vite", "dev": "shx cp index-native.html index.html && vite",
@ -68,7 +68,7 @@
"immutable-json-patch": "^6.0.1", "immutable-json-patch": "^6.0.1",
"katex": "^0.16.11", "katex": "^0.16.11",
"lodash.debounce": "4.0.8", "lodash.debounce": "4.0.8",
"ng-sdk-js": "workspace:^0.1.0-preview.8", "ng-sdk-js": "workspace:^0.1.1-alpha",
"prism-themes": "^1.9.0", "prism-themes": "^1.9.0",
"prosemirror-model": "^1.7.1", "prosemirror-model": "^1.7.1",
"prosemirror-state": "^1.2.3", "prosemirror-state": "^1.2.3",

@ -551,6 +551,53 @@ async fn branch_history(session_id: u64, nuri: String) -> Result<AppHistoryJs, S
} }
} }
#[tauri::command(rename_all = "snake_case")]
async fn update_header(
session_id: u64,
nuri: String,
title: Option<String>,
about: Option<String>,
) -> Result<(), String> {
let nuri = NuriV0::new_from(&nuri).map_err(|e| e.to_string())?;
let request = AppRequest::V0(AppRequestV0 {
command: AppRequestCommandV0::new_header(),
nuri,
payload: Some(AppRequestPayload::new_header(title, about)),
session_id,
});
let res = nextgraph::local_broker::app_request(request)
.await
.map_err(|e: NgError| e.to_string())?;
if let AppResponse::V0(AppResponseV0::Error(e)) = res {
Err(e)
} else {
Ok(())
}
}
#[tauri::command(rename_all = "snake_case")]
async fn fetch_header(session_id: u64, nuri: String) -> Result<AppHeader, String> {
let nuri = NuriV0::new_from(&nuri).map_err(|e| e.to_string())?;
let request = AppRequest::V0(AppRequestV0 {
command: AppRequestCommandV0::new_fetch_header(),
nuri,
payload: None,
session_id,
});
let res = nextgraph::local_broker::app_request(request)
.await
.map_err(|e: NgError| e.to_string())?;
match res {
AppResponse::V0(AppResponseV0::Error(e)) => Err(e),
AppResponse::V0(AppResponseV0::Header(h)) => Ok(h),
_ => Err("invalid response".to_string()),
}
}
#[tauri::command(rename_all = "snake_case")] #[tauri::command(rename_all = "snake_case")]
async fn sparql_update( async fn sparql_update(
session_id: u64, session_id: u64,
@ -1023,6 +1070,8 @@ impl AppBuilder {
signature_status, signature_status,
signature_request, signature_request,
signed_snapshot_request, signed_snapshot_request,
update_header,
fetch_header,
]) ])
.run(tauri::generate_context!()) .run(tauri::generate_context!())
.expect("error while running tauri application"); .expect("error while running tauri application");

@ -8,7 +8,7 @@
}, },
"package": { "package": {
"productName": "Nextgraph", "productName": "Nextgraph",
"version": "0.1.0-preview.8" "version": "0.1.1-alpha"
}, },
"tauri": { "tauri": {
"bundle": { "bundle": {

@ -53,6 +53,8 @@ const mapping = {
"signature_status": ["session_id", "nuri"], "signature_status": ["session_id", "nuri"],
"signed_snapshot_request": ["session_id", "nuri"], "signed_snapshot_request": ["session_id", "nuri"],
"signature_request": ["session_id", "nuri"], "signature_request": ["session_id", "nuri"],
"update_header": ["session_id","nuri","title","about"],
"fetch_header": ["session_id", "nuri"]
} }

@ -11,8 +11,7 @@
<script lang="ts"> <script lang="ts">
import { import ng from "../api";
} from "../store";
import { link } from "svelte-spa-router"; import { link } from "svelte-spa-router";
import { Button, Progressbar, Spinner, Alert } from "flowbite-svelte"; import { Button, Progressbar, Spinner, Alert } from "flowbite-svelte";
import{ PlusCircle } from "svelte-heros-v2"; import{ PlusCircle } from "svelte-heros-v2";
@ -20,9 +19,16 @@
import { import {
in_memory_discrete, open_viewer, set_viewer, set_editor, set_view_or_edit, cur_tab_branch_class, cur_tab_doc_can_edit, cur_tab in_memory_discrete, open_viewer, set_viewer, set_editor, set_view_or_edit, cur_tab_branch_class, cur_tab_doc_can_edit, cur_tab
} from "../tab"; } from "../tab";
import DataClassIcon from "../lib/icons/DataClassIcon.svelte";
import { import {
openModalCreate openModalCreate,
sparql_query,
active_session
} from "../store"; } from "../store";
import {
Clipboard
} from "svelte-heros-v2";
export let commits; export let commits;
function contained(graph) { function contained(graph) {
@ -30,23 +36,41 @@
for (const g of graph) { for (const g of graph) {
if (g.substring(57,90) === "http://www.w3.org/ns/ldp#contains") { if (g.substring(57,90) === "http://www.w3.org/ns/ldp#contains") {
let nuri = g.substring(93,146); let nuri = g.substring(93,146);
let repo = nuri;
nuri = nuri + ":" + $cur_tab.store.overlay; nuri = nuri + ":" + $cur_tab.store.overlay;
let hash = nuri.substring(9,16); let hash = nuri.substring(9,16);
ret.push({nuri,hash}); ret.push({nuri,hash,repo});
} }
} }
ret.sort((a, b) => a.hash.localeCompare(b.hash)); ret.sort((a, b) => a.hash.localeCompare(b.hash));
return ret; return ret;
} }
async function fetch_header(repo) {
try {
let res = await ng.fetch_header($active_session.session_id, repo);
return res;
}catch(e){
console.error(e);
return {};
}
}
const create = () => { const create = () => {
openModalCreate(); openModalCreate();
} }
const config = {
class: "mr-2 w-6 h-6 shrink-0 focus:outline-none"
}
</script> </script>
<div class="flex-col p-5"> <div class="flex-col p-5">
{#each contained(commits.graph) as doc} {#each contained(commits.graph) as doc}
<div class="flex font-mono mb-3"> <a use:link href="/{doc.nuri}">{doc.hash}</a> </div> {#await fetch_header(doc.repo)}
<div class="flex"> <Clipboard tabindex="-1" class="mr-2 w-6 h-6 shrink-0 focus:outline-none"/><div class="flex font-mono mb-3"> <a use:link href="/{doc.nuri}">{doc.hash}</a> </div> </div>
{:then header}
<div class="flex" title="{header.about || ''}"> {#if header.class}<DataClassIcon {config} dataClass={header.class}/>{:else}<Clipboard tabindex="-1" class="mr-2 w-6 h-6 shrink-0 focus:outline-none"/>{/if}<div class="flex font-mono mb-3"> <a use:link href="/{doc.nuri}">{header.title || doc.hash}</a> </div></div>
{/await}
{/each} {/each}
{#if commits.graph.length == 0 || contained(commits.graph).length == 0} {#if commits.graph.length == 0 || contained(commits.graph).length == 0}
<p>{$t("doc.empty_container")}</p> <p>{$t("doc.empty_container")}</p>

@ -104,6 +104,7 @@
} }
onMount(async ()=>{ onMount(async ()=>{
if (editor) await editor.destroy();
await setup(); await setup();
}); });
@ -112,6 +113,7 @@
ydoc.destroy(); ydoc.destroy();
commits.discrete?.deregisterOnUpdate(); commits.discrete?.deregisterOnUpdate();
if (editor) await editor.destroy(); if (editor) await editor.destroy();
editor = undefined;
}); });

@ -181,7 +181,7 @@
} }
onMount(async ()=>{ onMount(async ()=>{
if (editor) await editor.destroy();
await setup(); await setup();
}); });
@ -189,6 +189,7 @@
onDestroy(async ()=>{ onDestroy(async ()=>{
ydoc.destroy(); ydoc.destroy();
if (editor) await editor.destroy(); if (editor) await editor.destroy();
editor = undefined;
}); });
</script> </script>

@ -129,6 +129,7 @@
} }
onMount(async ()=>{ onMount(async ()=>{
if (editor) await editor.destroy();
await setup(); await setup();
}); });
@ -137,6 +138,7 @@
ydoc.destroy(); ydoc.destroy();
try { try {
if (editor) await editor.destroy(); if (editor) await editor.destroy();
editor = undefined;
} catch(e) { } catch(e) {
console.log(e); console.log(e);
} }

@ -55,7 +55,7 @@
await reset_toasts(); await reset_toasts();
results = await sparql_query($in_memory_discrete, union); results = await sparql_query($in_memory_discrete, union);
} catch(e) { } catch(e) {
console.log(e) console.error(e)
toast_error(display_error(e)); toast_error(display_error(e));
} }
} }
@ -112,7 +112,7 @@
{#each results.results.bindings as row} {#each results.results.bindings as row}
<TableBodyRow> <TableBodyRow>
{#each results.head.vars as variable} {#each results.head.vars as variable}
<TableBodyCell class="px-6 py-4 whitespace-break-spaces font-medium">{row[variable].value}</TableBodyCell> <TableBodyCell class="px-6 py-4 whitespace-break-spaces font-medium">{#if row[variable]} {row[variable].value }{/if}</TableBodyCell>
{/each} {/each}
</TableBodyRow> </TableBodyRow>
{/each} {/each}

@ -254,6 +254,7 @@
onDestroy(async ()=>{ onDestroy(async ()=>{
ydoc.destroy(); ydoc.destroy();
await editor.destroy(); await editor.destroy();
editor = undefined;
}); });
function onRenderMenu(items, context) { function onRenderMenu(items, context) {

@ -125,6 +125,7 @@
onDestroy(async ()=>{ onDestroy(async ()=>{
ydoc.destroy(); ydoc.destroy();
await editor.destroy(); await editor.destroy();
editor = undefined;
}); });
const edit = () => { const edit = () => {

@ -12,7 +12,7 @@
// "data:graph", "data:json", "data:array", "data:map", "data:xml", "data:table", "data:collection", "data:board", "data:grid", "data:geomap", // "data:graph", "data:json", "data:array", "data:map", "data:xml", "data:table", "data:collection", "data:board", "data:grid", "data:geomap",
// "e:email", "e:web", "e:http://[url of class in ontology]", "e:rdf" (read-only cache of RDF fetched from web2.0) // "e:email", "e:web", "e:http://[url of class in ontology]", "e:rdf" (read-only cache of RDF fetched from web2.0)
// "mc:text", "mc:link", "mc:card", "mc:pad", // "mc:text", "mc:link", "mc:card", "mc:pad",
// "doc:diagram","doc:chart", "doc:pdf", "doc:odf", "doc:latex", "doc:ps", "doc:music", "doc:maths", "doc:chemistry", "doc:braille", "doc:ancientscript", // "diagram","chart", "doc:pdf", "doc:odf", "doc:latex", "doc:ps", "doc:music", "doc:maths", "doc:chemistry", "doc:braille", "doc:ancientscript",
// "media:image", "media:reel", "media:album", "media:video", "media:audio", "media:song", "media:subtitle", "media:overlay", // "media:image", "media:reel", "media:album", "media:video", "media:audio", "media:song", "media:subtitle", "media:overlay",
// "social:channel", "social:stream", "social:contact", "social:event", "social:calendar", "social:scheduler", "social:reaction", "social:chatroom", // "social:channel", "social:stream", "social:contact", "social:event", "social:calendar", "social:scheduler", "social:reaction", "social:chatroom",
// "prod:task", "prod:project", "prod:issue", "prod:form", "prod:filling", "prod:cad", "prod:slides", "prod:question", "prod:answer", "prod:poll", "prod:vote" // "prod:task", "prod:project", "prod:issue", "prod:form", "prod:filling", "prod:cad", "prod:slides", "prod:question", "prod:answer", "prod:poll", "prod:vote"
@ -165,35 +165,24 @@ export const official_classes = {
}, },
"ng:compat": ["rdfs:Class"], "ng:compat": ["rdfs:Class"],
}, },
"schema:rdfs": { "schema": { // display with https://github.com/VisualDataWeb/WebVOWL
"ng:crdt": "Graph", "ng:crdt": "Graph",
"ng:n": "Schema - RDFS", "ng:n": "Schema - RDFS/OWL",
"ng:a": "Define the Schema, Ontology or Vocabulary for your data and the relations between them, with RDFS", "ng:a": "Define the Schema, Ontology or Vocabulary for your data and the relations between them, with RDFS and/or OWL",
"ng:o": "n:g:z:json_ld_viewer", // default viewer "ng:o": "n:g:z:ontology_viewer", // default viewer
"ng:w": "n:g:z:ontology_editor", // default editor "ng:w": "n:g:z:ontology_editor", // default editor
"ng:x": { "ng:x": {
"rdfs":true, "rdfs":true,
},
"ng:include": ["data:graph"],
"ng:compat": ["rdfs:*","class"],
},
"schema:owl": { // display with https://github.com/VisualDataWeb/WebVOWL
"ng:crdt": "Graph",
"ng:n": "Schema - OWL",
"ng:a": "Define the Schema, Ontology or Vocabulary for your data and the relations between them, with OWL",
"ng:o": "n:g:z:owl_viewer", // default viewer
"ng:w": "n:g:z:ontology_editor", // default editor
"ng:x": {
"owl":true, "owl":true,
}, },
"ng:include": ["data:graph"], "ng:include": ["data:graph"],
"ng:compat": ["owl:Ontology"], "ng:compat": ["rdfs:*","class","owl:Ontology"],
}, },
"schema:shacl": { "schema:shacl": {
"ng:crdt": "Graph", "ng:crdt": "Graph",
"ng:n": "Schema - SHACL", "ng:n": "Schema - SHACL",
"ng:a": "Define the Schema, Ontology or Vocabulary for your data and the relations between them, with SHACL", "ng:a": "Define the rules for your data with SHACL",
"ng:o": "n:g:z:json_ld_viewer", // default viewer "ng:o": "n:g:z:ontology_viewer", // default viewer
"ng:w": "n:g:z:ontology_editor", // default editor "ng:w": "n:g:z:ontology_editor", // default editor
"ng:x": { "ng:x": {
"sh":true, "sh":true,
@ -204,8 +193,8 @@ export const official_classes = {
"schema:shex": { "schema:shex": {
"ng:crdt": "Graph", "ng:crdt": "Graph",
"ng:n": "Schema - SHEX", "ng:n": "Schema - SHEX",
"ng:a": "Define the Schema, Ontology or Vocabulary for your data and the relations between them, with SHEX", "ng:a": "Define the rules for your data with SHEX",
"ng:o": "n:g:z:json_ld_viewer", // default viewer "ng:o": "n:g:z:ontology_viewer", // default viewer
"ng:w": "n:g:z:ontology_editor", // default editor "ng:w": "n:g:z:ontology_editor", // default editor
"ng:x": { "ng:x": {
"shex":true, "shex":true,
@ -426,13 +415,13 @@ export const official_classes = {
"ng:n": "Link", "ng:n": "Link",
"ng:a": "Link to a document. kept in Magic Carpet", "ng:a": "Link to a document. kept in Magic Carpet",
}, },
"plato/card": { "plato:card": {
"ng:crdt": "Graph", "ng:crdt": "Graph",
"ng:n": "Card", "ng:n": "Card",
"ng:a": "Card representation of a document", "ng:a": "Card representation of a document",
"ng:o": "n:g:z:card", "ng:o": "n:g:z:card",
}, },
"plato/pad": { "plato:pad": {
"ng:crdt": "Graph", "ng:crdt": "Graph",
"ng:n": "Pad", "ng:n": "Pad",
"ng:a": "Pad representation of a document", "ng:a": "Pad representation of a document",
@ -445,62 +434,62 @@ export const official_classes = {
"ng:o": "n:g:z:compose:viewer", "ng:o": "n:g:z:compose:viewer",
"ng:w": "n:g:z:compose:editor", "ng:w": "n:g:z:compose:editor",
}, },
"doc:diagram:mermaid" : { "diagram:mermaid" : {
"ng:crdt": "YText", "ng:crdt": "YText",
"ng:n": "Diagram - Mermaid", "ng:n": "Diagram - Mermaid",
"ng:a": "Describe Diagrams with Mermaid", "ng:a": "Describe Diagrams with Mermaid",
"ng:compat": ["file:iana:application:vnd.mermaid"] "ng:compat": ["file:iana:application:vnd.mermaid"]
}, },
"doc:diagram:drawio" : { "diagram:drawio" : {
"ng:crdt": "YXml", "ng:crdt": "YXml",
"ng:n": "Diagram - DrawIo", "ng:n": "Diagram - DrawIo",
"ng:a": "Draw Diagrams with DrawIo", "ng:a": "Draw Diagrams with DrawIo",
"ng:compat": ["file:iana:application:vnd.jgraph.mxfile","file:iana:application:x-drawio"] "ng:compat": ["file:iana:application:vnd.jgraph.mxfile","file:iana:application:x-drawio"]
}, },
"doc:diagram:graphviz" : { "diagram:graphviz" : {
"ng:crdt": "YText", "ng:crdt": "YText",
"ng:n": "Diagram - Graphviz", "ng:n": "Diagram - Graphviz",
"ng:a": "Describe Diagrams with Graphviz", "ng:a": "Describe Diagrams with Graphviz",
"ng:compat": ["file:iana:text:vnd.graphviz"] "ng:compat": ["file:iana:text:vnd.graphviz"]
}, },
"doc:diagram:excalidraw" : { "diagram:excalidraw" : {
"ng:crdt": "Automerge", "ng:crdt": "Automerge",
"ng:n": "Diagram - Excalidraw", "ng:n": "Diagram - Excalidraw",
"ng:a": "Collaborate on Diagrams with Excalidraw", "ng:a": "Collaborate on Diagrams with Excalidraw",
"ng:compat": ["file:iana:application:vnd.excalidraw+json"] "ng:compat": ["file:iana:application:vnd.excalidraw+json"]
}, },
"doc:diagram:gantt" : { //https://github.com/frappe/gantt "diagram:gantt" : { //https://github.com/frappe/gantt
"ng:crdt": "Automerge", "ng:crdt": "Automerge",
"ng:n": "Diagram - Gantt", "ng:n": "Diagram - Gantt",
"ng:a": "Interactive gantt chart", "ng:a": "Interactive gantt chart",
"ng:compat": [] "ng:compat": []
}, },
"doc:diagram:flowchart" : { //https://github.com/adrai/flowchart.js "diagram:flowchart" : { //https://github.com/adrai/flowchart.js
"ng:crdt": "YText", "ng:crdt": "YText",
"ng:n": "Diagram - Flowchart", "ng:n": "Diagram - Flowchart",
"ng:a": "flow chart diagrams", "ng:a": "flow chart diagrams",
"ng:compat": [] "ng:compat": []
}, },
"doc:diagram:sequence" : { //https://github.com/bramp/js-sequence-diagrams "diagram:sequence" : { //https://github.com/bramp/js-sequence-diagrams
"ng:crdt": "YText", "ng:crdt": "YText",
"ng:n": "Diagram - Sequence", "ng:n": "Diagram - Sequence",
"ng:a": "sequence diagrams", "ng:a": "sequence diagrams",
"ng:compat": [] "ng:compat": []
}, },
// checkout https://www.mindmaps.app/ but it is AGPL // checkout https://www.mindmaps.app/ but it is AGPL
"doc:diagram:markmap" : { //https://github.com/markmap/markmap "diagram:markmap" : { //https://github.com/markmap/markmap
"ng:crdt": "YText", "ng:crdt": "YText",
"ng:n": "Diagram - Markmap", "ng:n": "Diagram - Markmap",
"ng:a": "mindmaps with markmap", "ng:a": "mindmaps with markmap",
"ng:compat": [] "ng:compat": []
}, },
"doc:diagram:mymind" : { //https://github.com/markmap/markmap "diagram:mymind" : { //https://github.com/markmap/markmap
"ng:crdt": "YText", // see MyMind format, MindMup JSON, FreeMind XML and MindMap Architect XML "ng:crdt": "YText", // see MyMind format, MindMup JSON, FreeMind XML and MindMap Architect XML
"ng:n": "Diagram - Mymind", "ng:n": "Diagram - Mymind",
"ng:a": "mindmaps with mymind", "ng:a": "mindmaps with mymind",
"ng:compat": [] // https://github.com/ondras/my-mind/wiki/Saving-and-loading#file-formats "ng:compat": [] // https://github.com/ondras/my-mind/wiki/Saving-and-loading#file-formats
}, },
"doc:diagram:jsmind" : { //https://github.com/hizzgdev/jsmind "diagram:jsmind" : { //https://github.com/hizzgdev/jsmind
"ng:crdt": "Automerge", "ng:crdt": "Automerge",
"ng:n": "Diagram - jsmind", "ng:n": "Diagram - jsmind",
"ng:a": "mindmaps with jsmind", "ng:a": "mindmaps with jsmind",
@ -514,69 +503,69 @@ export const official_classes = {
// https://github.com/Rich-Harris/pancake // https://github.com/Rich-Harris/pancake
// https://github.com/williamngan/pts // https://github.com/williamngan/pts
// https://visjs.org/ // https://visjs.org/
"doc:viz:cytoscape" : { "viz:cytoscape" : {
"ng:crdt": "Automerge", "ng:crdt": "Automerge",
"ng:n": "Viz - Cytoscape", "ng:n": "Viz - Cytoscape",
"ng:a": "Graph theory (network) visualization", "ng:a": "Graph theory (network) visualization",
"ng:compat": [] // https://github.com/cytoscape/cytoscape.js "ng:compat": [] // https://github.com/cytoscape/cytoscape.js
}, },
"doc:viz:vega" : { "viz:vega" : {
"ng:crdt": "Automerge", "ng:crdt": "Automerge",
"ng:n": "Viz - Vega", "ng:n": "Viz - Vega",
"ng:a": "Grammar for interactive graphics", "ng:a": "Grammar for interactive graphics",
"ng:compat": [] // https://vega.github.io/vega-lite/docs/ https://github.com/vega/editor "ng:compat": [] // https://vega.github.io/vega-lite/docs/ https://github.com/vega/editor
}, },
"doc:viz:vizzu" : { "viz:vizzu" : {
"ng:crdt": "Automerge", "ng:crdt": "Automerge",
"ng:n": "Viz - Vizzu", "ng:n": "Viz - Vizzu",
"ng:a": "Animated data visualizations and data stories", "ng:a": "Animated data visualizations and data stories",
"ng:compat": [] // https://github.com/vizzuhq/vizzu-lib "ng:compat": [] // https://github.com/vizzuhq/vizzu-lib
}, },
"doc:viz:plotly" : { //https://github.com/plotly/plotly.js "viz:plotly" : { //https://github.com/plotly/plotly.js
"ng:crdt": "Automerge", "ng:crdt": "Automerge",
"ng:n": "Viz - Plotly", "ng:n": "Viz - Plotly",
"ng:a": "Declarative charts", "ng:a": "Declarative charts",
"ng:compat": [] // https://github.com/cytoscape/cytoscape.js "ng:compat": [] // https://github.com/cytoscape/cytoscape.js
}, },
"doc:viz:avail" : { "viz:avail" : {
"ng:crdt": "Automerge", "ng:crdt": "Automerge",
"ng:n": "Viz - Avail", "ng:n": "Viz - Avail",
"ng:a": "Time Data Availability Visualization", "ng:a": "Time Data Availability Visualization",
"ng:compat": [] // https://github.com/flrs/visavail "ng:compat": [] // https://github.com/flrs/visavail
}, },
"doc:chart:frappecharts" : { "chart:frappecharts" : {
"ng:crdt": "Automerge", "ng:crdt": "Automerge",
"ng:n": "Charts - Frappe", "ng:n": "Charts - Frappe",
"ng:a": "GitHub-inspired responsive charts", "ng:a": "GitHub-inspired responsive charts",
"ng:compat": [] // https://github.com/frappe/charts "ng:compat": [] // https://github.com/frappe/charts
}, },
"doc:chart:financial" : { "chart:financial" : {
"ng:crdt": "Automerge", "ng:crdt": "Automerge",
"ng:n": "Charts - Financial", "ng:n": "Charts - Financial",
"ng:a": "Financial charts", "ng:a": "Financial charts",
"ng:compat": [] //https://github.com/tradingview/lightweight-charts "ng:compat": [] //https://github.com/tradingview/lightweight-charts
}, },
// have a look at https://github.com/cube-js/cube and https://awesome.cube.dev/ and https://frappe.io/products // have a look at https://github.com/cube-js/cube and https://awesome.cube.dev/ and https://frappe.io/products
"doc:chart:apexcharts" : { "chart:apexcharts" : {
"ng:crdt": "Automerge", "ng:crdt": "Automerge",
"ng:n": "Charts - ApexCharts", "ng:n": "Charts - ApexCharts",
"ng:a": "Interactive data visualizations", "ng:a": "Interactive data visualizations",
"ng:compat": [] // https://github.com/apexcharts/apexcharts.js "ng:compat": [] // https://github.com/apexcharts/apexcharts.js
}, },
//realtime data with https://github.com/square/cubism //realtime data with https://github.com/square/cubism
"doc:chart:billboard" : { "chart:billboard" : {
"ng:crdt": "Automerge", "ng:crdt": "Automerge",
"ng:n": "Charts - BillBoard", "ng:n": "Charts - BillBoard",
"ng:a": "Interactive data visualizations based on D3", "ng:a": "Interactive data visualizations based on D3",
"ng:compat": [] // https://github.com/naver/billboard.js "ng:compat": [] // https://github.com/naver/billboard.js
}, },
"doc:chart:echarts" : { "chart:echarts" : {
"ng:crdt": "Automerge", "ng:crdt": "Automerge",
"ng:n": "Charts - ECharts", "ng:n": "Charts - ECharts",
"ng:a": "Interactive charting and data visualization with Apache ECharts", "ng:a": "Interactive charting and data visualization with Apache ECharts",
"ng:compat": [] // https://github.com/apache/echarts "ng:compat": [] // https://github.com/apache/echarts
}, },
"doc:chart:chartjs" : { "chart:chartjs" : {
"ng:crdt": "Automerge", "ng:crdt": "Automerge",
"ng:n": "Charts - Chart.js", "ng:n": "Charts - Chart.js",
"ng:a": "Simple yet flexible charting for designers & developers with Chart.js", "ng:a": "Simple yet flexible charting for designers & developers with Chart.js",

@ -14,7 +14,7 @@
branch_subscribe, branch_subscribe,
active_session, active_session,
cannot_load_offline, cannot_load_offline,
online, open_doc_popup
} from "../store"; } from "../store";
import { import {
@ -42,7 +42,7 @@
const inview_options = {};//{rootMargin: "-44px"}; const inview_options = {};//{rootMargin: "-44px"};
function openEditHeader() { function openEditHeader() {
//TODO open_doc_popup("header");
} }
</script> </script>

@ -34,7 +34,6 @@
import BranchIcon from "./icons/BranchIcon.svelte"; import BranchIcon from "./icons/BranchIcon.svelte";
import Message from "./components/Message.svelte"; import Message from "./components/Message.svelte";
import Signature from "./popups/Signature.svelte";
import { import {
get, get,
} from "svelte/store"; } from "svelte/store";
@ -47,11 +46,11 @@
has_editor_chat, all_files_count, all_comments_count, hideMenu, show_modal_menu, show_modal_create, has_editor_chat, all_files_count, all_comments_count, 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_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, show_spinner, cur_tab_toc_pane, cur_tab_show_menu, cur_tab_branch_has_discrete, cur_tab_graph_or_discrete, cur_tab_view_or_edit, show_spinner,
in_private_store, show_doc_popup, cur_doc_popup, open_doc_popup } from "../tab"; in_private_store, show_doc_popup, cur_doc_popup } from "../tab";
import { import {
active_session, redirect_after_login, toasts, check_has_camera, toast_error, active_session, redirect_after_login, toasts, check_has_camera, toast_error,
reset_toasts, redirect_if_wallet_is, active_wallet, reset_toasts, redirect_if_wallet_is, active_wallet,
display_error, openModalCreate display_error, openModalCreate, open_doc_popup
} from "../store"; } from "../store";
import ZeraIcon from "./icons/ZeraIcon.svelte"; import ZeraIcon from "./icons/ZeraIcon.svelte";
import ng from "../api"; import ng from "../api";
@ -300,33 +299,33 @@
]; ];
const create_chart_items = [ const create_chart_items = [
"doc:chart:frappecharts", "chart:frappecharts",
"doc:chart:financial", "chart:financial",
"doc:chart:apexcharts", "chart:apexcharts",
"doc:chart:billboard", "chart:billboard",
"doc:chart:echarts", "chart:echarts",
"doc:chart:chartjs", "chart:chartjs",
]; ];
const create_viz_items = [ const create_viz_items = [
"doc:viz:cytoscape", "viz:cytoscape",
"doc:viz:vega", "viz:vega",
"doc:viz:vizzu", "viz:vizzu",
"doc:viz:plotly", "viz:plotly",
"doc:viz:avail", "viz:avail",
]; ];
const create_diagram_items = [ const create_diagram_items = [
"doc:diagram:mermaid", "diagram:mermaid",
"doc:diagram:drawio", "diagram:drawio",
"doc:diagram:graphviz", "diagram:graphviz",
"doc:diagram:excalidraw", "diagram:excalidraw",
"doc:diagram:gantt", "diagram:gantt",
"doc:diagram:flowchart", "diagram:flowchart",
"doc:diagram:sequence", "diagram:sequence",
"doc:diagram:markmap", "diagram:markmap",
"doc:diagram:mymind", "diagram:mymind",
"doc:diagram:jsmind", "diagram:jsmind",
]; ];
const create_doc_items = [ const create_doc_items = [
@ -367,6 +366,19 @@
"app:n:xxx.xx.xx", "app:n:xxx.xx.xx",
]; ];
import Signature from "./popups/Signature.svelte";
import Header from "./popups/Header.svelte";
const doc_popups = {
"signature": Signature,
"header": Header,
}
const doc_popups_size = {
"signature": "xs",
"header": "md",
}
let top; let top;
let shareMenu; let shareMenu;
let toolsMenu; let toolsMenu;
@ -428,7 +440,7 @@
const openAction = (action:string) => { const openAction = (action:string) => {
hideMenu(); hideMenu();
if (doc_popups[action]) open_doc_popup(action); open_doc_popup(action);
} }
const openPane = (pane:string) => { const openPane = (pane:string) => {
@ -564,10 +576,6 @@
"mc":Sparkles, "mc":Sparkles,
}; };
const doc_popups = {
"signature": Signature,
}
let destination = "store"; let destination = "store";
$: destination = $cur_tab_branch_nuri === "" ? "mc" : destination == "mc" ? "store" : destination; $: destination = $cur_tab_branch_nuri === "" ? "mc" : destination == "mc" ? "store" : destination;
@ -755,7 +763,8 @@
{/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") }> <!-- ()=> openAction("new_block") -->
<MenuItem title={$t("doc.menu.items.new_block.desc")} clickable={ undefined }>
<PlusCircle <PlusCircle
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"
@ -764,7 +773,8 @@
</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") }> <!-- ()=> openPane("chat") -->
<MenuItem title={$t("doc.menu.items.editor_chat.desc")} selected={$cur_tab_right_pane == "chat"} clickable={ undefined }>
<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>
@ -794,14 +804,16 @@
</MenuItem> </MenuItem>
{#if open_share } {#if open_share }
{#each share_items as share} {#each share_items as share}
<MenuItem title={$t(`doc.menu.items.${share.n}.desc`)} extraClass="submenu" clickable={ () => openShare(share.n) }> <!-- () => openShare(share.n) -->
<MenuItem title={$t(`doc.menu.items.${share.n}.desc`)} extraClass="submenu" clickable={ undefined }>
<Icon tabindex="-1" class="w-7 h-7 text-gray-700 focus:outline-none dark:text-white " variation="outline" color="currentColor" icon={share.i} /> <Icon tabindex="-1" class="w-7 h-7 text-gray-700 focus:outline-none dark:text-white " variation="outline" color="currentColor" icon={share.i} />
<span class="ml-3">{$t(`doc.menu.items.${share.n}.label`)}</span> <span class="ml-3">{$t(`doc.menu.items.${share.n}.label`)}</span>
</MenuItem> </MenuItem>
{/each} {/each}
{/if} {/if}
{:else} {:else}
<MenuItem title={$t(`doc.menu.items.download.desc`)} clickable={ () => openShare("download") }> <!-- () => openShare("download") -->
<MenuItem title={$t(`doc.menu.items.download.desc`)} clickable={ undefined }>
<Icon tabindex="-1" class="w-7 h-7 text-gray-700 focus:outline-none dark:text-white " variation="outline" color="currentColor" icon={DocumentArrowDown} /> <Icon tabindex="-1" class="w-7 h-7 text-gray-700 focus:outline-none dark:text-white " variation="outline" color="currentColor" icon={DocumentArrowDown} />
<span class="ml-3">{$t(`doc.menu.items.download.label`)}</span> <span class="ml-3">{$t(`doc.menu.items.download.label`)}</span>
</MenuItem> </MenuItem>
@ -823,37 +835,37 @@
<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>
<!-- find -->
<MenuItem title={$t("doc.menu.items.find.desc")} clickable={ find }> <MenuItem title={$t("doc.menu.items.find.desc")} clickable={ undefined }>
<MagnifyingGlass <MagnifyingGlass
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.items.find.label")}</span> <span class="ml-3">{$t("doc.menu.items.find.label")}</span>
</MenuItem> </MenuItem>
<!-- bookmark -->
<MenuItem title={$t("doc.menu.items.bookmark.desc")} clickable={ bookmark }> <MenuItem title={$t("doc.menu.items.bookmark.desc")} clickable={ undefined }>
<Bookmark <Bookmark
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.items.bookmark.label")}</span> <span class="ml-3">{$t("doc.menu.items.bookmark.label")}</span>
</MenuItem> </MenuItem>
<!-- annotate -->
<MenuItem title={$t("doc.menu.items.annotate.desc")} clickable={ annotate }> <MenuItem title={$t("doc.menu.items.annotate.desc")} clickable={ undefined }>
<ChatBubbleLeftEllipsis <ChatBubbleLeftEllipsis
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.items.annotate.label")}</span> <span class="ml-3">{$t("doc.menu.items.annotate.label")}</span>
</MenuItem> </MenuItem>
<!-- ()=> openPane("info") -->
<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={ undefined }>
<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>
<!-- ()=> openAction("notifs") -->
<MenuItem title={$t("doc.menu.items.notifs.desc")} clickable={ ()=> openAction("notifs") }> <MenuItem title={$t("doc.menu.items.notifs.desc")} clickable={ undefined }>
<Bell <Bell
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"
@ -861,7 +873,8 @@
<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 && !$in_private_store} {#if $cur_tab_doc_is_member && !$in_private_store}
<MenuItem title={$t("doc.menu.items.permissions.desc")} clickable={ ()=> openAction("permissions") }> <!-- ()=> openAction("permissions") -->
<MenuItem title={$t("doc.menu.items.permissions.desc")} clickable={ undefined }>
<LockOpen <LockOpen
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"
@ -869,7 +882,8 @@
<span class="ml-3">{$t("doc.menu.items.permissions.label")}</span> <span class="ml-3">{$t("doc.menu.items.permissions.label")}</span>
</MenuItem> </MenuItem>
{/if} {/if}
<MenuItem title={$t("doc.menu.items.settings.desc")} clickable={ ()=> openAction("settings") }> <!-- ()=> openAction("settings") -->
<MenuItem title={$t("doc.menu.items.settings.desc")} clickable={ undefined }>
<Cog6Tooth <Cog6Tooth
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"
@ -887,7 +901,8 @@
{#if open_tools } {#if open_tools }
{#each tools_items as tool} {#each tools_items as tool}
{#if !$in_private_store || tool.n !== "signature" } {#if !$in_private_store || tool.n !== "signature" }
<MenuItem title={$t(`doc.menu.items.${tool.n}.desc`)} extraClass="submenu" clickable={ () => openAction(tool.n) }> <!-- () => openAction(tool.n) -->
<MenuItem title={$t(`doc.menu.items.${tool.n}.desc`)} extraClass="submenu" clickable={ tool.n === "signature" ? () => openAction(tool.n) : undefined }>
<Icon tabindex="-1" class="w-7 h-7 text-gray-700 focus:outline-none dark:text-white " variation="outline" color="currentColor" icon={tool.i} /> <Icon tabindex="-1" class="w-7 h-7 text-gray-700 focus:outline-none dark:text-white " variation="outline" color="currentColor" icon={tool.i} />
<span class="ml-3">{$t(`doc.menu.items.${tool.n}.label`)}</span> <span class="ml-3">{$t(`doc.menu.items.${tool.n}.label`)}</span>
</MenuItem> </MenuItem>
@ -895,11 +910,13 @@
{/each} {/each}
{/if} {/if}
{/if} {/if}
<MenuItem title={$t("doc.menu.items.mc.desc")} selected={$cur_tab_right_pane == "mc"} clickable={ ()=> openPane("mc") }> <!-- ()=> openPane("mc") -->
<MenuItem title={$t("doc.menu.items.mc.desc")} selected={$cur_tab_right_pane == "mc"} clickable={ undefined }>
<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")} clickable={ ()=> openArchive() }> <!-- ()=> openArchive() -->
<MenuItem title={$t("doc.menu.items.archive.desc")} clickable={ undefined }>
<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"
@ -945,12 +962,12 @@
<Modal class="document-popup" <Modal class="document-popup"
outsideclose outsideclose
bind:open={$show_doc_popup} bind:open={$show_doc_popup}
size = 'xs' size = {doc_popups_size[$cur_doc_popup]}
placement = 'center' placement = 'center'
defaultClass="bg-white dark:bg-gray-800 text-gray-800 dark:text-gray-400 rounded-lg border-gray-200 dark:border-gray-700 divide-gray-200 dark:divide-gray-700 shadow-md relative flex flex-col mx-auto w-full" defaultClass="bg-white dark:bg-gray-800 text-gray-800 dark:text-gray-400 rounded-lg border-gray-200 dark:border-gray-700 divide-gray-200 dark:divide-gray-700 shadow-md relative flex flex-col mx-auto w-full"
backdropClass="bg-gray-900 bg-opacity-50 dark:bg-opacity-80 popup-bg-modal" backdropClass="bg-gray-900 bg-opacity-50 dark:bg-opacity-80 popup-bg-modal"
> >
<svelte:component this={doc_popups[$cur_doc_popup]}/> {#if doc_popups[$cur_doc_popup]}<svelte:component this={doc_popups[$cur_doc_popup]}/>{/if}
</Modal> </Modal>
<Modal class="menu-modal" <Modal class="menu-modal"
outsideclose outsideclose
@ -1121,7 +1138,7 @@
<div style="padding:0;" bind:this={createMenu.chart}></div> <div style="padding:0;" bind:this={createMenu.chart}></div>
<MenuItem title={$t("doc.chart")} dropdown={createMenuOpened.chart} clickable={ () => { createMenuOpened.chart = !createMenuOpened.chart; scrollToCreateMenu("chart"); } }> <MenuItem title={$t("doc.chart")} dropdown={createMenuOpened.chart} clickable={ () => { createMenuOpened.chart = !createMenuOpened.chart; scrollToCreateMenu("chart"); } }>
<DataClassIcon dataClass="doc:chart" {config}/> <DataClassIcon dataClass="chart" {config}/>
<span class="ml-3">{$t("doc.chart")}</span> <span class="ml-3">{$t("doc.chart")}</span>
</MenuItem> </MenuItem>
{#if createMenuOpened.chart } {#if createMenuOpened.chart }
@ -1136,7 +1153,7 @@
<div style="padding:0;" bind:this={createMenu.viz}></div> <div style="padding:0;" bind:this={createMenu.viz}></div>
<MenuItem title={$t("doc.viz")} dropdown={createMenuOpened.viz} clickable={ () => { createMenuOpened.viz = !createMenuOpened.viz; scrollToCreateMenu("viz"); } }> <MenuItem title={$t("doc.viz")} dropdown={createMenuOpened.viz} clickable={ () => { createMenuOpened.viz = !createMenuOpened.viz; scrollToCreateMenu("viz"); } }>
<DataClassIcon dataClass="doc:viz" {config}/> <DataClassIcon dataClass="viz" {config}/>
<span class="ml-3">{$t("doc.viz")}</span> <span class="ml-3">{$t("doc.viz")}</span>
</MenuItem> </MenuItem>
{#if createMenuOpened.viz } {#if createMenuOpened.viz }
@ -1151,7 +1168,7 @@
<div style="padding:0;" bind:this={createMenu.diagram}></div> <div style="padding:0;" bind:this={createMenu.diagram}></div>
<MenuItem title={$t("doc.diagram")} dropdown={createMenuOpened.diagram} clickable={ () => { createMenuOpened.diagram = !createMenuOpened.diagram; scrollToCreateMenu("diagram"); } }> <MenuItem title={$t("doc.diagram")} dropdown={createMenuOpened.diagram} clickable={ () => { createMenuOpened.diagram = !createMenuOpened.diagram; scrollToCreateMenu("diagram"); } }>
<DataClassIcon dataClass="doc:diagram" {config}/> <DataClassIcon dataClass="diagram" {config}/>
<span class="ml-3">{$t("doc.diagram")}</span> <span class="ml-3">{$t("doc.diagram")}</span>
</MenuItem> </MenuItem>
{#if createMenuOpened.diagram } {#if createMenuOpened.diagram }

@ -116,8 +116,8 @@
"e:link": Link, "e:link": Link,
"mc:text": Bars3BottomLeft, "mc:text": Bars3BottomLeft,
"mc:link": Link, "mc:link": Link,
"plato/card": Clipboard, "plato:card": Clipboard,
"plato/pad": Square2Stack, "plato:pad": Square2Stack,
"media:image": Photo, "media:image": Photo,
"media:reel": VideoCamera, "media:reel": VideoCamera,
"media:video": Film, "media:video": Film,
@ -171,9 +171,9 @@
"app:": StopCircle, "app:": StopCircle,
"query:": RocketLaunch, "query:": RocketLaunch,
"data:": CircleStack, "data:": CircleStack,
"doc:diagram": DocumentChartBar, "diagram": DocumentChartBar,
"doc:chart": ChartPie, "chart": ChartPie,
"doc:viz": ArrowTrendingUp, "viz": ArrowTrendingUp,
"doc:": ClipboardDocumentList, "doc:": ClipboardDocumentList,
file: Document, file: Document,
}; };

@ -0,0 +1,70 @@
<!--
// Copyright (c) 2022-2024 Niko Bonnieure, Par le Peuple, NextGraph.org developers
// All rights reserved.
// Licensed under the Apache License, Version 2.0
// <LICENSE-APACHE2 or http://www.apache.org/licenses/LICENSE-2.0>
// or the MIT license <LICENSE-MIT or http://opensource.org/licenses/MIT>,
// at your option. All files in the project carrying such
// notice may not be copied, modified, or distributed except
// according to those terms.
-->
<script lang="ts">
import {
branch_subscribe,
active_session,
toast_error,
toast_success,
display_error,
online,
change_header
} from "../../store";
import {
cur_tab,
show_doc_popup
} from "../../tab";
import { get } from "svelte/store";
import { onMount, onDestroy, tick } from "svelte";
import ng from "../../api";
import { t } from "svelte-i18n";
import {
CheckCircle
} from "svelte-heros-v2";
import {
} from "flowbite-svelte";
let is_tauri = import.meta.env.TAURI_PLATFORM;
onMount(()=>{
title = $cur_tab.doc.title;
about = $cur_tab.doc.description;
});
async function update_header() {
await change_header(title,about);
$show_doc_popup = false;
}
let title;
let about;
</script>
<div class="flex flex-col">
<span class="font-bold text-xl mb-3">{$t("doc.header.buttons.edit_intro")}</span>
{$t("doc.header.doc.title")} :
<input placeholder="Enter the title of the document" bind:value={title} class="mb-3"/>
{$t("doc.header.doc.about")} :
<textarea rows=6 class="my-4 col-span-6 pr-11 bg-gray-50 border border-gray-300 text-gray-900 text-sm rounded-lg focus:ring-blue-500 focus:border-blue-500 block w-full p-2.5 dark:bg-gray-700 dark:border-gray-600 dark:placeholder-gray-400 dark:text-gray-400 dark:focus:ring-blue-500 dark:focus:border-blue-500"
placeholder="Enter the introduction" bind:value={about}/>
<button
style="width:120px;"
on:click|once={update_header}
class="mt-4 text-white bg-primary-700 hover:bg-primary-700/90 focus:ring-4 focus:ring-primary-700/50 font-medium rounded-lg text-lg px-3 py-2.5 text-center inline-flex items-center dark:focus:ring-primary-700/55 mb-2"
>
<CheckCircle class="w-8 h-8 mr-3"/>
{$t("doc.header.buttons.save")}
</button>
</div>

@ -19,9 +19,9 @@
"pro": "Pro", "pro": "Pro",
"media": "Media", "media": "Media",
"chart": "Chart", "chart": "Chart",
"viz": "Vizualitation", "viz": "Visualization",
"diagram": "Diagram", "diagram": "Diagram",
"other": "Other file formats", "other": "Other formats",
"data": "Data", "data": "Data",
"code": "Code", "code": "Code",
"apps": "Apps", "apps": "Apps",
@ -71,7 +71,16 @@
"groups": "Groups", "groups": "Groups",
"channels": "Channels", "channels": "Channels",
"inbox": "Inbox", "inbox": "Inbox",
"chat": "Chat" "chat": "Chat",
"save": "Save"
},
"doc":{
"title": "Title",
"about": "Introduction"
},
"profile": {
"title": "Name",
"about": "Bio"
} }
}, },
"signature": { "signature": {
@ -555,6 +564,8 @@
"DecryptionError": "Error with decryption.", "DecryptionError": "Error with decryption.",
"InvalidValue": "The value is invalid.", "InvalidValue": "The value is invalid.",
"ConnectionNotFound": "The connection was not found.", "ConnectionNotFound": "The connection was not found.",
"InvalidSecurityImage": "The security image you chose is not valid.",
"InvalidSecurityText": "The security text you chose is too short. It must be at least 10 characters long.",
"InvalidKey": "The key is invalid.", "InvalidKey": "The key is invalid.",
"InvalidInvitation": "The invitation is invalid.", "InvalidInvitation": "The invitation is invalid.",
"InvalidCreateAccount": "An error occurred creating the account.", "InvalidCreateAccount": "An error occurred creating the account.",

@ -357,7 +357,7 @@
{/if} {/if}
<!-- Remove Wallet --> <!-- Remove Wallet -->
<li <!-- <li
tabindex="0" tabindex="0"
role="menuitem" role="menuitem"
class="text-left flex items-center p-2 text-base font-normal text-gray-900 clickable rounded-lg dark:text-white hover:bg-gray-200 dark:hover:bg-gray-700" class="text-left flex items-center p-2 text-base font-normal text-gray-900 clickable rounded-lg dark:text-white hover:bg-gray-200 dark:hover:bg-gray-700"
@ -372,7 +372,7 @@
</div> </div>
<span class="ml-3">{$t("pages.wallet_info.remove_wallet")}</span <span class="ml-3">{$t("pages.wallet_info.remove_wallet")}</span
> >
</li> </li> -->
<!-- Confirm Remove Wallet Modal --> <!-- Confirm Remove Wallet Modal -->
<Modal <Modal
autoclose autoclose

@ -147,6 +147,9 @@
async function gotWallet(event) { async function gotWallet(event) {
try { try {
if (importing) { if (importing) {
step = "loggedin";
$redirect_after_login=undefined;
$redirect_if_wallet_is=undefined;
let in_memory = !event.detail.trusted; let in_memory = !event.detail.trusted;
//console.log("IMPORTING", in_memory, event.detail.wallet, wallet); //console.log("IMPORTING", in_memory, event.detail.wallet, wallet);
let client = await ng.wallet_import( let client = await ng.wallet_import(
@ -188,6 +191,7 @@
if (importing) {wallet = undefined;} if (importing) {wallet = undefined;}
importing = false; importing = false;
error = e; error = e;
step = "open";
return; return;
} }
//await tick(); //await tick();
@ -252,6 +256,25 @@
{$t("buttons.start_over")} {$t("buttons.start_over")}
</button> </button>
</div> </div>
{:else if step == "loggedin"}
<div class=" max-w-6xl lg:px-8 mx-auto px-4 text-green-800">
{@html $t("pages.wallet_login.logged_in")}...
<svg
class="my-10 h-16 w-16 mx-auto"
fill="none"
stroke="currentColor"
stroke-width="1.5"
viewBox="0 0 24 24"
xmlns="http://www.w3.org/2000/svg"
aria-hidden="true"
>
<path
stroke-linecap="round"
stroke-linejoin="round"
d="M9 12.75L11.25 15 15 9.75M21 12c0 1.268-.63 2.39-1.593 3.068a3.745 3.745 0 01-1.043 3.296 3.745 3.745 0 01-3.296 1.043A3.745 3.745 0 0112 21c-1.268 0-2.39-.63-3.068-1.593a3.746 3.746 0 01-3.296-1.043 3.745 3.745 0 01-1.043-3.296A3.745 3.745 0 013 12c0-1.268.63-2.39 1.593-3.068a3.745 3.745 0 011.043-3.296 3.746 3.746 0 013.296-1.043A3.746 3.746 0 0112 3c1.268 0 2.39.63 3.068 1.593a3.746 3.746 0 013.296 1.043 3.746 3.746 0 011.043 3.296A3.745 3.745 0 0121 12z"
/>
</svg>
</div>
{:else if $wallet_from_import} {:else if $wallet_from_import}
<!-- Imported a wallet --> <!-- Imported a wallet -->
@ -437,25 +460,6 @@
</a> </a>
</div> </div>
</div> </div>
{:else if step == "loggedin"}
<div class=" max-w-6xl lg:px-8 mx-auto px-4 text-green-800">
{@html $t("pages.wallet_login.logged_in")}...
<svg
class="my-10 h-16 w-16 mx-auto"
fill="none"
stroke="currentColor"
stroke-width="1.5"
viewBox="0 0 24 24"
xmlns="http://www.w3.org/2000/svg"
aria-hidden="true"
>
<path
stroke-linecap="round"
stroke-linejoin="round"
d="M9 12.75L11.25 15 15 9.75M21 12c0 1.268-.63 2.39-1.593 3.068a3.745 3.745 0 01-1.043 3.296 3.745 3.745 0 01-3.296 1.043A3.745 3.745 0 0112 21c-1.268 0-2.39-.63-3.068-1.593a3.746 3.746 0 01-3.296-1.043 3.745 3.745 0 01-1.043-3.296A3.745 3.745 0 013 12c0-1.268.63-2.39 1.593-3.068a3.745 3.745 0 011.043-3.296 3.746 3.746 0 013.296-1.043A3.746 3.746 0 0112 3c1.268 0 2.39.63 3.068 1.593a3.746 3.746 0 013.296 1.043 3.746 3.746 0 011.043 3.296A3.745 3.745 0 0121 12z"
/>
</svg>
</div>
{/if} {/if}
</CenteredLayout> </CenteredLayout>
</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, show_modal_create, cur_tab_update, nav_bar,in_memory_save } from "./tab"; import { persistent_error, update_class, update_branch_display, open_branch, tab_update, change_nav_bar, cur_branch, cur_tab, show_modal_create, save, nav_bar,in_memory_save, cur_doc_popup, show_doc_popup } from "./tab";
import { encode } from "./base64url"; import { encode } from "./base64url";
let all_branches = {}; let all_branches = {};
@ -27,12 +27,12 @@ let retry_branches = {};
export const available_languages = { export const available_languages = {
en: "English", en: "English",
de: "Deutsch", de: "Deutsch",
fr: "Français", //fr: "Français",
ru: "Русский", //ru: "Русский",
es: "Español", //es: "Español",
it: "Italiano", //it: "Italiano",
zh: "中文", //zh: "中文",
pt: "Português", //pt: "Português",
}; };
for (const lang of Object.keys(available_languages)) { for (const lang of Object.keys(available_languages)) {
@ -47,6 +47,7 @@ init({
export const display_error = (error: string) => { export const display_error = (error: string) => {
if (error.message) return error.message; if (error.message) return error.message;
if (error.includes(" ")) return error; if (error.includes(" ")) return error;
if (error.includes("\"")) return error;
//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(":");
@ -143,6 +144,7 @@ export const toast_success = (text) => {
} }
export const openModalCreate = async () => { export const openModalCreate = async () => {
await save();
await reset_toasts() await reset_toasts()
show_modal_create.set(true); show_modal_create.set(true);
} }
@ -421,6 +423,43 @@ export const discrete_update = async (update, crdt, heads) => {
// the editor then process those updates and calls live_discrete_update // the editor then process those updates and calls live_discrete_update
} }
export const open_doc_popup = async (popup_name) => {
await reset_toasts();
cur_doc_popup.set(popup_name);
show_doc_popup.set(true);
}
export const change_header = async (title_, about_) => {
let session = get(active_session);
if (!session) {
persistent_error(get(cur_branch), {
title: get(format)("doc.errors.no_session"),
desc: get(format)("doc.errors_details.no_session")
});
throw new Error("no session");
}
let nuri = "did:ng:"+get(cur_tab).doc.nuri+":"+get(cur_tab).store.overlay;
let title = undefined;
let about = undefined;
if ( get(cur_tab).doc.title != title_ ) {
title = title_;
}
if ( get(cur_tab).doc.description != about_ ) {
about = about_;
}
if (title === undefined && about === undefined) {
//console.log("identical");
return;
}
try {
await ng.update_header(session.session_id, nuri, title, about);
}
catch (e) {
toast_error(display_error(e));
}
}
export const live_discrete_update = async (update, crdt, heads) => { export const live_discrete_update = async (update, crdt, heads) => {
// send directly to verifier with AppRequest Update // send directly to verifier with AppRequest Update
let session = get(active_session); let session = get(active_session);
@ -464,6 +503,7 @@ export const sparql_update = async function(sparql:string) {
} }
export const branch_subscribe = function(nuri:string, in_tab:boolean) { export const branch_subscribe = function(nuri:string, in_tab:boolean) {
//console.log("branch_subscribe", nuri) //console.log("branch_subscribe", nuri)
// const { subscribe, set, update } = writable([]); // create the underlying writable store // const { subscribe, set, update } = writable([]); // create the underlying writable store
@ -492,12 +532,14 @@ export const branch_subscribe = function(nuri:string, in_tab:boolean) {
// // update, // // update,
// }; // };
open_branch(nuri, in_tab);
return { return {
load: async () => { load: async () => {
//console.log("load upper"); //console.log("load upper");
await save();
open_branch(nuri, in_tab);
let already_subscribed = all_branches[nuri]; let already_subscribed = all_branches[nuri];
if (!already_subscribed) return; if (!already_subscribed) return;
if (already_subscribed.load) { if (already_subscribed.load) {
@ -563,15 +605,21 @@ export const branch_subscribe = function(nuri:string, in_tab:boolean) {
if (response.V0.TabInfo.doc?.nuri) { if (response.V0.TabInfo.doc?.nuri) {
$cur_tab.doc.nuri = response.V0.TabInfo.doc.nuri; $cur_tab.doc.nuri = response.V0.TabInfo.doc.nuri;
} }
if (response.V0.TabInfo.doc?.can_edit) { if (typeof response.V0.TabInfo.doc?.can_edit === "boolean" ) {
$cur_tab.doc.can_edit = response.V0.TabInfo.doc.can_edit; $cur_tab.doc.can_edit = response.V0.TabInfo.doc.can_edit;
} }
if (response.V0.TabInfo.doc?.is_store) { if (typeof response.V0.TabInfo.doc?.is_store === "boolean") {
$cur_tab.doc.is_store = response.V0.TabInfo.doc.is_store; $cur_tab.doc.is_store = response.V0.TabInfo.doc.is_store;
} }
if (response.V0.TabInfo.doc?.is_member) { if (response.V0.TabInfo.doc?.is_member) {
$cur_tab.doc.is_member = response.V0.TabInfo.doc.is_member; $cur_tab.doc.is_member = response.V0.TabInfo.doc.is_member;
} }
if (response.V0.TabInfo.doc?.title !== undefined && response.V0.TabInfo.doc?.title !== null) {
$cur_tab.doc.title = response.V0.TabInfo.doc.title;
}
if (response.V0.TabInfo.doc?.description !== undefined && response.V0.TabInfo.doc?.description !== null) {
$cur_tab.doc.description = response.V0.TabInfo.doc.description;
}
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;
} }
@ -638,13 +686,17 @@ export const branch_subscribe = function(nuri:string, in_tab:boolean) {
onUpdate(response.V0.Patch.discrete); onUpdate(response.V0.Patch.discrete);
} }
if (response.V0.Patch.graph) { if (response.V0.Patch.graph) {
//console.log(response.V0.Patch.graph)
let duplicates = []; let duplicates = [];
for (let i = 0; i < old.graph.length; i++) { for (let i = 0; i < old.graph.length; i++) {
if (response.V0.Patch.graph.inserts.includes(old.graph[i])) { if (response.V0.Patch.graph.inserts.includes(old.graph[i])) {
duplicates.push(old.graph[i]) duplicates.push(old.graph[i])
} else } else {
if (response.V0.Patch.graph.removes.includes(old.graph[i])) {//TODO: optimization: remove this triple from the removes list. //console.log("remove?", i, old.graph[i], JSON.stringify(old.graph))
old.graph.splice(i, 1); if (response.V0.Patch.graph.removes.includes(old.graph[i])) {//TODO: optimization: remove this triple from the removes list.
old.graph.splice(i, 1);
//console.log("yes",JSON.stringify(old.graph))
}
} }
} }
for (const insert of response.V0.Patch.graph.inserts){ for (const insert of response.V0.Patch.graph.inserts){
@ -696,7 +748,10 @@ export const branch_subscribe = function(nuri:string, in_tab:boolean) {
}); });
} else { } else {
console.error(e); console.error(e);
// TODO: display persistent_error persistent_error(nuri, {
title: get(format)("errors.an_error_occurred"),
desc: display_error(e)
});
} }
} }
// this is in case decrease has been called before the load function returned. // this is in case decrease has been called before the load function returned.

@ -220,13 +220,17 @@ td.hljs {
.container3 { .container3 {
margin: 0; margin: 0;
min-width: 280px;
display: flex; display: flex;
flex-direction: column; flex-direction: column;
justify-content: center; justify-content: center;
text-align: center; text-align: center;
} }
.container3 aside {
width: 20rem !important;
}
div[role="alert"] div { div[role="alert"] div {
display: block; display: block;
} }

@ -208,11 +208,6 @@ export const show_doc_popup = writable(false);
export const cur_doc_popup = writable(""); export const cur_doc_popup = writable("");
export const show_modal_create = writable(false); export const show_modal_create = writable(false);
export const open_doc_popup = (popup_name) => {
cur_doc_popup.set(popup_name);
show_doc_popup.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("");
@ -335,9 +330,11 @@ export const save = async () => {
nav_bar.update((o) => { if (o.save === true) o.save = false; return o; }); nav_bar.update((o) => { if (o.save === true) o.save = false; return o; });
if (in_memory_save.length > 0) { if (in_memory_save.length > 0) {
await in_memory_save_callback(in_memory_save); let temp = in_memory_save;
in_memory_save = [];
await in_memory_save_callback(temp);
} }
in_memory_save = [];
} }
export const set_header_in_view = function(val) { export const set_header_in_view = function(val) {
@ -349,7 +346,7 @@ export const cur_branch = writable("");
export const cur_tab = derived([cur_branch, all_tabs], ([cb, all]) => {return 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) => { export const cur_tab_branch_nuri = derived(cur_tab, ($cur_tab) => {
return $cur_tab.branch.nuri; return $cur_tab.branch.nuri;
@ -469,7 +466,8 @@ export const cur_tab_update = function( fn ) {
export const live_editing = writable(false); export const live_editing = writable(false);
export const showMenu = () => { export const showMenu = async () => {
await save();
show_modal_menu.set(true); show_modal_menu.set(true);
cur_tab_update(ct => { cur_tab_update(ct => {
ct.show_menu = true; ct.show_menu = true;

@ -1 +1 @@
console.log("workertest ok"); ;

@ -210,16 +210,16 @@ export const official_apps = {
"ng:g": "n:g:z:ontology_editor", "ng:g": "n:g:z:ontology_editor",
"ng:b": "JsonLdEditor", "ng:b": "JsonLdEditor",
"ng:o": [], "ng:o": [],
"ng:w": ["schema:*"], "ng:w": ["schema*"],
}, },
"n:g:z:owl_viewer": { "n:g:z:ontology_viewer": {
"ng:n": "OWL Ontology", "ng:n": "Ontology",
"ng:a": "View the OWL Ontology", "ng:a": "View the OWL Ontology",
"ng:c": "app", "ng:c": "app",
"ng:u": "ontology_viewer",//favicon. can be a did:ng:j "ng:u": "ontology_viewer",//favicon. can be a did:ng:j
"ng:g": "n:g:z:owl_viewer", "ng:g": "n:g:z:ontology_viewer",
"ng:b": "OwlViewer", // display with https://github.com/VisualDataWeb/WebVOWL "ng:b": "OntologyViewer", // display with https://github.com/VisualDataWeb/WebVOWL
"ng:o": ["schema:owl"], "ng:o": ["schema*"],
"ng:w": [], "ng:w": [],
}, },
"n:g:z:sparql:invoke": { // displayed with highlight.js https://github.com/highlightjs/highlightjs-turtle/tree/master "n:g:z:sparql:invoke": { // displayed with highlight.js https://github.com/highlightjs/highlightjs-turtle/tree/master
@ -313,7 +313,7 @@ export const official_apps = {
"ng:u": "source",//favicon. can be a did:ng:j "ng:u": "source",//favicon. can be a did:ng:j
"ng:g": "n:g:z:crdt_source_viewer:xml", "ng:g": "n:g:z:crdt_source_viewer:xml",
"ng:b": "XmlSource", // displayed with highlight.js , with option to download "ng:b": "XmlSource", // displayed with highlight.js , with option to download
"ng:o": ["post:rich","post:md","post:html","page","data:xml", "doc:diagram:drawio"], "ng:o": ["post:rich","post:md","post:html","page","data:xml", "diagram:drawio"],
"ng:w": [], "ng:w": [],
implemented: true, implemented: true,
}, },
@ -335,7 +335,7 @@ export const official_apps = {
"ng:u": "source",//favicon. can be a did:ng:j "ng:u": "source",//favicon. can be a did:ng:j
"ng:g": "n:g:z:crdt_source_viewer:json", "ng:g": "n:g:z:crdt_source_viewer:json",
"ng:b": "AutomergeJsonSource", // displayed with highlight.js , with option to download "ng:b": "AutomergeJsonSource", // displayed with highlight.js , with option to download
"ng:o": ["data:json", "data:table", "doc:diagram:jsmind", "doc:diagram:gantt", "doc:diagram:excalidraw", "doc:viz:*", "doc:chart:*", "prod:cad"], "ng:o": ["data:json", "data:table", "diagram:jsmind", "diagram:gantt", "diagram:excalidraw", "viz:*", "chart:*", "prod:cad"],
"ng:w": [], "ng:w": [],
"full_width": true, "full_width": true,
implemented: true, implemented: true,
@ -369,8 +369,8 @@ export const official_apps = {
"ng:u": "source",//favicon. can be a did:ng:j "ng:u": "source",//favicon. can be a did:ng:j
"ng:g": "n:g:z:crdt_source_viewer:text", "ng:g": "n:g:z:crdt_source_viewer:text",
"ng:b": "TextViewer", // displayed with highlight.js , with option to download and copy paste "ng:b": "TextViewer", // displayed with highlight.js , with option to download and copy paste
"ng:o": ["post:asciidoc", "service*", "contract", "query:sparql*","query:graphql","doc:diagram:mermaid","doc:diagram:graphviz","doc:diagram:flowchart", "ng:o": ["post:asciidoc", "service*", "contract", "query:sparql*","query:graphql","diagram:mermaid","diagram:graphviz","diagram:flowchart",
"doc:diagram:sequence","doc:diagram:markmap","doc:diagram:mymind","doc:music*", "doc:maths", "doc:chemistry", "doc:ancientscript", "doc:braille", "media:subtitle"], "diagram:sequence","diagram:markmap","diagram:mymind","doc:music*", "doc:maths", "doc:chemistry", "doc:ancientscript", "doc:braille", "media:subtitle"],
"ng:w": [], "ng:w": [],
implemented: true, implemented: true,
}, },
@ -454,7 +454,7 @@ export const official_apps = {
"ng:u": "pad",//favicon. can be a did:ng:j "ng:u": "pad",//favicon. can be a did:ng:j
"ng:g": "n:g:z:pad", "ng:g": "n:g:z:pad",
"ng:b": "Pad", "ng:b": "Pad",
"ng:o": ["plato/pad"], "ng:o": ["plato:pad"],
"ng:w": [], "ng:w": [],
}, },
"n:g:z:card": { "n:g:z:card": {
@ -464,7 +464,7 @@ export const official_apps = {
"ng:u": "card",//favicon. can be a did:ng:j "ng:u": "card",//favicon. can be a did:ng:j
"ng:g": "n:g:z:card", "ng:g": "n:g:z:card",
"ng:b": "Card", "ng:b": "Card",
"ng:o": ["plato/card"], "ng:o": ["plato:card"],
"ng:w": [], "ng:w": [],
}, },
"n:g:z:gallery": { "n:g:z:gallery": {
@ -673,7 +673,7 @@ export const official_services = {
"ng:c": "service", "ng:c": "service",
"ng:u": "data",// favicon. can be a did:ng:j "ng:u": "data",// favicon. can be a did:ng:j
"ng:g": "n:g:z:dump_json", "ng:g": "n:g:z:dump_json",
"ng:o": ["data:json", "data:map", "data:array", "data:table", "doc:diagram:jsmind", "doc:diagram:gantt", "doc:diagram:excalidraw", "doc:viz:*", "doc:chart:*", "prod:cad"], "ng:o": ["data:json", "data:map", "data:array", "data:table", "diagram:jsmind", "diagram:gantt", "diagram:excalidraw", "viz:*", "chart:*", "prod:cad"],
"ng:w": [], "ng:w": [],
"ng:result": ["file:iana:application:json"], "ng:result": ["file:iana:application:json"],
}, },
@ -683,7 +683,7 @@ export const official_services = {
"ng:c": "service", "ng:c": "service",
"ng:u": "data",// favicon. can be a did:ng:j "ng:u": "data",// favicon. can be a did:ng:j
"ng:g": "n:g:z:dump_xml", "ng:g": "n:g:z:dump_xml",
"ng:o": ["post:rich","post:md","post:html","page","data:xml", "doc:diagram:drawio"], "ng:o": ["post:rich","post:md","post:html","page","data:xml", "diagram:drawio"],
"ng:w": [], "ng:w": [],
"ng:result": ["file:iana:text:xml"], "ng:result": ["file:iana:text:xml"],
}, },
@ -693,8 +693,8 @@ export const official_services = {
"ng:c": "service", "ng:c": "service",
"ng:u": "dump",// favicon. can be a did:ng:j "ng:u": "dump",// favicon. can be a did:ng:j
"ng:g": "n:g:z:dump_text", "ng:g": "n:g:z:dump_text",
"ng:o": ["post:text", "post:asciidoc", "code*", "service*", "contract", "query:sparql*","query:graphql","doc:diagram:mermaid","doc:diagram:graphviz","doc:diagram:flowchart", "ng:o": ["post:text", "post:asciidoc", "code*", "service*", "contract", "query:sparql*","query:graphql","diagram:mermaid","diagram:graphviz","diagram:flowchart",
"doc:diagram:sequence","doc:diagram:markmap","doc:diagram:mymind","doc:music*", "doc:maths", "doc:chemistry", "doc:ancientscript", "doc:braille", "media:subtitle"], "diagram:sequence","diagram:markmap","diagram:mymind","doc:music*", "doc:maths", "doc:chemistry", "doc:ancientscript", "doc:braille", "media:subtitle"],
"ng:w": [], "ng:w": [],
"ng:result": ["file:iana:text:plain"], "ng:result": ["file:iana:text:plain"],
}, },

@ -1,6 +1,6 @@
[package] [package]
name = "ng-broker" name = "ng-broker"
version = "0.1.0-preview.8" version = "0.1.1-alpha"
description = "Broker library of NextGraph, a decentralized, secure and local-first web 3.0 ecosystem based on Semantic Web and CRDTs" description = "Broker library of NextGraph, a decentralized, secure and local-first web 3.0 ecosystem based on Semantic Web and CRDTs"
edition.workspace = true edition.workspace = true
license.workspace = true license.workspace = true
@ -26,11 +26,11 @@ async-trait = "0.1.64"
rust-embed= { version = "6.7.0", features=["include-exclude"] } rust-embed= { version = "6.7.0", features=["include-exclude"] }
ng-async-tungstenite = { version = "0.22.2", git = "https://git.nextgraph.org/NextGraph/async-tungstenite.git", branch = "nextgraph", features = ["async-std-runtime"] } ng-async-tungstenite = { version = "0.22.2", git = "https://git.nextgraph.org/NextGraph/async-tungstenite.git", branch = "nextgraph", features = ["async-std-runtime"] }
blake3 = "1.3.1" blake3 = "1.3.1"
ng-repo = { path = "../ng-repo", version = "0.1.0-preview.8" } ng-repo = { path = "../ng-repo", version = "0.1.1-alpha" }
ng-net = { path = "../ng-net", version = "0.1.0-preview.8" } ng-net = { path = "../ng-net", version = "0.1.1-alpha" }
ng-client-ws = { path = "../ng-client-ws", version = "0.1.0-preview.8" } ng-client-ws = { path = "../ng-client-ws", version = "0.1.1-alpha" }
ng-verifier = { path = "../ng-verifier", version = "0.1.0-preview.8" } ng-verifier = { path = "../ng-verifier", version = "0.1.1-alpha" }
ng-storage-rocksdb = { path = "../ng-storage-rocksdb", version = "0.1.0-preview.8" } ng-storage-rocksdb = { path = "../ng-storage-rocksdb", version = "0.1.1-alpha" }
[target.'cfg(target_arch = "wasm32")'.dependencies.getrandom] [target.'cfg(target_arch = "wasm32")'.dependencies.getrandom]
version = "0.2.7" version = "0.2.7"

@ -18,8 +18,8 @@ either = "1.8.1"
futures = "0.3.24" futures = "0.3.24"
async-trait = "0.1.64" async-trait = "0.1.64"
async-std = { version = "1.12.0", features = ["attributes","unstable"] } async-std = { version = "1.12.0", features = ["attributes","unstable"] }
ng-repo = { path = "../ng-repo", version = "0.1.0-preview.8" } ng-repo = { path = "../ng-repo", version = "0.1.1-alpha" }
ng-net = { path = "../ng-net", version = "0.1.0-preview.8" } ng-net = { path = "../ng-net", version = "0.1.1-alpha" }
[target.'cfg(target_arch = "wasm32")'.dependencies] [target.'cfg(target_arch = "wasm32")'.dependencies]
wasm-bindgen = "0.2" wasm-bindgen = "0.2"

@ -36,7 +36,7 @@ url = "2.4.0"
regex = "1.8.4" regex = "1.8.4"
base64-url = "2.0.0" base64-url = "2.0.0"
web-time = "0.2.0" web-time = "0.2.0"
ng-repo = { path = "../ng-repo", version = "0.1.0-preview.8" } ng-repo = { path = "../ng-repo", version = "0.1.1-alpha" }
[target.'cfg(target_arch = "wasm32")'.dependencies] [target.'cfg(target_arch = "wasm32")'.dependencies]
reqwest = { version = "0.11.18", features = ["json","native-tls-vendored"] } reqwest = { version = "0.11.18", features = ["json","native-tls-vendored"] }

@ -53,7 +53,6 @@ pub enum AppFetchContentV0 {
Get, // does not subscribe. Get, // does not subscribe.
Subscribe, Subscribe,
Update, Update,
//Invoke,
ReadQuery, ReadQuery,
WriteQuery, WriteQuery,
RdfDump, RdfDump,
@ -61,6 +60,8 @@ pub enum AppFetchContentV0 {
SignatureStatus, SignatureStatus,
SignatureRequest, SignatureRequest,
SignedSnapshotRequest, SignedSnapshotRequest,
Header,
//Invoke,
} }
impl AppFetchContentV0 { impl AppFetchContentV0 {
@ -80,7 +81,7 @@ pub enum NgAccessV0 {
#[serde(with = "serde_bytes")] #[serde(with = "serde_bytes")]
ExtRequest(Vec<u8>), ExtRequest(Vec<u8>),
Key(BlockKey), Key(BlockKey),
Inbox(Digest), Inbox(PubKey),
} }
#[derive(Clone, Debug, Serialize, Deserialize)] #[derive(Clone, Debug, Serialize, Deserialize)]
@ -261,6 +262,14 @@ impl NuriV0 {
format!("{DID_PREFIX}:o:{repo_id}:v:{overlay_id}") format!("{DID_PREFIX}:o:{repo_id}:v:{overlay_id}")
} }
pub fn branch_repo_graph_name(
branch_id: &BranchId,
repo_id: &RepoId,
overlay_id: &OverlayId,
) -> String {
format!("{DID_PREFIX}:o:{repo_id}:v:{overlay_id}:b:{branch_id}")
}
pub fn repo_skolem( pub fn repo_skolem(
repo_id: &RepoId, repo_id: &RepoId,
peer_id: &Vec<u8>, peer_id: &Vec<u8>,
@ -576,6 +585,7 @@ pub enum AppRequestCommandV0 {
Create, Create,
FileGet, // needs the Nuri of branch/doc/store AND ObjectId FileGet, // needs the Nuri of branch/doc/store AND ObjectId
FilePut, // needs the Nuri of branch/doc/store FilePut, // needs the Nuri of branch/doc/store
Header,
} }
impl AppRequestCommandV0 { impl AppRequestCommandV0 {
@ -587,6 +597,7 @@ impl AppRequestCommandV0 {
| Self::Delete | Self::Delete
| Self::UnPin | Self::UnPin
| Self::Pin | Self::Pin
| Self::Header
| Self::Fetch(_) => false, | Self::Fetch(_) => false,
} }
} }
@ -617,6 +628,12 @@ impl AppRequestCommandV0 {
pub fn new_create() -> Self { pub fn new_create() -> Self {
AppRequestCommandV0::Create AppRequestCommandV0::Create
} }
pub fn new_header() -> Self {
AppRequestCommandV0::Header
}
pub fn new_fetch_header() -> Self {
AppRequestCommandV0::Fetch(AppFetchContentV0::Header)
}
} }
#[derive(Clone, Debug, Serialize, Deserialize)] #[derive(Clone, Debug, Serialize, Deserialize)]
@ -743,10 +760,10 @@ pub enum DocQuery {
#[derive(Clone, Debug, Serialize, Deserialize)] #[derive(Clone, Debug, Serialize, Deserialize)]
pub struct GraphUpdate { pub struct GraphUpdate {
// serialization of Vec<Quad> // serialization of Vec<Triple>
#[serde(with = "serde_bytes")] #[serde(with = "serde_bytes")]
pub inserts: Vec<u8>, pub inserts: Vec<u8>,
// serialization of Vec<Quad> // serialization of Vec<Triple>
#[serde(with = "serde_bytes")] #[serde(with = "serde_bytes")]
pub removes: Vec<u8>, pub removes: Vec<u8>,
} }
@ -793,6 +810,12 @@ pub struct DocAddFile {
pub object: ObjectRef, pub object: ObjectRef,
} }
#[derive(Clone, Debug, Serialize, Deserialize)]
pub struct DocHeader {
pub title: Option<String>,
pub about: Option<String>,
}
#[derive(Clone, Debug, Serialize, Deserialize)] #[derive(Clone, Debug, Serialize, Deserialize)]
pub enum DocCreateDestination { pub enum DocCreateDestination {
Store, Store,
@ -830,12 +853,16 @@ pub enum AppRequestPayloadV0 {
Query(DocQuery), Query(DocQuery),
Update(DocUpdate), Update(DocUpdate),
AddFile(DocAddFile), AddFile(DocAddFile),
//RemoveFile
Delete(DocDelete), Delete(DocDelete),
//Invoke(InvokeArguments),
SmallFilePut(SmallFile), SmallFilePut(SmallFile),
RandomAccessFilePut(String), // content_type (iana media type) RandomAccessFilePut(String), // content_type (iana media type)
RandomAccessFilePutChunk((u32, serde_bytes::ByteBuf)), // end the upload with an empty vec RandomAccessFilePutChunk((u32, serde_bytes::ByteBuf)), // end the upload with an empty vec
Header(DocHeader),
//RemoveFile
//Invoke(InvokeArguments),
} }
#[derive(Clone, Debug, Serialize, Deserialize)] #[derive(Clone, Debug, Serialize, Deserialize)]
@ -847,6 +874,9 @@ impl AppRequestPayload {
pub fn new_sparql_query(sparql: String, base: Option<String>) -> Self { pub fn new_sparql_query(sparql: String, base: Option<String>) -> Self {
AppRequestPayload::V0(AppRequestPayloadV0::Query(DocQuery::V0 { sparql, base })) AppRequestPayload::V0(AppRequestPayloadV0::Query(DocQuery::V0 { sparql, base }))
} }
pub fn new_header(title: Option<String>, about: Option<String>) -> Self {
AppRequestPayload::V0(AppRequestPayloadV0::Header(DocHeader { title, about }))
}
pub fn new_discrete_update( pub fn new_discrete_update(
head_strings: Vec<String>, head_strings: Vec<String>,
crdt: String, crdt: String,
@ -1017,6 +1047,22 @@ pub struct AppTabDocInfo {
//TODO branches //TODO branches
} }
impl AppTabDocInfo {
pub fn new() -> Self {
AppTabDocInfo {
nuri: None,
is_store: None,
is_member: None,
title: None,
icon: None,
description: None,
authors: None,
inbox: None,
can_edit: None,
}
}
}
#[derive(Clone, Debug, Serialize, Deserialize)] #[derive(Clone, Debug, Serialize, Deserialize)]
pub struct AppTabBranchInfo { pub struct AppTabBranchInfo {
pub id: Option<String>, //+ pub id: Option<String>, //+
@ -1032,6 +1078,13 @@ pub struct AppTabInfo {
pub store: Option<AppTabStoreInfo>, pub store: Option<AppTabStoreInfo>,
} }
#[derive(Clone, Debug, Serialize, Deserialize)]
pub struct AppHeader {
pub about: Option<String>,
pub title: Option<String>,
pub class: Option<String>,
}
#[derive(Clone, Debug, Serialize, Deserialize)] #[derive(Clone, Debug, Serialize, Deserialize)]
pub enum AppResponseV0 { pub enum AppResponseV0 {
SessionStart(AppSessionStartResponse), SessionStart(AppSessionStartResponse),
@ -1057,6 +1110,7 @@ pub enum AppResponseV0 {
Error(String), Error(String),
EndOfStream, EndOfStream,
Nuri(String), Nuri(String),
Header(AppHeader),
} }
#[derive(Clone, Debug, Serialize, Deserialize)] #[derive(Clone, Debug, Serialize, Deserialize)]

@ -2975,7 +2975,7 @@ impl OpenRepo {
/// Request to pin a repo on the broker. /// Request to pin a repo on the broker.
/// ///
/// When client will disconnect, the subscriptions and publisherAdvert of the topics will be remain active on the broker. /// When client will disconnect, the subscriptions and publisherAdvert of the topics will remain active on the broker.
/// replied with a RepoOpened /// replied with a RepoOpened
#[derive(Clone, Debug, Serialize, Deserialize)] #[derive(Clone, Debug, Serialize, Deserialize)]
pub struct PinRepoV0 { pub struct PinRepoV0 {
@ -3329,7 +3329,7 @@ impl BlocksGet {
/// and we need to default to using BlocksGet instead. /// and we need to default to using BlocksGet instead.
#[derive(Clone, Debug, Serialize, Deserialize)] #[derive(Clone, Debug, Serialize, Deserialize)]
pub struct CommitGetV0 { pub struct CommitGetV0 {
/// Block IDs to request /// Commit ID to request
pub id: ObjectId, pub id: ObjectId,
/// Topic the commit is referenced from, if it is known by the requester. /// Topic the commit is referenced from, if it is known by the requester.

@ -1,6 +1,6 @@
[package] [package]
name = "ng-oxigraph" name = "ng-oxigraph"
version = "0.4.0-alpha.7-ngpreview7" version = "0.4.0-alpha.7-ngalpha"
authors = ["Tpt <thomas@pellissier-tanon.fr>", "Niko PLP <niko@nextgraph.org>"] authors = ["Tpt <thomas@pellissier-tanon.fr>", "Niko PLP <niko@nextgraph.org>"]
license = "MIT OR Apache-2.0" license = "MIT OR Apache-2.0"
readme = "README.md" readme = "README.md"
@ -46,7 +46,7 @@ quick-xml = ">=0.29, <0.32"
memchr = "2.5" memchr = "2.5"
peg = "0.8" peg = "0.8"
base64-url = "2.0.0" base64-url = "2.0.0"
ng-repo = { path = "../ng-repo", version = "0.1.0-preview.8" } ng-repo = { path = "../ng-repo", version = "0.1.1-alpha" }
[target.'cfg(all(not(target_family = "wasm"),not(docsrs)))'.dependencies] [target.'cfg(all(not(target_family = "wasm"),not(docsrs)))'.dependencies]
libc = "0.2" libc = "0.2"

@ -16,7 +16,7 @@ use crate::oxigraph::storage::numeric_encoder::{
}; };
use crate::oxigraph::storage::{MatchBy, StorageError, StorageReader}; use crate::oxigraph::storage::{MatchBy, StorageError, StorageReader};
use crate::oxigraph::store::CorruptionError; use crate::oxigraph::store::CorruptionError;
use crate::oxrdf::GraphName; use crate::oxrdf::{GraphName, NamedNodeRef};
use crate::sparopt::algebra::NamedNode; use crate::sparopt::algebra::NamedNode;
use std::cell::RefCell; use std::cell::RefCell;
@ -43,30 +43,44 @@ impl Iterator for ErrorIterator {
impl DatasetView { impl DatasetView {
pub fn new( pub fn new(
reader: StorageReader, reader: StorageReader,
dataset: &QueryDataset, query_dataset: &QueryDataset,
default_graph: &Option<String>, default_graph: &Option<String>,
) -> Self { ) -> Self {
let dataset = EncodedDatasetSpec { let dataset = EncodedDatasetSpec {
default: if dataset.has_no_default_dataset() && default_graph.is_some() { default: if query_dataset.has_no_default_dataset() && default_graph.is_some() {
Some(vec![GraphName::NamedNode(NamedNode::new_unchecked( Some(vec![GraphName::NamedNode(NamedNode::new_unchecked(
default_graph.to_owned().unwrap(), default_graph.to_owned().unwrap(),
)) ))
.as_ref() .as_ref()
.into()]) .into()])
} else { } else {
dataset query_dataset
.default_graph_graphs() .default_graph_graphs()
.map(|graphs| graphs.iter().map(|g| g.as_ref().into()).collect::<Vec<_>>()) .map(|graphs| graphs.iter().map(|g| g.as_ref().into()).collect::<Vec<_>>())
}, },
named: dataset named: query_dataset
.available_named_graphs() .available_named_graphs()
.map(|graphs| graphs.iter().map(|g| g.as_ref().into()).collect::<Vec<_>>()), .map(|graphs| graphs.iter().map(|g| g.as_ref().into()).collect::<Vec<_>>()),
}; };
Self { let res = Self {
reader, reader,
extra: RefCell::new(HashMap::default()), extra: RefCell::new(HashMap::default()),
dataset, dataset,
};
if let Some(default_graph) = default_graph {
res.encode_term(NamedNodeRef::new_unchecked(default_graph));
}
if !query_dataset.has_no_default_dataset() {
query_dataset.default_graph_graphs().map(|graphs| {
graphs.iter().for_each(|g| match g {
GraphName::NamedNode(nn) => {
let _a = res.encode_term(nn);
}
_ => {}
})
});
} }
res
} }
fn parse_graph_name(&self, graph_name: &EncodedTerm) -> Result<MatchBy, StorageError> { fn parse_graph_name(&self, graph_name: &EncodedTerm) -> Result<MatchBy, StorageError> {

@ -2185,12 +2185,14 @@ impl<'a> StorageWriter<'a> {
let value = [value]; let value = [value];
self.buffer.clear(); self.buffer.clear();
write_spog_quad(&mut self.buffer, encoded); write_spog_quad(&mut self.buffer, encoded);
let result = if self let result =
.transaction // if self
.contains_key_for_update(&self.storage.spog_cf, &self.buffer)? // .transaction
// .contains_key_for_update(&self.storage.spog_cf, &self.buffer)?
// {
// false
// } else
{ {
false
} else {
self.transaction self.transaction
.insert(&self.storage.spog_cf, &self.buffer, &value)?; .insert(&self.storage.spog_cf, &self.buffer, &value)?;

@ -405,6 +405,7 @@ impl From<NgError> for VerifierError {
NgError::BranchNotFound => VerifierError::BranchNotFound, NgError::BranchNotFound => VerifierError::BranchNotFound,
NgError::SerializationError => VerifierError::SerializationError, NgError::SerializationError => VerifierError::SerializationError,
NgError::PermissionDenied => VerifierError::PermissionDenied, NgError::PermissionDenied => VerifierError::PermissionDenied,
NgError::VerifierError(e) => e,
// NgError::JsStorageReadError // NgError::JsStorageReadError
// NgError::JsStorageWriteError(String) // NgError::JsStorageWriteError(String)
// NgError::JsStorageKeyNotFound // NgError::JsStorageKeyNotFound

@ -87,7 +87,7 @@ impl UserInfo {
} }
} }
#[derive(Debug)] #[derive(Debug, Clone)]
pub struct BranchInfo { pub struct BranchInfo {
pub id: BranchId, pub id: BranchId,
@ -641,6 +641,15 @@ impl Repo {
None None
} }
pub fn header_branch(&self) -> Option<&BranchInfo> {
for (_, branch) in self.branches.iter() {
if branch.branch_type == BranchType::Header {
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 {

@ -220,8 +220,6 @@ impl Store {
)?; )?;
let branch_read_cap = branch_commit.reference().unwrap(); let branch_read_cap = branch_commit.reference().unwrap();
//log_debug!("{:?} BRANCH COMMIT {}", branch_type, branch_commit);
// creating the AddBranch commit (on root_branch), deps to the RootBranch commit // creating the AddBranch commit (on root_branch), deps to the RootBranch commit
// author is the owner // author is the owner
@ -247,12 +245,6 @@ impl Store {
self, self,
)?; )?;
// log_debug!(
// "ADD_BRANCH {:?} BRANCH COMMIT {}",
// &branch_type,
// add_branch_commit
// );
let branch_info = BranchInfo { let branch_info = BranchInfo {
id: branch_pub_key, id: branch_pub_key,
branch_type, branch_type,
@ -369,7 +361,6 @@ impl Store {
&self, &self,
)?; )?;
//log_debug!("ROOT_BRANCH COMMIT {}", root_branch_commit);
let root_branch_readcap = root_branch_commit.reference().unwrap(); let root_branch_readcap = root_branch_commit.reference().unwrap();
let root_branch_readcap_id = root_branch_readcap.id; let root_branch_readcap_id = root_branch_readcap.id;
// adding the 2 events for the Repository and Rootbranch commits // adding the 2 events for the Repository and Rootbranch commits
@ -378,6 +369,32 @@ impl Store {
events.push((root_branch_commit, vec![])); events.push((root_branch_commit, vec![]));
// creating the header branch
let (header_add_branch_commit, header_branch_info, next_dep) = if !is_private_store {
let (header_branch_commit, header_add_branch_commit, header_branch_info) =
self.as_ref().create_branch(
BranchType::Header,
BranchCrdt::Graph(branch_crdt.as_ref().unwrap().class().clone()),
creator,
creator_priv_key,
repo_pub_key,
repository_commit_ref.clone(),
root_branch_readcap_id,
&repo_write_cap_secret,
vec![root_branch_readcap.clone()],
vec![],
)?;
let header_add_branch_readcap = header_add_branch_commit.reference().unwrap();
events_postponed.push((header_branch_commit, vec![]));
(
Some(header_add_branch_commit),
Some(header_branch_info),
header_add_branch_readcap,
)
} else {
(None, None, root_branch_readcap.clone())
};
// creating the main branch // creating the main branch
let (main_branch_commit, main_add_branch_commit, main_branch_info) = let (main_branch_commit, main_add_branch_commit, main_branch_info) =
@ -390,10 +407,9 @@ impl Store {
repository_commit_ref.clone(), repository_commit_ref.clone(),
root_branch_readcap_id, root_branch_readcap_id,
&repo_write_cap_secret, &repo_write_cap_secret,
vec![root_branch_readcap.clone()], vec![next_dep],
vec![], vec![],
)?; )?;
events_postponed.push((main_branch_commit, vec![])); events_postponed.push((main_branch_commit, vec![]));
// TODO: optional AddMember and AddPermission, that should be added as deps to the SynSignature below (and to the commits of the SignatureContent) // TODO: optional AddMember and AddPermission, that should be added as deps to the SynSignature below (and to the commits of the SignatureContent)
@ -414,7 +430,6 @@ impl Store {
vec![main_add_branch_commit.reference().unwrap()], vec![main_add_branch_commit.reference().unwrap()],
vec![], vec![],
)?; )?;
events_postponed.push((store_branch_commit, vec![])); events_postponed.push((store_branch_commit, vec![]));
// creating the overlay or user branch // creating the overlay or user branch
@ -467,7 +482,20 @@ impl Store {
// creating signature for RootBranch, AddBranch and Branch commits // creating signature for RootBranch, AddBranch and Branch commits
// signed with owner threshold signature (threshold = 0) // signed with owner threshold signature (threshold = 0)
let mut signed_commits = vec![main_branch_info.read_cap.as_ref().unwrap().id]; let mut signed_commits = if header_branch_info.is_some() {
vec![
header_branch_info
.as_ref()
.unwrap()
.read_cap
.as_ref()
.unwrap()
.id,
main_branch_info.read_cap.as_ref().unwrap().id,
]
} else {
vec![main_branch_info.read_cap.as_ref().unwrap().id]
};
if let Some((_, store_branch, oou_add_branch, oou_branch)) = &extra_branches { if let Some((_, store_branch, oou_add_branch, oou_branch)) = &extra_branches {
signed_commits.append(&mut vec![ signed_commits.append(&mut vec![
@ -563,16 +591,32 @@ impl Store {
&self, &self,
)?; )?;
let mut branches = vec![(main_branch_info.id, main_branch_info)]; let mut branches = if header_branch_info.is_some() {
vec![
(
header_branch_info.as_ref().unwrap().id,
header_branch_info.unwrap(),
),
(main_branch_info.id, main_branch_info),
]
} else {
vec![(main_branch_info.id, main_branch_info)]
};
// adding the event for the sync_sig_on_root_branch_commit // adding the event for the sync_sig_on_root_branch_commit
let mut additional_blocks = Vec::with_capacity( let mut capacity =
cert_obj_blocks.len() + sig_obj_blocks.len() + main_add_branch_commit.blocks().len(), cert_obj_blocks.len() + sig_obj_blocks.len() + main_add_branch_commit.blocks().len();
); if header_add_branch_commit.is_some() {
capacity += header_add_branch_commit.as_ref().unwrap().blocks().len()
}
let mut additional_blocks = Vec::with_capacity(capacity);
additional_blocks.extend(cert_obj_blocks.iter()); additional_blocks.extend(cert_obj_blocks.iter());
additional_blocks.extend(sig_obj_blocks.iter()); additional_blocks.extend(sig_obj_blocks.iter());
additional_blocks.extend(main_add_branch_commit.blocks().iter()); additional_blocks.extend(main_add_branch_commit.blocks().iter());
if header_add_branch_commit.is_some() {
additional_blocks.extend(header_add_branch_commit.unwrap().blocks().iter());
}
if let Some((store_add_branch, store_branch_info, oou_add_branch, oou_branch_info)) = if let Some((store_add_branch, store_branch_info, oou_add_branch, oou_branch_info)) =
extra_branches extra_branches
{ {
@ -582,7 +626,7 @@ impl Store {
branches.push((oou_branch_info.id, oou_branch_info)); branches.push((oou_branch_info.id, oou_branch_info));
} }
// creating the SyncSignature for all 3 branches with deps to the Branch commit and acks also to this commit as it is its direct causal future. // creating the SyncSignature for all (2+ optional 2) branches with deps to the Branch commit and acks also to this commit as it is its direct causal future.
for (branch_id, branch_info) in &mut branches { for (branch_id, branch_info) in &mut branches {
let sync_sig_on_branch_commit = Commit::new_with_body_acks_deps_and_save( let sync_sig_on_branch_commit = Commit::new_with_body_acks_deps_and_save(
@ -600,12 +644,10 @@ impl Store {
// adding the event for the sync_sig_on_branch_commit // adding the event for the sync_sig_on_branch_commit
let mut additional_blocks = let mut additional = Vec::with_capacity(cert_obj_blocks.len() + sig_obj_blocks.len());
Vec::with_capacity(cert_obj_blocks.len() + sig_obj_blocks.len()); additional.extend(cert_obj_blocks.iter());
additional_blocks.extend(cert_obj_blocks.iter()); additional.extend(sig_obj_blocks.iter());
additional_blocks.extend(sig_obj_blocks.iter()); events_postponed.push((sync_sig_on_branch_commit, additional));
events_postponed.push((sync_sig_on_branch_commit, additional_blocks));
branch_info.current_heads = vec![sync_sig_on_branch_commit_ref]; branch_info.current_heads = vec![sync_sig_on_branch_commit_ref];

@ -810,6 +810,17 @@ impl fmt::Display for StoreRepo {
} }
impl StoreRepo { impl StoreRepo {
pub fn from_type_and_repo(store_type: &String, repo_id_str: &String) -> Result<Self, NgError> {
let repo_id: RepoId = repo_id_str.as_str().try_into()?;
Ok(StoreRepo::V0(match store_type.as_str() {
"public" => StoreRepoV0::PublicStore(repo_id),
"protected" => StoreRepoV0::ProtectedStore(repo_id),
"private" => StoreRepoV0::PrivateStore(repo_id),
"group" => StoreRepoV0::Group(repo_id),
"dialog" | _ => unimplemented!(),
}))
}
pub fn store_type_for_app(&self) -> String { pub fn store_type_for_app(&self) -> String {
match self { match self {
Self::V0(v0) => match v0 { Self::V0(v0) => match v0 {
@ -1533,6 +1544,12 @@ impl BranchType {
_ => false, _ => false,
} }
} }
pub fn is_header(&self) -> bool {
match self {
Self::Header => true,
_ => false,
}
}
} }
impl fmt::Display for BranchType { impl fmt::Display for BranchType {
@ -1669,7 +1686,7 @@ pub enum RemoveMember {
V0(RemoveMemberV0), V0(RemoveMemberV0),
} }
/// when a signing capability is removed, a new SignerSecretKeys should be added to wallet, with the removed key set to None /// when a signing capability is removed, a new SignerCap should be committed to User branch, with the removed key set to None
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq, Eq)] #[derive(Clone, Debug, Serialize, Deserialize, PartialEq, Eq)]
pub struct SignerCap { pub struct SignerCap {
pub repo: RepoId, pub repo: RepoId,
@ -2122,10 +2139,9 @@ pub enum RemoveFile {
/// ///
/// Contains a data structure /// Contains a data structure
/// computed from the commits at the specified head. /// computed from the commits at the specified head.
/// ACKS contains the head the snapshot was made from
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq, Eq)] #[derive(Clone, Debug, Serialize, Deserialize, PartialEq, Eq)]
pub struct SnapshotV0 { pub struct SnapshotV0 {
// Branch heads the snapshot was made from, can be useful when shared outside and the commit_header_key is set to None. otherwise it is redundant to ACKS // Branch heads the snapshot was made from
pub heads: Vec<ObjectId>, pub heads: Vec<ObjectId>,
/// Reference to Object containing Snapshot data structure /// Reference to Object containing Snapshot data structure
@ -3005,7 +3021,7 @@ impl PeerId {
/// Content of EventV0 /// Content of EventV0
/// ///
/// Contains the objects of newly published Commit, its optional blocks, and optional FILES and their blocks. /// Contains the objects of newly published Commit, its optional blocks, and optional FILES and their blocks.
/// If a block is not present in the Event, its ID should be present in block_ids and the block should be put on the emitting broker beforehand with BlocksPut. /// If a block is not present in the Event, its ID should be present in file_ids and the block should be put on the emitting broker beforehand with BlocksPut.
#[derive(Clone, Debug, Serialize, Deserialize)] #[derive(Clone, Debug, Serialize, Deserialize)]
pub struct EventContentV0 { pub struct EventContentV0 {
/// Pub/sub topic /// Pub/sub topic

@ -25,10 +25,10 @@ ng.init_headless(config).then( async() => {
//let user_id = await ng.admin_create_user(config); //let user_id = await ng.admin_create_user(config);
//console.log("user created: ",user_id); //console.log("user created: ",user_id);
let user_id = "NnAJWxO-KapuWyCm7RGwO5VszZwaJARGit-i3i1mXbkA"; let user_id = "tPY8WDkgXdqJsQMXI6U5ztj_SK54djy9XtHJhKlzyGQA";
let base = "did:ng:o:8mqfhoSprneBjkAASinRk0OYvFpbiyhjMBVHKQIarDEA";
//let base;
let session = await ng.session_headless_start(user_id); let session = await ng.session_headless_start(user_id);
session_id = session.session_id; session_id = session.session_id;
console.log(session); console.log(session);
@ -36,19 +36,35 @@ ng.init_headless(config).then( async() => {
let dump = await ng.rdf_dump(session.session_id); let dump = await ng.rdf_dump(session.session_id);
console.log(dump); console.log(dump);
//let nuri = await ng.doc_create(session.session_id, "Graph", "data:graph", "protected", "RMKIXeT9RvGT5wc2uJQaRqEFjaJpC19haeaSx4iRenIA", "store");
let nuri = "did:ng:o:b70vk7Bj4eInXgG8pLysrFpEL-YSOiRYEmihPGiM1EsA:v:_0hm2qIpq443C7rMEdCGnhPDhsaWR2XruTIaF-9LKbkA";
console.log("nuri=",nuri);
let base = "did:ng:o:b70vk7Bj4eInXgG8pLysrFpEL-YSOiRYEmihPGiM1EsA";
console.log("******** SELECT") console.log("******** SELECT")
let sparql_result = await ng.sparql_query(session.session_id, "SELECT ?s ?p ?o WHERE { ?s ?p ?o }", base); let header_branch = "did:ng:o:b70vk7Bj4eInXgG8pLysrFpEL-YSOiRYEmihPGiM1EsA:v:_0hm2qIpq443C7rMEdCGnhPDhsaWR2XruTIaF-9LKbkA:b:TokczMya9WDpQ-_FYFi7QJVbHmllWS3lD-vjtzHHQa0A";
console.log(sparql_result);
for (const q of sparql_result.results.bindings) { // let sparql_result = await ng.sparql_query(session.session_id, "SELECT ?s ?p ?o WHERE { ?s ?p ?o }", base, header_branch);
console.log(q); // console.log(sparql_result);
} // for (const q of sparql_result.results.bindings) {
// console.log(q);
// }
await ng.sparql_update(session.session_id, "WITH <"+header_branch+"> \
DELETE { <> <did:ng:x:ng#n> ?n. } INSERT {<> <did:ng:x:ng#n> \"ddd6\". } WHERE {OPTIONAL { <> <did:ng:x:ng#n> ?n } }",nuri);
// let history = await ng.branch_history(session.session_id); // let history = await ng.branch_history(session.session_id);
// for (const h of history.history) { // for (const h of history.history) {
// console.log(h[0], h[1]); // console.log(h[0], h[1]);
// } // }
// console.log(history.swimlane_state); // console.log(history.swimlane_state);
sparql_result = await ng.sparql_query(session.session_id, "CONSTRUCT { ?s ?p ?o } WHERE { GRAPH <"+header_branch+"> { ?s ?p ?o } }", base);
console.log("******** CONSTRUCT")
for (const r of sparql_result) console.log(r.subject.value, r.predicate.value,r.object.value);
//await ng.sparql_update(session.session_id, "INSERT DATA { <did:ng:o:8mqfhoSprneBjkAASinRk0OYvFpbiyhjMBVHKQIarDEA> <did:ng:i> <did:ng:j> }"); //await ng.sparql_update(session.session_id, "INSERT DATA { <did:ng:o:8mqfhoSprneBjkAASinRk0OYvFpbiyhjMBVHKQIarDEA> <did:ng:i> <did:ng:j> }");
// await ng.sparql_update(session.session_id, "DELETE DATA { <did:ng:t:AJQ5gCLoXXjalC9diTDCvxxWu5ZQUcYWEE821nhVRMcE> <did:ng:i> <did:ng:j> }"); // await ng.sparql_update(session.session_id, "DELETE DATA { <did:ng:t:AJQ5gCLoXXjalC9diTDCvxxWu5ZQUcYWEE821nhVRMcE> <did:ng:i> <did:ng:j> }");
@ -65,29 +81,29 @@ ng.init_headless(config).then( async() => {
//await ng.sparql_update(session.session_id, "INSERT { _:_ <did:ng:ok> <did:ng:v> . } WHERE { _:_ <did:ng:m> <did:ng:n> } "); //await ng.sparql_update(session.session_id, "INSERT { _:_ <did:ng:ok> <did:ng:v> . } WHERE { _:_ <did:ng:m> <did:ng:n> } ");
//await ng.sparql_update(session.session_id, "INSERT DATA { _:_ <abc:a> <d:a> . _:_a <abceee:a> <d:a> . }"); //await ng.sparql_update(session.session_id, "INSERT DATA { _:_ <abc:a> <d:a> . _:_a <abceee:a> <d:a> . }");
await ng.sparql_update(session.session_id, "INSERT DATA { <> <a:selftest> <a:selftest> . }",base); //await ng.sparql_update(session.session_id, "INSERT DATA { <> <a:selftest> <a:selftest> . }",base);
//await ng.sparql_update(session.session_id, "INSERT DATA { <did:ng:TEST4> <did:ng:j> _:_ . _:_ <did:ng:m> <did:ng:n> . }"); //await ng.sparql_update(session.session_id, "INSERT DATA { <did:ng:TEST4> <did:ng:j> _:_ . _:_ <did:ng:m> <did:ng:n> . }");
//await ng.sparql_update(session.session_id, "INSERT DATA { <did:ng:TEST5> <did:ng:j> [ <did:ng:m> <did:ng:n> ]. }"); //await ng.sparql_update(session.session_id, "INSERT DATA { <did:ng:TEST5> <did:ng:j> [ <did:ng:m> <did:ng:n> ]. }");
sparql_result = await ng.sparql_query(session.session_id, "SELECT ?a WHERE { ?a <did:ng:j> _:abc. _:abc <did:ng:m> <did:ng:n> }", base); // sparql_result = await ng.sparql_query(session.session_id, "SELECT ?a WHERE { ?a <did:ng:j> _:abc. _:abc <did:ng:m> <did:ng:n> }", base);
console.log(sparql_result); // console.log(sparql_result);
for (const q of sparql_result.results.bindings) { // for (const q of sparql_result.results.bindings) {
console.log(q); // console.log(q);
} // }
sparql_result = await ng.sparql_query(session.session_id, "SELECT ?s ?a WHERE { ?s <did:ng:j> ?a }", base); // sparql_result = await ng.sparql_query(session.session_id, "SELECT ?s ?a WHERE { ?s <did:ng:j> ?a }", base);
console.log(sparql_result); // console.log(sparql_result);
for (const q of sparql_result.results.bindings) { // for (const q of sparql_result.results.bindings) {
console.log(q); // console.log(q);
} // }
console.log("******** CONSTRUCT") // console.log("******** CONSTRUCT2")
let quads = await ng.sparql_query(session.session_id, "CONSTRUCT { ?s ?p ?o } WHERE { ?s ?p ?o }",base); // let quads = await ng.sparql_query(session.session_id, "CONSTRUCT { ?s ?p ?o } WHERE { ?s ?p ?o }",base);
for (const q of quads) { // for (const q of quads) {
console.log(q.subject.toString(), q.predicate.toString(), q.object.toString(), q.graph.toString()) // console.log(q.subject.toString(), q.predicate.toString(), q.object.toString(), q.graph.toString())
} // }
// let file_nuri = await ng.file_put_to_private_store(session.session_id,"LICENSE-MIT","text/plain"); // let file_nuri = await ng.file_put_to_private_store(session.session_id,"LICENSE-MIT","text/plain");
// console.log(file_nuri); // console.log(file_nuri);

@ -399,6 +399,71 @@ pub async fn sparql_update(
} }
} }
#[wasm_bindgen]
pub async fn update_header(
session_id: JsValue,
nuri: String,
title: JsValue,
about: JsValue,
) -> Result<(), String> {
let session_id: u64 = serde_wasm_bindgen::from_value::<u64>(session_id)
.map_err(|_| "Invalid session_id".to_string())?;
let nuri = NuriV0::new_from(&nuri).map_err(|e| e.to_string())?;
let title = if title.is_string() {
Some(title.as_string().unwrap())
} else {
None
};
let about = if about.is_string() {
Some(about.as_string().unwrap())
} else {
None
};
let request = AppRequest::V0(AppRequestV0 {
command: AppRequestCommandV0::new_header(),
nuri,
payload: Some(AppRequestPayload::new_header(title, about)),
session_id,
});
let res = nextgraph::local_broker::app_request(request)
.await
.map_err(|e: NgError| e.to_string())?;
if let AppResponse::V0(AppResponseV0::Error(e)) = res {
Err(e)
} else {
Ok(())
}
}
#[wasm_bindgen]
pub async fn fetch_header(session_id: JsValue, nuri: String) -> Result<JsValue, String> {
let session_id: u64 = serde_wasm_bindgen::from_value::<u64>(session_id)
.map_err(|_| "Invalid session_id".to_string())?;
let nuri = NuriV0::new_from(&nuri).map_err(|e| e.to_string())?;
let request = AppRequest::V0(AppRequestV0 {
command: AppRequestCommandV0::new_fetch_header(),
nuri,
payload: None,
session_id,
});
let res = nextgraph::local_broker::app_request(request)
.await
.map_err(|e: NgError| e.to_string())?;
match res {
AppResponse::V0(AppResponseV0::Error(e)) => Err(e),
AppResponse::V0(AppResponseV0::Header(h)) => Ok(serde_wasm_bindgen::to_value(&h).unwrap()),
_ => Err("invalid response".to_string()),
}
}
#[cfg(not(wasmpack_target = "nodejs"))] #[cfg(not(wasmpack_target = "nodejs"))]
#[wasm_bindgen] #[wasm_bindgen]
pub async fn sparql_query( pub async fn sparql_query(
@ -1211,6 +1276,7 @@ pub async fn app_request_with_nuri_command(
Ok(serde_wasm_bindgen::to_value(&response).unwrap()) Ok(serde_wasm_bindgen::to_value(&response).unwrap())
} }
#[cfg(not(wasmpack_target = "nodejs"))]
#[wasm_bindgen] #[wasm_bindgen]
pub async fn doc_create( pub async fn doc_create(
session_id: JsValue, session_id: JsValue,
@ -1253,6 +1319,50 @@ pub async fn doc_create(
} }
} }
#[cfg(wasmpack_target = "nodejs")]
#[wasm_bindgen]
pub async fn doc_create(
session_id: JsValue,
crdt: String,
class_name: String,
store_type: String,
store_repo: String,
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 = StoreRepo::from_type_and_repo(&store_type, &store_repo)
.map_err(|_| "invalid 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,

@ -1,6 +1,6 @@
[package] [package]
name = "ng-storage-rocksdb" name = "ng-storage-rocksdb"
version = "0.1.0-preview.8" version = "0.1.1-alpha"
description = "Stores based on RocksDB for NextGraph" description = "Stores based on RocksDB for NextGraph"
edition.workspace = true edition.workspace = true
license.workspace = true license.workspace = true
@ -14,7 +14,7 @@ build = "build.rs"
[dependencies] [dependencies]
serde_bare = "0.5.0" serde_bare = "0.5.0"
ng-repo = { path = "../ng-repo", version = "0.1.0-preview.8" } ng-repo = { path = "../ng-repo", version = "0.1.1-alpha" }
[target.'cfg(all(not(target_arch = "wasm32"),not(docsrs)))'.dependencies.ng-rocksdb] [target.'cfg(all(not(target_arch = "wasm32"),not(docsrs)))'.dependencies.ng-rocksdb]
git = "https://git.nextgraph.org/NextGraph/rust-rocksdb.git" git = "https://git.nextgraph.org/NextGraph/rust-rocksdb.git"

@ -1,6 +1,6 @@
[package] [package]
name = "ng-verifier" name = "ng-verifier"
version = "0.1.0-preview.8" version = "0.1.1-alpha"
description = "Verifier library of NextGraph" description = "Verifier library of NextGraph"
edition.workspace = true edition.workspace = true
license.workspace = true license.workspace = true
@ -27,21 +27,22 @@ rand = { version = "0.7", features = ["getrandom"] }
web-time = "0.2.0" web-time = "0.2.0"
either = "1.8.1" either = "1.8.1"
futures = "0.3.24" futures = "0.3.24"
lazy_static = "1.4.0"
async-trait = "0.1.64" async-trait = "0.1.64"
async-std = { version = "1.12.0", features = [ "attributes", "unstable" ] } async-std = { version = "1.12.0", features = [ "attributes", "unstable" ] }
automerge = "0.5.11" automerge = "0.5.11"
yrs = "0.19.2" yrs = "0.19.2"
sbbf-rs-safe = "0.3.2" sbbf-rs-safe = "0.3.2"
ng-repo = { path = "../ng-repo", version = "0.1.0-preview.8" } ng-repo = { path = "../ng-repo", version = "0.1.1-alpha" }
ng-net = { path = "../ng-net", version = "0.1.0-preview.8" } ng-net = { path = "../ng-net", version = "0.1.1-alpha" }
ng-oxigraph = { path = "../ng-oxigraph", version = "0.4.0-alpha.7-ngpreview7" } ng-oxigraph = { path = "../ng-oxigraph", version = "0.4.0-alpha.7-ngalpha" }
[target.'cfg(target_family = "wasm")'.dependencies] [target.'cfg(target_family = "wasm")'.dependencies]
ng-oxigraph = { path = "../ng-oxigraph", version = "0.4.0-alpha.7-ngpreview7", features = ["js"] } ng-oxigraph = { path = "../ng-oxigraph", version = "0.4.0-alpha.7-ngalpha", features = ["js"] }
[target.'cfg(all(not(target_family = "wasm"),not(docsrs)))'.dependencies] [target.'cfg(all(not(target_family = "wasm"),not(docsrs)))'.dependencies]
ng-storage-rocksdb = { path = "../ng-storage-rocksdb", version = "0.1.0-preview.8" } ng-storage-rocksdb = { path = "../ng-storage-rocksdb", version = "0.1.1-alpha" }
getrandom = "0.2.7" getrandom = "0.2.7"
[dev-dependencies] [dev-dependencies]
ng-repo = { path = "../ng-repo", version = "0.1.0-preview.8", features = ["testing"] } ng-repo = { path = "../ng-repo", version = "0.1.1-alpha", features = ["testing"] }

@ -33,7 +33,7 @@ use crate::verifier::Verifier;
struct BranchUpdateInfo { struct BranchUpdateInfo {
branch_id: BranchId, branch_id: BranchId,
branch_is_main: bool, branch_type: BranchType,
repo_id: RepoId, repo_id: RepoId,
topic_id: TopicId, topic_id: TopicId,
token: Digest, token: Digest,
@ -229,7 +229,10 @@ impl Verifier {
(BranchCrdt::YMap(_), DiscreteTransaction::YMap(v)) => DiscretePatch::YMap(v), (BranchCrdt::YMap(_), DiscreteTransaction::YMap(v)) => DiscretePatch::YMap(v),
(BranchCrdt::YText(_), DiscreteTransaction::YText(v)) => DiscretePatch::YText(v), (BranchCrdt::YText(_), DiscreteTransaction::YText(v)) => DiscretePatch::YText(v),
(BranchCrdt::YXml(_), DiscreteTransaction::YXml(v)) => DiscretePatch::YXml(v), (BranchCrdt::YXml(_), DiscreteTransaction::YXml(v)) => DiscretePatch::YXml(v),
_ => return Err(VerifierError::InvalidCommit), _ => {
//log_debug!("{:?} {:?}", crdt, patch);
return Err(VerifierError::InvalidCommit);
}
}; };
self.push_app_response( self.push_app_response(
branch_id, branch_id,
@ -265,7 +268,7 @@ impl Verifier {
if body.graph.is_some() { if body.graph.is_some() {
let info = BranchUpdateInfo { let info = BranchUpdateInfo {
branch_id: *branch_id, branch_id: *branch_id,
branch_is_main: branch.branch_type.is_main(), branch_type: branch.branch_type.clone(),
repo_id: *repo_id, repo_id: *repo_id,
topic_id: branch.topic.clone().unwrap(), topic_id: branch.topic.clone().unwrap(),
token: branch.read_cap.as_ref().unwrap().tokenize(), token: branch.read_cap.as_ref().unwrap().tokenize(),
@ -327,7 +330,10 @@ impl Verifier {
fn find_branch_and_repo_for_quad( fn find_branch_and_repo_for_quad(
&self, &self,
quad: &Quad, quad: &Quad,
branches: &mut HashMap<BranchId, (StoreRepo, RepoId, bool, TopicId, Digest, OverlayId)>, branches: &mut HashMap<
BranchId,
(StoreRepo, RepoId, BranchType, TopicId, Digest, OverlayId),
>,
nuri_branches: &mut HashMap<String, (RepoId, BranchId, bool)>, nuri_branches: &mut HashMap<String, (RepoId, BranchId, bool)>,
) -> Result<(RepoId, BranchId, bool), VerifierError> { ) -> Result<(RepoId, BranchId, bool), VerifierError> {
match &quad.graph_name { match &quad.graph_name {
@ -345,13 +351,13 @@ impl Verifier {
nuri.overlay.unwrap().outer().to_slice(), nuri.overlay.unwrap().outer().to_slice(),
))?; ))?;
let repo = self.get_repo(nuri.target.repo_id(), store.get_store_repo())?; let repo = self.get_repo(nuri.target.repo_id(), store.get_store_repo())?;
let (branch_id, is_publisher, is_main, topic_id, token) = match nuri.branch { let (branch_id, is_publisher, branch_type, topic_id, token) = match nuri.branch {
None => { None => {
let b = repo.main_branch().ok_or(VerifierError::BranchNotFound)?; let b = repo.main_branch().ok_or(VerifierError::BranchNotFound)?;
( (
b.id, b.id,
b.topic_priv_key.is_some(), b.topic_priv_key.is_some(),
true, b.branch_type.clone(),
b.topic.clone().unwrap(), b.topic.clone().unwrap(),
b.read_cap.as_ref().unwrap().tokenize(), b.read_cap.as_ref().unwrap().tokenize(),
) )
@ -362,7 +368,7 @@ impl Verifier {
( (
id, id,
b.topic_priv_key.is_some(), b.topic_priv_key.is_some(),
false, b.branch_type.clone(),
b.topic.clone().unwrap(), b.topic.clone().unwrap(),
b.read_cap.as_ref().unwrap().tokenize(), b.read_cap.as_ref().unwrap().tokenize(),
) )
@ -373,7 +379,7 @@ impl Verifier {
let _ = branches.entry(branch_id).or_insert(( let _ = branches.entry(branch_id).or_insert((
store.get_store_repo().clone(), store.get_store_repo().clone(),
repo.id, repo.id,
is_main, branch_type,
topic_id, topic_id,
token, token,
store.overlay_id, store.overlay_id,
@ -389,7 +395,7 @@ impl Verifier {
} }
} }
async fn prepare_sparql_update( pub(crate) async fn prepare_sparql_update(
&mut self, &mut self,
inserts: Vec<Quad>, inserts: Vec<Quad>,
removes: Vec<Quad>, removes: Vec<Quad>,
@ -402,8 +408,10 @@ impl Verifier {
// for now we just do skip, without giving option to user // for now we just do skip, without giving option to user
let mut inserts_map: HashMap<BranchId, HashSet<Triple>> = HashMap::with_capacity(1); let mut inserts_map: HashMap<BranchId, HashSet<Triple>> = HashMap::with_capacity(1);
let mut removes_map: HashMap<BranchId, HashSet<Triple>> = HashMap::with_capacity(1); let mut removes_map: HashMap<BranchId, HashSet<Triple>> = HashMap::with_capacity(1);
let mut branches: HashMap<BranchId, (StoreRepo, RepoId, bool, TopicId, Digest, OverlayId)> = let mut branches: HashMap<
HashMap::with_capacity(1); BranchId,
(StoreRepo, RepoId, BranchType, TopicId, Digest, OverlayId),
> = HashMap::with_capacity(1);
let mut nuri_branches: HashMap<String, (RepoId, BranchId, bool)> = let mut nuri_branches: HashMap<String, (RepoId, BranchId, bool)> =
HashMap::with_capacity(1); HashMap::with_capacity(1);
let mut inserts_len = inserts.len(); let mut inserts_len = inserts.len();
@ -459,8 +467,7 @@ impl Verifier {
let mut updates = Vec::with_capacity(branches.len()); let mut updates = Vec::with_capacity(branches.len());
for (branch_id, (store_repo, repo_id, branch_is_main, topic_id, token, overlay_id)) in for (branch_id, (store_repo, repo_id, branch_type, topic_id, token, overlay_id)) in branches
branches
{ {
let graph_transac = GraphTransaction { let graph_transac = GraphTransaction {
inserts: Vec::from_iter(inserts_map.remove(&branch_id).unwrap_or(HashSet::new())), inserts: Vec::from_iter(inserts_map.remove(&branch_id).unwrap_or(HashSet::new())),
@ -494,7 +501,7 @@ impl Verifier {
let info = BranchUpdateInfo { let info = BranchUpdateInfo {
branch_id, branch_id,
branch_is_main, branch_type,
repo_id, repo_id,
topic_id, topic_id,
token, token,
@ -523,13 +530,15 @@ impl Verifier {
let reader = transaction.ng_get_reader(); let reader = transaction.ng_get_reader();
for update in updates_ref.iter_mut() { for update in updates_ref.iter_mut() {
let branch_is_main = update.branch_type.is_main();
let commit_name = let commit_name =
NuriV0::commit_graph_name(&update.commit_id, &update.overlay_id); NuriV0::commit_graph_name(&update.commit_id, &update.overlay_id);
let commit_encoded = numeric_encoder::StrHash::new(&commit_name); let commit_encoded = numeric_encoder::StrHash::new(&commit_name);
let cv_graphname = NamedNode::new_unchecked(commit_name); let cv_graphname = NamedNode::new_unchecked(commit_name);
let cv_graphname_ref = GraphNameRef::NamedNode((&cv_graphname).into()); let cv_graphname_ref = GraphNameRef::NamedNode((&cv_graphname).into());
let ov_main = if update.branch_is_main { let ov_main = if branch_is_main {
let ov_graphname = NamedNode::new_unchecked(NuriV0::repo_graph_name( let ov_graphname = NamedNode::new_unchecked(NuriV0::repo_graph_name(
&update.repo_id, &update.repo_id,
&update.overlay_id, &update.overlay_id,
@ -538,7 +547,7 @@ impl Verifier {
} else { } else {
None None
}; };
let value = if update.branch_is_main { let value = if branch_is_main {
ADDED_IN_MAIN ADDED_IN_MAIN
} else { } else {
ADDED_IN_OTHER ADDED_IN_OTHER
@ -608,7 +617,7 @@ impl Verifier {
let at_current_heads = current_heads == direct_causal_past_encoded; let at_current_heads = current_heads == direct_causal_past_encoded;
// if not, we need to base ourselves on the materialized state of the direct_causal_past of the commit // if not, we need to base ourselves on the materialized state of the direct_causal_past of the commit
let value = if update.branch_is_main { let value = if branch_is_main {
REMOVED_IN_MAIN REMOVED_IN_MAIN
} else { } else {
REMOVED_IN_OTHER REMOVED_IN_OTHER
@ -675,18 +684,53 @@ impl Verifier {
.map_err(|e| VerifierError::OxigraphError(e.to_string())); .map_err(|e| VerifierError::OxigraphError(e.to_string()));
if res.is_ok() { if res.is_ok() {
for update in updates { for update in updates {
let graph_patch = update.transaction.as_patch(); if update.branch_type.is_header() {
self.push_app_response( let mut tab_doc_info = AppTabDocInfo::new();
&update.branch_id, for removed in update.transaction.removes {
AppResponse::V0(AppResponseV0::Patch(AppPatch { match removed.predicate.as_str() {
commit_id: update.commit_id.to_string(), NG_ONTOLOGY_ABOUT => tab_doc_info.description = Some("".to_string()),
commit_info: update.commit_info, NG_ONTOLOGY_TITLE => tab_doc_info.title = Some("".to_string()),
graph: Some(graph_patch), _ => {}
discrete: None, }
other: None, }
})), for inserted in update.transaction.inserts {
) match inserted.predicate.as_str() {
.await; NG_ONTOLOGY_ABOUT => {
if let Term::Literal(l) = inserted.object {
tab_doc_info.description = Some(l.value().to_string())
}
}
NG_ONTOLOGY_TITLE => {
if let Term::Literal(l) = inserted.object {
tab_doc_info.title = Some(l.value().to_string())
}
}
_ => {}
}
}
self.push_app_response(
&update.branch_id,
AppResponse::V0(AppResponseV0::TabInfo(AppTabInfo {
branch: None,
doc: Some(tab_doc_info),
store: None,
})),
)
.await;
} else {
let graph_patch = update.transaction.as_patch();
self.push_app_response(
&update.branch_id,
AppResponse::V0(AppResponseV0::Patch(AppPatch {
commit_id: update.commit_id.to_string(),
commit_info: update.commit_info,
graph: Some(graph_patch),
discrete: None,
other: None,
})),
)
.await;
}
} }
} }
res res
@ -711,7 +755,7 @@ impl Verifier {
); );
match res { match res {
Err(e) => Err(e.to_string()), Err(e) => Err(e.to_string()),
Ok((mut inserts, removes)) => { Ok((inserts, removes)) => {
if inserts.is_empty() && removes.is_empty() { if inserts.is_empty() && removes.is_empty() {
Ok(()) Ok(())
} else { } else {

@ -16,6 +16,7 @@ use futures::channel::mpsc;
use futures::SinkExt; use futures::SinkExt;
use futures::StreamExt; use futures::StreamExt;
use ng_oxigraph::oxigraph::sparql::{results::*, Query, QueryResults}; use ng_oxigraph::oxigraph::sparql::{results::*, Query, QueryResults};
use ng_oxigraph::oxrdf::{Literal, NamedNode, Quad, Term};
use ng_repo::errors::*; use ng_repo::errors::*;
use ng_repo::file::{RandomAccessFile, ReadFile}; use ng_repo::file::{RandomAccessFile, ReadFile};
@ -146,6 +147,23 @@ impl Verifier {
} }
} }
fn resolve_header_branch(
&self,
target: &NuriTargetV0,
) -> Result<(RepoId, BranchId, StoreRepo), NgError> {
Ok(match target {
NuriTargetV0::Repo(repo_id) => {
let (branch, store_repo) = {
let repo = self.repos.get(repo_id).ok_or(NgError::RepoNotFound)?;
let branch = repo.header_branch().ok_or(NgError::BranchNotFound)?;
(branch.id, repo.store.get_store_repo().clone())
};
(*repo_id, branch, store_repo)
}
_ => return Err(NgError::NotImplemented),
})
}
pub(crate) fn resolve_target_for_sparql( pub(crate) fn resolve_target_for_sparql(
&self, &self,
target: &NuriTargetV0, target: &NuriTargetV0,
@ -532,6 +550,80 @@ impl Verifier {
payload: Option<AppRequestPayload>, payload: Option<AppRequestPayload>,
) -> Result<AppResponse, NgError> { ) -> Result<AppResponse, NgError> {
match command { match command {
AppRequestCommandV0::Header => {
if let Some(AppRequestPayload::V0(AppRequestPayloadV0::Header(doc_header))) =
payload
{
let (repo_id, branch_id, store_repo) =
match self.resolve_header_branch(&nuri.target) {
Err(e) => return Ok(AppResponse::error(e.to_string())),
Ok(a) => a,
};
let graph_name = NuriV0::branch_repo_graph_name(
&branch_id,
&repo_id,
&store_repo.overlay_id_for_storage_purpose(),
);
let base = NuriV0::repo_id(&repo_id);
let mut deletes = String::new();
let mut wheres = String::new();
let mut inserts = String::new();
if let Some(about) = doc_header.about {
deletes += &format!("<> <{NG_ONTOLOGY_ABOUT}> ?a. ");
wheres += &format!("OPTIONAL {{ <> <{NG_ONTOLOGY_ABOUT}> ?a }} ");
if about.len() > 0 {
inserts += &format!(
"<> <{NG_ONTOLOGY_ABOUT}> \"{}\". ",
about.replace("\\", "\\\\").replace("\"", "\\\"")
);
}
}
if let Some(title) = doc_header.title {
deletes += &format!("<> <{NG_ONTOLOGY_TITLE}> ?n. ");
wheres += &format!("OPTIONAL {{ <> <{NG_ONTOLOGY_TITLE}> ?n }} ");
if title.len() > 0 {
inserts += &format!(
"<> <{NG_ONTOLOGY_TITLE}> \"{}\". ",
title.replace("\\", "\\\\").replace("\"", "\\\"")
);
}
}
let query = format!(
"DELETE {{ {deletes} }} INSERT {{ {inserts} }} WHERE {{ {wheres} }}"
);
let oxistore = self.graph_dataset.as_ref().unwrap();
let update = ng_oxigraph::oxigraph::sparql::Update::parse(&query, Some(&base))
.map_err(|e| NgError::InternalError)?;
let res = oxistore.ng_update(update, Some(graph_name));
return Ok(match res {
Err(e) => AppResponse::error(NgError::InternalError.to_string()),
Ok((inserts, removes)) => {
if inserts.is_empty() && removes.is_empty() {
AppResponse::ok()
} else {
match self
.prepare_sparql_update(
Vec::from_iter(inserts),
Vec::from_iter(removes),
self.get_peer_id_for_skolem(),
)
.await
{
Err(e) => AppResponse::error(e.to_string()),
Ok(_) => AppResponse::ok(),
}
}
}
});
} else {
return Err(NgError::InvalidPayload);
}
}
AppRequestCommandV0::Create => { AppRequestCommandV0::Create => {
if let Some(AppRequestPayload::V0(AppRequestPayloadV0::Create(doc_create))) = if let Some(AppRequestPayload::V0(AppRequestPayloadV0::Create(doc_create))) =
payload payload
@ -540,6 +632,7 @@ impl Verifier {
let user_id = self.user_id().clone(); let user_id = self.user_id().clone();
let user_priv_key = self.user_privkey().clone(); let user_priv_key = self.user_privkey().clone();
let primary_class = doc_create.class.class().clone();
let repo_id = self let repo_id = self
.new_repo_default( .new_repo_default(
&user_id, &user_id,
@ -549,6 +642,11 @@ impl Verifier {
) )
.await?; .await?;
let header_branch_id = {
let repo = self.get_repo(&repo_id, &doc_create.store)?;
repo.header_branch().ok_or(NgError::BranchNotFound)?.id
};
// adding an AddRepo commit to the Store branch of store. // adding an AddRepo commit to the Store branch of store.
self.send_add_repo_to_store(&repo_id, &doc_create.store) self.send_add_repo_to_store(&repo_id, &doc_create.store)
.await?; .await?;
@ -570,12 +668,73 @@ impl Verifier {
self.add_doc(&repo_id, &overlay_id)?; self.add_doc(&repo_id, &overlay_id)?;
// adding the class triple to the header branch
let header_branch_nuri = format!("{nuri_result}:b:{}", header_branch_id);
let quad = Quad {
subject: NamedNode::new_unchecked(&nuri).into(),
predicate: NG_ONTOLOGY_CLASS_NAME.clone().into(),
object: Literal::new_simple_literal(primary_class).into(),
graph_name: NamedNode::new_unchecked(&header_branch_nuri).into(),
};
let ret = self.prepare_sparql_update(vec![quad], vec![], vec![]).await;
if let Err(e) = ret {
return Ok(AppResponse::error(e.to_string()));
}
return Ok(AppResponse::V0(AppResponseV0::Nuri(nuri_result))); return Ok(AppResponse::V0(AppResponseV0::Nuri(nuri_result)));
} else { } else {
return Err(NgError::InvalidPayload); return Err(NgError::InvalidPayload);
} }
} }
AppRequestCommandV0::Fetch(fetch) => match fetch { AppRequestCommandV0::Fetch(fetch) => match fetch {
AppFetchContentV0::Header => {
let (repo_id, branch_id, store_repo) =
match self.resolve_header_branch(&nuri.target) {
Err(e) => return Ok(AppResponse::error(e.to_string())),
Ok(a) => a,
};
self.open_branch(&repo_id, &branch_id, true).await?;
let graph_name = NuriV0::branch_repo_graph_name(
&branch_id,
&repo_id,
&store_repo.overlay_id_for_storage_purpose(),
);
let base = NuriV0::repo_id(&repo_id);
let oxistore = self.graph_dataset.as_ref().unwrap();
let parsed = Query::parse(
&format!("SELECT ?class ?title ?about WHERE {{ OPTIONAL {{ <> <{NG_ONTOLOGY_CLASS}> ?class }} OPTIONAL {{ <> <{NG_ONTOLOGY_ABOUT}> ?about }} OPTIONAL {{ <> <{NG_ONTOLOGY_TITLE}> ?title }} }}"), Some(&base));
if parsed.is_err() {
return Ok(AppResponse::error(parsed.unwrap_err().to_string()));
}
let results = oxistore.query(parsed.unwrap(), Some(graph_name));
match results {
Err(e) => return Ok(AppResponse::error(e.to_string())),
Ok(QueryResults::Solutions(mut sol)) => {
let mut title = None;
let mut about = None;
let mut class = None;
if let Some(Ok(s)) = sol.next() {
if let Some(Term::Literal(l)) = s.get("title") {
title = Some(l.value().to_string());
}
if let Some(Term::Literal(l)) = s.get("about") {
about = Some(l.value().to_string());
}
if let Some(Term::Literal(l)) = s.get("class") {
class = Some(l.value().to_string());
}
}
return Ok(AppResponse::V0(AppResponseV0::Header(AppHeader {
about,
title,
class,
})));
}
_ => return Err(NgError::InvalidResponse),
};
}
AppFetchContentV0::ReadQuery => { AppFetchContentV0::ReadQuery => {
if let Some(AppRequestPayload::V0(AppRequestPayloadV0::Query(DocQuery::V0 { if let Some(AppRequestPayload::V0(AppRequestPayloadV0::Query(DocQuery::V0 {
sparql, sparql,

@ -106,7 +106,7 @@ impl SiteV0 {
let protected_store = Self::site_store_to_store_repo(&protected); let protected_store = Self::site_store_to_store_repo(&protected);
let private_store = Self::site_store_to_store_repo(&private); let private_store = Self::site_store_to_store_repo(&private);
verifier.reserve_more(33)?; verifier.reserve_more(37)?;
let mut signer_caps = Vec::with_capacity(3); let mut signer_caps = Vec::with_capacity(3);

@ -17,11 +17,24 @@ use serde::{Deserialize, Serialize};
//use oxigraph::store::Store; //use oxigraph::store::Store;
//use oxigraph::model::GroundQuad; //use oxigraph::model::GroundQuad;
//use yrs::{StateVector, Update}; //use yrs::{StateVector, Update};
use lazy_static::lazy_static;
use ng_net::{app_protocol::*, types::*}; use ng_net::{app_protocol::*, types::*};
use ng_oxigraph::oxrdf::{GraphName, GraphNameRef, NamedNode, Quad, Triple, TripleRef}; use ng_oxigraph::oxrdf::{GraphName, GraphNameRef, NamedNode, Quad, Triple, TripleRef};
use ng_repo::{errors::*, types::*}; use ng_repo::{errors::*, types::*};
pub const NG_ONTOLOGY: &str = "did:ng:x:ng#";
pub const NG_ONTOLOGY_ABOUT: &str = "did:ng:x:ng#a";
pub const NG_ONTOLOGY_TITLE: &str = "did:ng:x:ng#n";
pub const NG_ONTOLOGY_CLASS: &str = "did:ng:x:ng#c";
lazy_static! {
pub static ref NG_ONTOLOGY_ABOUT_NAME: NamedNode = NamedNode::new_unchecked(NG_ONTOLOGY_ABOUT);
pub static ref NG_ONTOLOGY_TITLE_NAME: NamedNode = NamedNode::new_unchecked(NG_ONTOLOGY_TITLE);
pub static ref NG_ONTOLOGY_CLASS_NAME: NamedNode = NamedNode::new_unchecked(NG_ONTOLOGY_CLASS);
}
#[derive(Clone, Debug, Serialize, Deserialize)] #[derive(Clone, Debug, Serialize, Deserialize)]
pub struct GraphTransaction { pub struct GraphTransaction {
pub inserts: Vec<Triple>, pub inserts: Vec<Triple>,

@ -25,6 +25,9 @@ use async_std::stream::StreamExt;
use async_std::sync::{Mutex, RwLockReadGuard}; use async_std::sync::{Mutex, RwLockReadGuard};
use futures::channel::mpsc; use futures::channel::mpsc;
use futures::SinkExt; use futures::SinkExt;
use ng_oxigraph::oxigraph::sparql::Query;
use ng_oxigraph::oxigraph::sparql::QueryResults;
use ng_oxigraph::oxrdf::Term;
use ng_repo::utils::derive_key; use ng_repo::utils::derive_key;
use sbbf_rs_safe::Filter; use sbbf_rs_safe::Filter;
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
@ -253,10 +256,11 @@ impl Verifier {
} }
fn branch_get_tab_info( fn branch_get_tab_info(
&self,
repo: &Repo, repo: &Repo,
branch: &BranchId, branch: &BranchId,
outer: String, outer: String,
) -> Result<AppTabInfo, NgError> { ) -> Result<(AppTabInfo, Option<BranchId>), NgError> {
let branch_info = repo.branch(branch)?; let branch_info = repo.branch(branch)?;
let branch_tab_info = AppTabBranchInfo { let branch_tab_info = AppTabBranchInfo {
@ -266,6 +270,40 @@ impl Verifier {
comment_branch: None, //TODO comment_branch: None, //TODO
}; };
// Retrieve Header branch info (title and about)
let header_branch_info = repo.header_branch();
let mut about = None;
let mut title = None;
if let Some(header_branch_info) = header_branch_info {
let oxistore = self.graph_dataset.as_ref().unwrap();
let header_graph = NuriV0::branch_repo_graph_name(
&header_branch_info.id,
&repo.id,
&repo.store.overlay_id,
);
let base = NuriV0::repo_id(&repo.id);
let parsed = Query::parse(&format!("SELECT ?title ?about WHERE {{ OPTIONAL {{ <> <{NG_ONTOLOGY_ABOUT}> ?about }} OPTIONAL {{ <> <{NG_ONTOLOGY_TITLE}> ?title }} }}"),
Some(&base)).map_err(|e| NgError::OxiGraphError(e.to_string()))?;
let results = oxistore
.query(parsed, Some(header_graph))
.map_err(|e| NgError::OxiGraphError(e.to_string()))?;
match results {
QueryResults::Solutions(mut sol) => {
if let Some(Ok(s)) = sol.next() {
if let Some(Term::Literal(l)) = s.get("title") {
title = Some(l.value().to_string());
}
if let Some(Term::Literal(l)) = s.get("about") {
about = Some(l.value().to_string());
}
}
}
_ => return Err(NgError::InvalidResponse),
}
}
let root_branch_info = repo.branch(&repo.id)?; let root_branch_info = repo.branch(&repo.id)?;
let doc_tab_info = AppTabDocInfo { let doc_tab_info = AppTabDocInfo {
@ -275,9 +313,9 @@ impl Verifier {
authors: None, // TODO authors: None, // TODO
inbox: None, // TODO inbox: None, // TODO
can_edit: Some(true), can_edit: Some(true),
title: None, title,
icon: None, icon: None,
description: None, description: about,
}; };
let store_tab_info = AppTabStoreInfo { let store_tab_info = AppTabStoreInfo {
@ -293,11 +331,14 @@ impl Verifier {
description: None, description: None,
}; };
Ok(AppTabInfo { Ok((
branch: Some(branch_tab_info), AppTabInfo {
doc: Some(doc_tab_info), branch: Some(branch_tab_info),
store: Some(store_tab_info), doc: Some(doc_tab_info),
}) store: Some(store_tab_info),
},
header_branch_info.map(|i| i.id),
))
} }
pub(crate) async fn create_branch_subscription( pub(crate) async fn create_branch_subscription(
@ -317,19 +358,45 @@ impl Verifier {
//return Err(VerifierError::DoubleBranchSubscription); //return Err(VerifierError::DoubleBranchSubscription);
} }
} }
let (heads, head_keys, tab_info, header_branch_id, crdt) = {
let repo = self.get_repo(&repo_id, &store_repo)?;
let branch = repo.branch(&branch_id)?;
let repo = self.get_repo(&repo_id, &store_repo)?; let heads: Vec<ObjectId> = branch.current_heads.iter().map(|h| h.id.clone()).collect();
let branch = repo.branch(&branch_id)?; let head_keys: Vec<ObjectKey> =
branch.current_heads.iter().map(|h| h.key.clone()).collect();
//let tx = self.branch_subscriptions.entry(branch).or_insert_with(|| {});
let (tab_info, header_branch_id) =
self.branch_get_tab_info(repo, &branch_id, self.outer.clone())?;
(
heads,
head_keys,
tab_info,
header_branch_id,
branch.crdt.clone(),
)
};
if let Some(header_branch_id) = header_branch_id {
if let Some(returned) = self
.branch_subscriptions
.insert(header_branch_id, tx.clone())
{
if !returned.is_closed() {
returned.close_channel();
}
}
}
//let tx = self.branch_subscriptions.entry(branch).or_insert_with(|| {});
let files = self let files = self
.user_storage .user_storage
.as_ref() .as_ref()
.unwrap() .unwrap()
.branch_get_all_files(&branch_id)?; .branch_get_all_files(&branch_id)?;
let tab_info = Self::branch_get_tab_info(repo, &branch_id, self.outer.clone())?;
// let tab_info = self.user_storage.as_ref().unwrap().branch_get_tab_info( // let tab_info = self.user_storage.as_ref().unwrap().branch_get_tab_info(
// &branch_id, // &branch_id,
// &repo_id, // &repo_id,
@ -356,7 +423,6 @@ impl Verifier {
} }
} }
let crdt = &repo.branch(&branch_id)?.crdt;
let discrete = if crdt.is_graph() { let discrete = if crdt.is_graph() {
None None
} else { } else {
@ -366,7 +432,7 @@ impl Verifier {
.unwrap() .unwrap()
.branch_get_discrete_state(&branch_id) .branch_get_discrete_state(&branch_id)
{ {
Ok(state) => Some(match repo.branch(&branch_id)?.crdt { Ok(state) => Some(match crdt {
BranchCrdt::Automerge(_) => DiscreteState::Automerge(state), BranchCrdt::Automerge(_) => DiscreteState::Automerge(state),
BranchCrdt::YArray(_) => DiscreteState::YArray(state), BranchCrdt::YArray(_) => DiscreteState::YArray(state),
BranchCrdt::YMap(_) => DiscreteState::YMap(state), BranchCrdt::YMap(_) => DiscreteState::YMap(state),
@ -380,8 +446,8 @@ impl Verifier {
}; };
let state = AppState { let state = AppState {
heads: branch.current_heads.iter().map(|h| h.id.clone()).collect(), heads,
head_keys: branch.current_heads.iter().map(|h| h.key.clone()).collect(), head_keys,
graph: if results.is_empty() { graph: if results.is_empty() {
None None
} else { } else {
@ -1415,6 +1481,7 @@ impl Verifier {
let broker_id = if as_publisher { let broker_id = if as_publisher {
if branch_info.topic_priv_key.is_none() { if branch_info.topic_priv_key.is_none() {
// we need to subscribe as publisher, but we cant // we need to subscribe as publisher, but we cant
log_debug!("no topic_priv_key");
return Err(NgError::PermissionDenied); return Err(NgError::PermissionDenied);
} }
Some(remote_broker.broker_peer_id()) Some(remote_broker.broker_peer_id())
@ -1990,8 +2057,7 @@ impl Verifier {
repo_id, repo_id,
Arc::clone(&store), Arc::clone(&store),
) )
.await .await?;
.map_err(|e| NgError::BootstrapError(e.to_string()))?;
let mut store_branch = None; let mut store_branch = None;
@ -2028,8 +2094,7 @@ impl Verifier {
repo_id, repo_id,
Arc::clone(&store), Arc::clone(&store),
) )
.await .await?;
.map_err(|e| NgError::BootstrapError(e.to_string()))?;
} }
} }

@ -1,6 +1,6 @@
[package] [package]
name = "ng-wallet" name = "ng-wallet"
version = "0.1.0-preview.8" version = "0.1.1-alpha"
description = "Wallet library of NextGraph. keeps the secret keys of all identities of the user in a safe wallet. NextGraph is a decentralized, secure and local-first web 3.0 ecosystem based on Semantic Web and CRDTs" description = "Wallet library of NextGraph. keeps the secret keys of all identities of the user in a safe wallet. NextGraph is a decentralized, secure and local-first web 3.0 ecosystem based on Semantic Web and CRDTs"
categories = ["authentication"] categories = ["authentication"]
edition.workspace = true edition.workspace = true
@ -32,10 +32,10 @@ chacha20poly1305 = "0.10.1"
#{version = "0.10.1", features = ["heapless","getrandom"] } #{version = "0.10.1", features = ["heapless","getrandom"] }
image = "0.24.6" image = "0.24.6"
web-time = "0.2.0" web-time = "0.2.0"
ng-repo = { path = "../ng-repo", version = "0.1.0-preview.8" } ng-repo = { path = "../ng-repo", version = "0.1.1-alpha" }
ng-net = { path = "../ng-net", version = "0.1.0-preview.8" } ng-net = { path = "../ng-net", version = "0.1.1-alpha" }
ng-verifier = { path = "../ng-verifier", version = "0.1.0-preview.8" } ng-verifier = { path = "../ng-verifier", version = "0.1.1-alpha" }
[dev-dependencies] [dev-dependencies]
ng-repo = { path = "../ng-repo", version = "0.1.0-preview.8", features = ["testing"] } ng-repo = { path = "../ng-repo", version = "0.1.1-alpha", features = ["testing"] }
ng-verifier = { path = "../ng-verifier", version = "0.1.0-preview.8", features = ["testing"] } ng-verifier = { path = "../ng-verifier", version = "0.1.1-alpha", features = ["testing"] }

@ -23,6 +23,6 @@ log = "0.4"
env_logger = "0.10" env_logger = "0.10"
anyhow = "1.0.71" anyhow = "1.0.71"
duration-str = "0.7.1" duration-str = "0.7.1"
ng-repo = { path = "../ng-repo", version = "0.1.0-preview.8", features = ["server_log_output"] } ng-repo = { path = "../ng-repo", version = "0.1.1-alpha", features = ["server_log_output"] }
ng-net = { path = "../ng-net", version = "0.1.0-preview.8" } ng-net = { path = "../ng-net", version = "0.1.1-alpha" }
ng-client-ws = { path = "../ng-client-ws", version = "0.1.0-preview.8" } ng-client-ws = { path = "../ng-client-ws", version = "0.1.1-alpha" }

@ -210,7 +210,7 @@
/> />
</svg> </svg>
<span <span
>Our servers are located in France, and comply with the >Our servers are located in Germany, and comply with the
GDPR and DSA regulations, to the extent that they concern us.</span GDPR and DSA regulations, to the extent that they concern us.</span
> >
</li> </li>

@ -26,7 +26,7 @@ duration-str = "0.7.1"
clap = { version = "4.3.5", features = ["env","string","cargo"] } clap = { version = "4.3.5", features = ["env","string","cargo"] }
log = "0.4" log = "0.4"
env_logger = "0.10" env_logger = "0.10"
ng-repo = { path = "../ng-repo", version = "0.1.0-preview.8", features = ["server_log_output"] } ng-repo = { path = "../ng-repo", version = "0.1.1-alpha", features = ["server_log_output"] }
ng-net = { path = "../ng-net", version = "0.1.0-preview.8" } ng-net = { path = "../ng-net", version = "0.1.1-alpha" }
ng-client-ws = { path = "../ng-client-ws", version = "0.1.0-preview.8" } ng-client-ws = { path = "../ng-client-ws", version = "0.1.1-alpha" }
ng-async-tungstenite = { version = "0.22.2", git = "https://git.nextgraph.org/NextGraph/async-tungstenite.git", branch = "nextgraph", features = ["async-std-runtime", "async-native-tls"] } ng-async-tungstenite = { version = "0.22.2", git = "https://git.nextgraph.org/NextGraph/async-tungstenite.git", branch = "nextgraph", features = ["async-std-runtime", "async-native-tls"] }

@ -420,7 +420,7 @@ async fn main_inner() -> Result<(), NgcliError> {
match matches.subcommand() { match matches.subcommand() {
Some(("get", sub_matches)) => { Some(("get", sub_matches)) => {
log_debug!("processing get command"); //log_debug!("processing get command");
let nuri = NuriV0::new_for_readcaps(sub_matches.get_one::<String>("NURI").unwrap())?; let nuri = NuriV0::new_for_readcaps(sub_matches.get_one::<String>("NURI").unwrap())?;
let overlay_id = nuri.overlay.unwrap().try_into()?; let overlay_id = nuri.overlay.unwrap().try_into()?;

@ -27,9 +27,9 @@ lazy_static = "1.4.0"
log = "0.4" log = "0.4"
env_logger = "0.10" env_logger = "0.10"
clap = { version = "4.3.21", features = ["derive","env","string"] } clap = { version = "4.3.21", features = ["derive","env","string"] }
ng-repo = { path = "../ng-repo", version = "0.1.0-preview.8", features = ["server_log_output"] } ng-repo = { path = "../ng-repo", version = "0.1.1-alpha", features = ["server_log_output"] }
ng-net = { path = "../ng-net", version = "0.1.0-preview.8" } ng-net = { path = "../ng-net", version = "0.1.1-alpha" }
ng-broker = { path = "../ng-broker", version = "0.1.0-preview.8" } ng-broker = { path = "../ng-broker", version = "0.1.1-alpha" }

Loading…
Cancel
Save