update
This commit is contained in:
parent
6405c06646
commit
626e465d8c
23 changed files with 2346 additions and 274 deletions
3
.vscode/settings.json
vendored
3
.vscode/settings.json
vendored
|
@ -1,5 +1,6 @@
|
||||||
{
|
{
|
||||||
"[prisma]": {
|
"[prisma]": {
|
||||||
"editor.defaultFormatter": "Prisma.prisma"
|
"editor.defaultFormatter": "Prisma.prisma"
|
||||||
}
|
},
|
||||||
|
"editor.formatOnSave": true
|
||||||
}
|
}
|
||||||
|
|
18
apps/calendar/meta.yml
Normal file
18
apps/calendar/meta.yml
Normal file
|
@ -0,0 +1,18 @@
|
||||||
|
name: calendar
|
||||||
|
version: 0.1.0-rc1
|
||||||
|
|
||||||
|
namespaces:
|
||||||
|
panorama.calendar:
|
||||||
|
event-start-timestamp:
|
||||||
|
description: The exact timestamp the event starts
|
||||||
|
type: DateTimeTz
|
||||||
|
|
||||||
|
event-end-timestamp:
|
||||||
|
description: The exact timestamp the event ends
|
||||||
|
type: DateTimeTz
|
||||||
|
|
||||||
|
event-location:
|
||||||
|
description:
|
||||||
|
|
||||||
|
event-location:
|
||||||
|
description:
|
|
@ -1,9 +0,0 @@
|
||||||
import { HookContext } from "../../src/api";
|
|
||||||
|
|
||||||
export default class {
|
|
||||||
constructor() {}
|
|
||||||
|
|
||||||
static registerHooks(ct: HookContext) {
|
|
||||||
ct.addSensitivePattern(/ /);
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,11 +0,0 @@
|
||||||
{
|
|
||||||
"$schema": "../../generated/spec/meta.schema.json",
|
|
||||||
"title": "Todos",
|
|
||||||
"license": "MIT",
|
|
||||||
|
|
||||||
"depends": {},
|
|
||||||
|
|
||||||
"interfaces": {
|
|
||||||
"Todos": "./Todos.js"
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,13 +0,0 @@
|
||||||
# `meta.json`
|
|
||||||
|
|
||||||
`meta.json` is the entrypoint for installing an application. You can also use
|
|
||||||
[JSON5], since it supports comments and trailing commas and a lot of nice
|
|
||||||
features.
|
|
||||||
|
|
||||||
[json5]: https://json5.org
|
|
||||||
|
|
||||||
## API Reference
|
|
||||||
|
|
||||||
This is a rendered schema for how to write `meta.json` files.
|
|
||||||
|
|
||||||
[Documentation](./generated/spec)
|
|
16
docs/src/dev/permissions.md
Normal file
16
docs/src/dev/permissions.md
Normal file
|
@ -0,0 +1,16 @@
|
||||||
|
# Permission Model
|
||||||
|
|
||||||
|
Permissions are:
|
||||||
|
|
||||||
|
- compose
|
||||||
|
- This is a read/write/create permission for nodes created by the current app.
|
||||||
|
- NOTE: Unlike most operating systems, this permission does _not_ grant the
|
||||||
|
ability to create new nodes or write to nodes not created by the current app.
|
||||||
|
See `overwrite` below for that.
|
||||||
|
- overread
|
||||||
|
- This grants the ability to query for nodes outside of ones created by the
|
||||||
|
current app.
|
||||||
|
- overwrite
|
||||||
|
- This grants the ability to write into nodes outside of ones created by the
|
||||||
|
current app.
|
||||||
|
- (is it even worth it to eventually move this to being script-dependent?)
|
42
docs/src/dev/types.md
Normal file
42
docs/src/dev/types.md
Normal file
|
@ -0,0 +1,42 @@
|
||||||
|
# Data types
|
||||||
|
|
||||||
|
close to javascript types? i guess
|
||||||
|
|
||||||
|
## Primitives
|
||||||
|
|
||||||
|
- number
|
||||||
|
- Arbitrary precision number
|
||||||
|
- End with \_u8, \_u32, \_u64 or \_f- or \_i-equivalents to _suggest_ a
|
||||||
|
particular container size
|
||||||
|
- boolean
|
||||||
|
- literally true or false
|
||||||
|
- string
|
||||||
|
|
||||||
|
## Special primitives
|
||||||
|
|
||||||
|
- DateTimeTz
|
||||||
|
- Timezone-aware date (internally stored as ISO8601)
|
||||||
|
- There is no non-timezone-aware date. Please use a string type for that
|
||||||
|
|
||||||
|
## Type constructors
|
||||||
|
|
||||||
|
- Option
|
||||||
|
- Either
|
||||||
|
- Heterogeneous list
|
||||||
|
- Heterogeneous map
|
||||||
|
- Array
|
||||||
|
- Record
|
||||||
|
- Enum
|
||||||
|
|
||||||
|
## Complex type constructors
|
||||||
|
|
||||||
|
- JSON schema
|
||||||
|
|
||||||
|
# Interfaces
|
||||||
|
|
||||||
|
Interfaces approximately match traits in rust, comprised of
|
||||||
|
|
||||||
|
- Associated types
|
||||||
|
- Functions
|
||||||
|
|
||||||
|
TODO: Generics?
|
79
package-lock.json
generated
79
package-lock.json
generated
|
@ -14,6 +14,7 @@
|
||||||
"@chakra-ui/react": "^2.7.0",
|
"@chakra-ui/react": "^2.7.0",
|
||||||
"@emotion/react": "^11.11.1",
|
"@emotion/react": "^11.11.1",
|
||||||
"@emotion/styled": "^11.11.0",
|
"@emotion/styled": "^11.11.0",
|
||||||
|
"@prisma/client": "^4.8.0",
|
||||||
"@tauri-apps/api": "^1.3.0",
|
"@tauri-apps/api": "^1.3.0",
|
||||||
"classnames": "^2.3.2",
|
"classnames": "^2.3.2",
|
||||||
"framer-motion": "^10.12.16",
|
"framer-motion": "^10.12.16",
|
||||||
|
@ -27,6 +28,7 @@
|
||||||
"@types/react": "^18.0.15",
|
"@types/react": "^18.0.15",
|
||||||
"@types/react-dom": "^18.0.6",
|
"@types/react-dom": "^18.0.6",
|
||||||
"@vitejs/plugin-react": "^3.0.0",
|
"@vitejs/plugin-react": "^3.0.0",
|
||||||
|
"prisma": "^4.8.0",
|
||||||
"sass": "^1.63.3",
|
"sass": "^1.63.3",
|
||||||
"typescript": "^4.9.5",
|
"typescript": "^4.9.5",
|
||||||
"vite": "^4.2.1"
|
"vite": "^4.2.1"
|
||||||
|
@ -1863,6 +1865,38 @@
|
||||||
"url": "https://opencollective.com/popperjs"
|
"url": "https://opencollective.com/popperjs"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/@prisma/client": {
|
||||||
|
"version": "4.8.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/@prisma/client/-/client-4.8.0.tgz",
|
||||||
|
"integrity": "sha512-Y1riB0p2W52kh3zgssP/YAhln3RjBFcJy3uwEiyjmU+TQYh6QTZDRFBo3JtBWuq2FyMOl1Rye8jxzUP+n0l5Cg==",
|
||||||
|
"hasInstallScript": true,
|
||||||
|
"dependencies": {
|
||||||
|
"@prisma/engines-version": "4.8.0-61.d6e67a83f971b175a593ccc12e15c4a757f93ffe"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">=14.17"
|
||||||
|
},
|
||||||
|
"peerDependencies": {
|
||||||
|
"prisma": "*"
|
||||||
|
},
|
||||||
|
"peerDependenciesMeta": {
|
||||||
|
"prisma": {
|
||||||
|
"optional": true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@prisma/engines": {
|
||||||
|
"version": "4.8.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/@prisma/engines/-/engines-4.8.0.tgz",
|
||||||
|
"integrity": "sha512-A1Asn2rxZMlLAj1HTyfaCv0VQrLUv034jVay05QlqZg1qiHPeA3/pGTfNMijbsMYCsGVxfWEJuaZZuNxXGMCrA==",
|
||||||
|
"devOptional": true,
|
||||||
|
"hasInstallScript": true
|
||||||
|
},
|
||||||
|
"node_modules/@prisma/engines-version": {
|
||||||
|
"version": "4.8.0-61.d6e67a83f971b175a593ccc12e15c4a757f93ffe",
|
||||||
|
"resolved": "https://registry.npmjs.org/@prisma/engines-version/-/engines-version-4.8.0-61.d6e67a83f971b175a593ccc12e15c4a757f93ffe.tgz",
|
||||||
|
"integrity": "sha512-MHSOSexomRMom8QN4t7bu87wPPD+pa+hW9+71JnVcF3DqyyO/ycCLhRL1we3EojRpZxKvuyGho2REQsMCvxcJw=="
|
||||||
|
},
|
||||||
"node_modules/@react-dnd/asap": {
|
"node_modules/@react-dnd/asap": {
|
||||||
"version": "5.0.2",
|
"version": "5.0.2",
|
||||||
"resolved": "https://registry.npmjs.org/@react-dnd/asap/-/asap-5.0.2.tgz",
|
"resolved": "https://registry.npmjs.org/@react-dnd/asap/-/asap-5.0.2.tgz",
|
||||||
|
@ -3230,6 +3264,23 @@
|
||||||
"node": "^10 || ^12 || >=14"
|
"node": "^10 || ^12 || >=14"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/prisma": {
|
||||||
|
"version": "4.8.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/prisma/-/prisma-4.8.0.tgz",
|
||||||
|
"integrity": "sha512-DWIhxvxt8f4h6MDd35mz7BJff+fu7HItW3WPDIEpCR3RzcOWyiHBbLQW5/DOgmf+pRLTjwXQob7kuTZVYUAw5w==",
|
||||||
|
"devOptional": true,
|
||||||
|
"hasInstallScript": true,
|
||||||
|
"dependencies": {
|
||||||
|
"@prisma/engines": "4.8.0"
|
||||||
|
},
|
||||||
|
"bin": {
|
||||||
|
"prisma": "build/index.js",
|
||||||
|
"prisma2": "build/index.js"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">=14.17"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/prop-types": {
|
"node_modules/prop-types": {
|
||||||
"version": "15.8.1",
|
"version": "15.8.1",
|
||||||
"resolved": "https://registry.npmjs.org/prop-types/-/prop-types-15.8.1.tgz",
|
"resolved": "https://registry.npmjs.org/prop-types/-/prop-types-15.8.1.tgz",
|
||||||
|
@ -5256,6 +5307,25 @@
|
||||||
"resolved": "https://registry.npmjs.org/@popperjs/core/-/core-2.11.8.tgz",
|
"resolved": "https://registry.npmjs.org/@popperjs/core/-/core-2.11.8.tgz",
|
||||||
"integrity": "sha512-P1st0aksCrn9sGZhp8GMYwBnQsbvAWsZAX44oXNNvLHGqAOcoVxmjZiohstwQ7SqKnbR47akdNi+uleWD8+g6A=="
|
"integrity": "sha512-P1st0aksCrn9sGZhp8GMYwBnQsbvAWsZAX44oXNNvLHGqAOcoVxmjZiohstwQ7SqKnbR47akdNi+uleWD8+g6A=="
|
||||||
},
|
},
|
||||||
|
"@prisma/client": {
|
||||||
|
"version": "4.8.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/@prisma/client/-/client-4.8.0.tgz",
|
||||||
|
"integrity": "sha512-Y1riB0p2W52kh3zgssP/YAhln3RjBFcJy3uwEiyjmU+TQYh6QTZDRFBo3JtBWuq2FyMOl1Rye8jxzUP+n0l5Cg==",
|
||||||
|
"requires": {
|
||||||
|
"@prisma/engines-version": "4.8.0-61.d6e67a83f971b175a593ccc12e15c4a757f93ffe"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"@prisma/engines": {
|
||||||
|
"version": "4.8.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/@prisma/engines/-/engines-4.8.0.tgz",
|
||||||
|
"integrity": "sha512-A1Asn2rxZMlLAj1HTyfaCv0VQrLUv034jVay05QlqZg1qiHPeA3/pGTfNMijbsMYCsGVxfWEJuaZZuNxXGMCrA==",
|
||||||
|
"devOptional": true
|
||||||
|
},
|
||||||
|
"@prisma/engines-version": {
|
||||||
|
"version": "4.8.0-61.d6e67a83f971b175a593ccc12e15c4a757f93ffe",
|
||||||
|
"resolved": "https://registry.npmjs.org/@prisma/engines-version/-/engines-version-4.8.0-61.d6e67a83f971b175a593ccc12e15c4a757f93ffe.tgz",
|
||||||
|
"integrity": "sha512-MHSOSexomRMom8QN4t7bu87wPPD+pa+hW9+71JnVcF3DqyyO/ycCLhRL1we3EojRpZxKvuyGho2REQsMCvxcJw=="
|
||||||
|
},
|
||||||
"@react-dnd/asap": {
|
"@react-dnd/asap": {
|
||||||
"version": "5.0.2",
|
"version": "5.0.2",
|
||||||
"resolved": "https://registry.npmjs.org/@react-dnd/asap/-/asap-5.0.2.tgz",
|
"resolved": "https://registry.npmjs.org/@react-dnd/asap/-/asap-5.0.2.tgz",
|
||||||
|
@ -6213,6 +6283,15 @@
|
||||||
"source-map-js": "^1.0.2"
|
"source-map-js": "^1.0.2"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"prisma": {
|
||||||
|
"version": "4.8.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/prisma/-/prisma-4.8.0.tgz",
|
||||||
|
"integrity": "sha512-DWIhxvxt8f4h6MDd35mz7BJff+fu7HItW3WPDIEpCR3RzcOWyiHBbLQW5/DOgmf+pRLTjwXQob7kuTZVYUAw5w==",
|
||||||
|
"devOptional": true,
|
||||||
|
"requires": {
|
||||||
|
"@prisma/engines": "4.8.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
"prop-types": {
|
"prop-types": {
|
||||||
"version": "15.8.1",
|
"version": "15.8.1",
|
||||||
"resolved": "https://registry.npmjs.org/prop-types/-/prop-types-15.8.1.tgz",
|
"resolved": "https://registry.npmjs.org/prop-types/-/prop-types-15.8.1.tgz",
|
||||||
|
|
|
@ -16,6 +16,7 @@
|
||||||
"@chakra-ui/react": "^2.7.0",
|
"@chakra-ui/react": "^2.7.0",
|
||||||
"@emotion/react": "^11.11.1",
|
"@emotion/react": "^11.11.1",
|
||||||
"@emotion/styled": "^11.11.0",
|
"@emotion/styled": "^11.11.0",
|
||||||
|
"@prisma/client": "^4.8.0",
|
||||||
"@tauri-apps/api": "^1.3.0",
|
"@tauri-apps/api": "^1.3.0",
|
||||||
"classnames": "^2.3.2",
|
"classnames": "^2.3.2",
|
||||||
"framer-motion": "^10.12.16",
|
"framer-motion": "^10.12.16",
|
||||||
|
@ -29,6 +30,7 @@
|
||||||
"@types/react": "^18.0.15",
|
"@types/react": "^18.0.15",
|
||||||
"@types/react-dom": "^18.0.6",
|
"@types/react-dom": "^18.0.6",
|
||||||
"@vitejs/plugin-react": "^3.0.0",
|
"@vitejs/plugin-react": "^3.0.0",
|
||||||
|
"prisma": "^4.8.0",
|
||||||
"sass": "^1.63.3",
|
"sass": "^1.63.3",
|
||||||
"typescript": "^4.9.5",
|
"typescript": "^4.9.5",
|
||||||
"vite": "^4.2.1"
|
"vite": "^4.2.1"
|
||||||
|
|
|
@ -1,2 +1,5 @@
|
||||||
[registries.crates-io]
|
[registries.crates-io]
|
||||||
protocol = "sparse"
|
protocol = "sparse"
|
||||||
|
|
||||||
|
[alias]
|
||||||
|
prisma = "run -p prisma-cli --"
|
1
src-tauri/.gitignore
vendored
1
src-tauri/.gitignore
vendored
|
@ -2,3 +2,4 @@
|
||||||
# will have compiled files and executables
|
# will have compiled files and executables
|
||||||
/target/
|
/target/
|
||||||
|
|
||||||
|
src/prisma.rs
|
2116
src-tauri/Cargo.lock
generated
2116
src-tauri/Cargo.lock
generated
File diff suppressed because it is too large
Load diff
|
@ -7,7 +7,9 @@ license = ""
|
||||||
repository = ""
|
repository = ""
|
||||||
edition = "2021"
|
edition = "2021"
|
||||||
|
|
||||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
[workspace]
|
||||||
|
members = ["prisma-cli"]
|
||||||
|
resolver = "2"
|
||||||
|
|
||||||
[build-dependencies]
|
[build-dependencies]
|
||||||
tauri-build = { version = "1.3", features = [] }
|
tauri-build = { version = "1.3", features = [] }
|
||||||
|
@ -16,11 +18,18 @@ tauri-build = { version = "1.3", features = [] }
|
||||||
tauri = { version = "1.3", features = ["shell-open"] }
|
tauri = { version = "1.3", features = ["shell-open"] }
|
||||||
serde = { version = "1.0", features = ["derive"] }
|
serde = { version = "1.0", features = ["derive"] }
|
||||||
serde_json = "1.0"
|
serde_json = "1.0"
|
||||||
sqlx = { version = "0.6.3", features = ["runtime-tokio-rustls", "sqlite"] }
|
# TODO: L @ prisma-client-rust not updating to 0.25.x of the sqlite lib
|
||||||
|
sqlx = { version = "0.5", features = ["runtime-tokio-rustls", "sqlite"] }
|
||||||
tokio = { version = "1.28.2", features = ["full"] }
|
tokio = { version = "1.28.2", features = ["full"] }
|
||||||
anyhow = "1.0.71"
|
anyhow = "1.0.71"
|
||||||
dirs = "5.0.1"
|
dirs = "5.0.1"
|
||||||
|
|
||||||
|
[dependencies.prisma-client-rust]
|
||||||
|
git = "https://github.com/Brendonovich/prisma-client-rust"
|
||||||
|
tag = "0.6.8"
|
||||||
|
default-features = false
|
||||||
|
features = ["sqlite"]
|
||||||
|
|
||||||
[features]
|
[features]
|
||||||
# this feature is used for production builds or when `devPath` points to the filesystem
|
# this feature is used for production builds or when `devPath` points to the filesystem
|
||||||
# DO NOT REMOVE!!
|
# DO NOT REMOVE!!
|
||||||
|
|
|
@ -19,6 +19,7 @@ CREATE TABLE "Graph" (
|
||||||
"label" TEXT,
|
"label" TEXT,
|
||||||
"fromId" TEXT NOT NULL,
|
"fromId" TEXT NOT NULL,
|
||||||
"toId" TEXT NOT NULL,
|
"toId" TEXT NOT NULL,
|
||||||
|
"directional" BOOLEAN NOT NULL,
|
||||||
|
|
||||||
PRIMARY KEY ("fromId", "toId"),
|
PRIMARY KEY ("fromId", "toId"),
|
||||||
CONSTRAINT "Graph_fromId_fkey" FOREIGN KEY ("fromId") REFERENCES "Node" ("id") ON DELETE RESTRICT ON UPDATE CASCADE,
|
CONSTRAINT "Graph_fromId_fkey" FOREIGN KEY ("fromId") REFERENCES "Node" ("id") ON DELETE RESTRICT ON UPDATE CASCADE,
|
||||||
|
|
10
src-tauri/prisma-cli/Cargo.toml
Normal file
10
src-tauri/prisma-cli/Cargo.toml
Normal file
|
@ -0,0 +1,10 @@
|
||||||
|
[package]
|
||||||
|
name = "prisma-cli"
|
||||||
|
version = "0.1.0"
|
||||||
|
edition = "2021"
|
||||||
|
|
||||||
|
[dependencies.prisma-client-rust-cli]
|
||||||
|
git = "https://github.com/Brendonovich/prisma-client-rust"
|
||||||
|
tag = "0.6.8"
|
||||||
|
default-features = false
|
||||||
|
features = ["sqlite"]
|
3
src-tauri/prisma-cli/src/main.rs
Normal file
3
src-tauri/prisma-cli/src/main.rs
Normal file
|
@ -0,0 +1,3 @@
|
||||||
|
fn main() {
|
||||||
|
prisma_client_rust_cli::run();
|
||||||
|
}
|
|
@ -1,6 +1,6 @@
|
||||||
generator client {
|
generator client {
|
||||||
provider = "prisma-client-js"
|
provider = "cargo prisma"
|
||||||
binaryTargets = ["native"]
|
output = "../src/prisma.rs"
|
||||||
}
|
}
|
||||||
|
|
||||||
datasource db {
|
datasource db {
|
||||||
|
@ -40,6 +40,8 @@ model Edge {
|
||||||
toId String
|
toId String
|
||||||
toNode Node @relation(name: "toNode", fields: [toId], references: [id])
|
toNode Node @relation(name: "toNode", fields: [toId], references: [id])
|
||||||
|
|
||||||
|
directional Boolean
|
||||||
|
|
||||||
@@unique([fromId, toId])
|
@@unique([fromId, toId])
|
||||||
@@index([appId, appKey])
|
@@index([appId, appKey])
|
||||||
}
|
}
|
||||||
|
@ -97,3 +99,11 @@ model Patterns {
|
||||||
|
|
||||||
functionName String
|
functionName String
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Index table, for keeping track of indexes to build and take down when the database first starts
|
||||||
|
model Indices {
|
||||||
|
id String @id @default(uuid())
|
||||||
|
command String
|
||||||
|
|
||||||
|
// TODO: Does sqlite avoid making duplicate indexes automatically?
|
||||||
|
}
|
50
src-tauri/src/apps/meta.rs
Normal file
50
src-tauri/src/apps/meta.rs
Normal file
|
@ -0,0 +1,50 @@
|
||||||
|
use std::collections::{HashMap, HashSet};
|
||||||
|
|
||||||
|
/// Metadata describing the app
|
||||||
|
#[derive(Debug, Serialize, Deserialize)]
|
||||||
|
pub struct AppMetadata {
|
||||||
|
/// The name of the app
|
||||||
|
pub name: String,
|
||||||
|
|
||||||
|
/// Version ([semantic versioning])
|
||||||
|
///
|
||||||
|
/// [semantic versioning]: https://semver.org/
|
||||||
|
#[serde(default = "default_version")]
|
||||||
|
pub version: String,
|
||||||
|
|
||||||
|
/// Namespaces requested
|
||||||
|
///
|
||||||
|
/// A namespace is an app-specific [FQN] and cannot be used by other apps
|
||||||
|
/// unless permission is explicitly granted by the user.
|
||||||
|
///
|
||||||
|
/// [FQN]: https://en.wikipedia.org/wiki/Fully_qualified_name
|
||||||
|
///
|
||||||
|
/// Namespaces are used in metadata keys. For example, a calendar app may
|
||||||
|
/// request the namespace `org.somebody.calendar`. Then, it may use the keys:
|
||||||
|
///
|
||||||
|
/// - `org.somebody.calendar / event-timestamp`
|
||||||
|
/// - `org.somebody.calendar / event-location`
|
||||||
|
///
|
||||||
|
/// Notably, the `/` is purely syntactic here; the system keeps the two parts
|
||||||
|
/// completely isolated, so there is no possible namespace "leakage" based on
|
||||||
|
/// carefully crafted keys.
|
||||||
|
pub namespaces: HashMap<String, NamespaceConfig>,
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Name-to-description mapping of keys
|
||||||
|
#[derive(Debug, Serialize, Deserialize)]
|
||||||
|
#[serde(transparent)]
|
||||||
|
pub struct NamespaceConfig(HashMap<String, KeyDescriptionConfig>);
|
||||||
|
|
||||||
|
/// Name-to-description mapping of keys
|
||||||
|
#[derive(Debug, Serialize, Deserialize)]
|
||||||
|
pub struct KeyDescriptionConfig {
|
||||||
|
pub description: String,
|
||||||
|
|
||||||
|
#[serde(rename = "type")]
|
||||||
|
pub ty: String,
|
||||||
|
}
|
||||||
|
|
||||||
|
fn default_version() -> String {
|
||||||
|
"0.0.0".to_owned()
|
||||||
|
}
|
|
@ -1,8 +1,12 @@
|
||||||
|
pub mod meta;
|
||||||
|
|
||||||
use std::{collections::HashMap, env, path::PathBuf};
|
use std::{collections::HashMap, env, path::PathBuf};
|
||||||
|
|
||||||
use anyhow::Result;
|
use anyhow::Result;
|
||||||
use sqlx::SqlitePool;
|
use sqlx::SqlitePool;
|
||||||
|
|
||||||
|
use crate::prisma::PrismaClient;
|
||||||
|
|
||||||
pub struct Handler {}
|
pub struct Handler {}
|
||||||
|
|
||||||
pub enum Event {
|
pub enum Event {
|
||||||
|
@ -12,21 +16,20 @@ pub enum Event {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct AppManager {
|
pub struct AppManager {
|
||||||
pool: SqlitePool,
|
prisma: PrismaClient,
|
||||||
apps: Vec<App>,
|
apps: Vec<App>,
|
||||||
|
|
||||||
key_handlers: HashMap<(String, Event), Handler>,
|
key_handlers: HashMap<(String, Event), Handler>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl AppManager {
|
impl AppManager {
|
||||||
pub fn new(pool: &SqlitePool) -> Self {
|
pub async fn new() -> Result<Self> {
|
||||||
let pool = pool.clone();
|
let prisma = PrismaClient::_builder().build().await?;
|
||||||
let apps = vec![];
|
let apps = vec![];
|
||||||
Self {
|
Ok(Self {
|
||||||
pool,
|
prisma,
|
||||||
apps,
|
apps,
|
||||||
key_handlers: HashMap::default(),
|
key_handlers: HashMap::default(),
|
||||||
}
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Register apps into the pool
|
/// Register apps into the pool
|
||||||
|
@ -46,6 +49,11 @@ impl AppManager {
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Figure out which indices are required by the set of known apps
|
||||||
|
pub async fn compute_indices(&self) -> Result<()> {
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct App {
|
pub struct App {
|
|
@ -6,53 +6,35 @@ extern crate serde;
|
||||||
|
|
||||||
pub mod apps;
|
pub mod apps;
|
||||||
pub mod dal;
|
pub mod dal;
|
||||||
|
pub mod prisma;
|
||||||
|
|
||||||
use anyhow::Result;
|
use anyhow::Result;
|
||||||
use apps::AppManager;
|
use prisma::PrismaClient;
|
||||||
use sqlx::{
|
|
||||||
sqlite::{SqliteConnectOptions, SqlitePoolOptions},
|
|
||||||
SqlitePool,
|
|
||||||
};
|
|
||||||
use tokio::fs;
|
|
||||||
|
|
||||||
use crate::dal::Db;
|
use crate::apps::AppManager;
|
||||||
|
|
||||||
// Learn more about Tauri commands at https://tauri.app/v1/guides/features/command
|
pub use crate::apps::meta::AppMetadata;
|
||||||
#[tauri::command]
|
|
||||||
fn greet(name: &str) -> String {
|
|
||||||
format!("Hello, {}! You've been greeted from Rust!", name)
|
|
||||||
}
|
|
||||||
|
|
||||||
#[tokio::main]
|
#[tokio::main]
|
||||||
async fn main() -> Result<()> {
|
async fn main() -> Result<()> {
|
||||||
// Open database
|
// Open database
|
||||||
let pool = open_database().await?;
|
let client = PrismaClient::_builder().build().await?;
|
||||||
|
|
||||||
// Register apps
|
// Register apps
|
||||||
let mut app_manager = AppManager::new(&pool);
|
let mut app_manager = AppManager::new().await?;
|
||||||
app_manager.register().await?;
|
app_manager.register().await?;
|
||||||
|
|
||||||
|
// Read indexes
|
||||||
|
let indexes_from_apps = app_manager.compute_indices().await?;
|
||||||
|
let indexes_from_db = client.indices().find_many(vec![]).exec().await?;
|
||||||
|
println!("indexes: {:?}", indexes_from_db);
|
||||||
|
|
||||||
tauri::Builder::default()
|
tauri::Builder::default()
|
||||||
.manage(Db(pool))
|
|
||||||
.manage(app_manager)
|
.manage(app_manager)
|
||||||
.invoke_handler(tauri::generate_handler![greet])
|
.manage(client)
|
||||||
|
.invoke_handler(tauri::generate_handler![dal::query])
|
||||||
.run(tauri::generate_context!())
|
.run(tauri::generate_context!())
|
||||||
.expect("error while running tauri application");
|
.expect("error while running tauri application");
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn open_database() -> Result<SqlitePool> {
|
|
||||||
let app_dir = dirs::data_dir().unwrap().join("panorama");
|
|
||||||
fs::create_dir_all(&app_dir).await?;
|
|
||||||
|
|
||||||
let db_path = app_dir.join("vault.sqlite");
|
|
||||||
let db_options = SqliteConnectOptions::new()
|
|
||||||
.filename(&db_path)
|
|
||||||
.create_if_missing(true);
|
|
||||||
let pool = SqlitePoolOptions::new().connect_with(db_options).await?;
|
|
||||||
println!("Running migrations...");
|
|
||||||
sqlx::migrate!().run(&pool).await?;
|
|
||||||
|
|
||||||
Ok(pool)
|
|
||||||
}
|
|
||||||
|
|
127
src/App.tsx
127
src/App.tsx
|
@ -11,9 +11,10 @@ import {
|
||||||
Image,
|
Image,
|
||||||
MenuList,
|
MenuList,
|
||||||
CloseButton,
|
CloseButton,
|
||||||
|
useColorMode,
|
||||||
} from "@chakra-ui/react";
|
} from "@chakra-ui/react";
|
||||||
import { AddIcon, ChevronDownIcon, SearchIcon } from "@chakra-ui/icons";
|
import { AddIcon, ChevronDownIcon, SearchIcon } from "@chakra-ui/icons";
|
||||||
import { Mosaic, MosaicWindow, RemoveButton } from "react-mosaic-component";
|
import { Mosaic, MosaicWindow } from "react-mosaic-component";
|
||||||
import classNames from "classnames";
|
import classNames from "classnames";
|
||||||
|
|
||||||
import "react-mosaic-component/react-mosaic-component.css";
|
import "react-mosaic-component/react-mosaic-component.css";
|
||||||
|
@ -27,76 +28,78 @@ function App() {
|
||||||
c: <div>Bottom Right Window</div>,
|
c: <div>Bottom Right Window</div>,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const { colorMode, toggleColorMode } = useColorMode();
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<ChakraProvider>
|
<main className={styles.main}>
|
||||||
<main className={styles.main}>
|
<nav className={styles.nav}>
|
||||||
<nav className={styles.nav}>
|
<h1 className={styles.title}>panorama</h1>
|
||||||
<h1 className={styles.title}>panorama</h1>
|
|
||||||
|
|
||||||
<Menu>
|
{colorMode}
|
||||||
<MenuButton as={Button} rightIcon={<ChevronDownIcon />}>
|
|
||||||
<AddIcon />
|
|
||||||
</MenuButton>
|
|
||||||
|
|
||||||
<MenuList zIndex={500}>
|
<Menu>
|
||||||
<MenuItem minH="48px">
|
<MenuButton as={Button} rightIcon={<ChevronDownIcon />}>
|
||||||
<Image
|
<AddIcon />
|
||||||
boxSize="2rem"
|
</MenuButton>
|
||||||
borderRadius="full"
|
|
||||||
src="https://placekitten.com/100/100"
|
|
||||||
alt="Fluffybuns the destroyer"
|
|
||||||
mr="12px"
|
|
||||||
/>
|
|
||||||
<span>Fluffybuns the Destroyer</span>
|
|
||||||
</MenuItem>
|
|
||||||
|
|
||||||
<MenuItem minH="40px">
|
<MenuList zIndex={500}>
|
||||||
<Image
|
<MenuItem minH="48px" onClick={toggleColorMode}>
|
||||||
boxSize="2rem"
|
<Image
|
||||||
borderRadius="full"
|
boxSize="2rem"
|
||||||
src="https://placekitten.com/120/120"
|
borderRadius="full"
|
||||||
alt="Simon the pensive"
|
src="https://placekitten.com/100/100"
|
||||||
mr="12px"
|
alt="Fluffybuns the destroyer"
|
||||||
/>
|
mr="12px"
|
||||||
<span>Simon the pensive</span>
|
/>
|
||||||
</MenuItem>
|
<span>Fluffybuns the Destroyer</span>
|
||||||
</MenuList>
|
</MenuItem>
|
||||||
</Menu>
|
|
||||||
|
|
||||||
<div className={styles.spacer} />
|
<MenuItem minH="40px">
|
||||||
|
<Image
|
||||||
|
boxSize="2rem"
|
||||||
|
borderRadius="full"
|
||||||
|
src="https://placekitten.com/120/120"
|
||||||
|
alt="Simon the pensive"
|
||||||
|
mr="12px"
|
||||||
|
/>
|
||||||
|
<span>Simon the pensive</span>
|
||||||
|
</MenuItem>
|
||||||
|
</MenuList>
|
||||||
|
</Menu>
|
||||||
|
|
||||||
<InputGroup className={styles.searchContainer}>
|
<div className={styles.spacer} />
|
||||||
<Input placeholder="Search..." />
|
|
||||||
<InputRightElement>
|
|
||||||
<SearchIcon />
|
|
||||||
</InputRightElement>
|
|
||||||
</InputGroup>
|
|
||||||
</nav>
|
|
||||||
|
|
||||||
<Mosaic<string>
|
<InputGroup className={styles.searchContainer}>
|
||||||
className={classNames(styles.container, "mosaic-blueprint-theme")}
|
<Input placeholder="Search..." />
|
||||||
renderTile={(id, path) => (
|
<InputRightElement>
|
||||||
<MosaicWindow title={id} path={path}></MosaicWindow>
|
<SearchIcon />
|
||||||
)}
|
</InputRightElement>
|
||||||
blueprintNamespace="bp3"
|
</InputGroup>
|
||||||
initialValue={{
|
</nav>
|
||||||
|
|
||||||
|
<Mosaic<string>
|
||||||
|
className={classNames(styles.container, "mosaic-blueprint-theme")}
|
||||||
|
renderTile={(id, path) => (
|
||||||
|
<MosaicWindow title={id} path={path}></MosaicWindow>
|
||||||
|
)}
|
||||||
|
blueprintNamespace="bp3"
|
||||||
|
initialValue={{
|
||||||
|
direction: "row",
|
||||||
|
first: "Journal",
|
||||||
|
second: {
|
||||||
direction: "row",
|
direction: "row",
|
||||||
first: "Journal",
|
first: {
|
||||||
second: {
|
direction: "column",
|
||||||
direction: "row",
|
first: "Calendar",
|
||||||
first: {
|
second: "Email",
|
||||||
direction: "column",
|
|
||||||
first: "Calendar",
|
|
||||||
second: "Email",
|
|
||||||
},
|
|
||||||
second: "Chat",
|
|
||||||
splitPercentage: 66.66,
|
|
||||||
},
|
},
|
||||||
splitPercentage: 25,
|
second: "Chat",
|
||||||
}}
|
splitPercentage: 66.66,
|
||||||
/>
|
},
|
||||||
</main>
|
splitPercentage: 25,
|
||||||
</ChakraProvider>
|
}}
|
||||||
|
/>
|
||||||
|
</main>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
19
src/main.tsx
19
src/main.tsx
|
@ -2,9 +2,26 @@ import React from "react";
|
||||||
import ReactDOM from "react-dom/client";
|
import ReactDOM from "react-dom/client";
|
||||||
import App from "./App";
|
import App from "./App";
|
||||||
import "./styles.css";
|
import "./styles.css";
|
||||||
|
import {
|
||||||
|
ChakraProvider,
|
||||||
|
ColorModeProvider,
|
||||||
|
ThemeConfig,
|
||||||
|
ThemeProvider,
|
||||||
|
extendBaseTheme,
|
||||||
|
extendTheme,
|
||||||
|
} from "@chakra-ui/react";
|
||||||
|
|
||||||
|
const config: ThemeConfig = {
|
||||||
|
initialColorMode: "system",
|
||||||
|
useSystemColorMode: true,
|
||||||
|
};
|
||||||
|
|
||||||
|
const theme = extendBaseTheme({ config });
|
||||||
|
|
||||||
ReactDOM.createRoot(document.getElementById("root") as HTMLElement).render(
|
ReactDOM.createRoot(document.getElementById("root") as HTMLElement).render(
|
||||||
<React.StrictMode>
|
<React.StrictMode>
|
||||||
<App />
|
<ChakraProvider theme={theme}>
|
||||||
|
<App />
|
||||||
|
</ChakraProvider>
|
||||||
</React.StrictMode>
|
</React.StrictMode>
|
||||||
);
|
);
|
||||||
|
|
|
@ -5,4 +5,6 @@ body,
|
||||||
padding: 0;
|
padding: 0;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
height: 100%;
|
height: 100%;
|
||||||
|
|
||||||
|
background-color: var(--chakra-colors-chakra-body-bg);
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue