dcos
This commit is contained in:
parent
710b783ca7
commit
397e456983
25 changed files with 3292 additions and 9401 deletions
1
.gitignore
vendored
1
.gitignore
vendored
|
@ -6,3 +6,4 @@ target
|
||||||
test.db*
|
test.db*
|
||||||
.env
|
.env
|
||||||
.direnv
|
.direnv
|
||||||
|
/proto/generated
|
4
Makefile
4
Makefile
|
@ -1,6 +1,6 @@
|
||||||
deploy-docs:
|
deploy-docs:
|
||||||
mdbook build docs
|
(cd docs; BASE_URL=/panorama bun run build) || true
|
||||||
rsync -azrP docs/book/ root@veil:/home/blogDeploy/public/panorama
|
rsync -azrP docs/dist/ root@veil:/home/blogDeploy/public/panorama
|
||||||
|
|
||||||
JOURNAL_SOURCES := $(shell find . apps/journal -name "*.rs" -not -path "./target/*")
|
JOURNAL_SOURCES := $(shell find . apps/journal -name "*.rs" -not -path "./target/*")
|
||||||
journal: $(JOURNAL_SOURCES)
|
journal: $(JOURNAL_SOURCES)
|
||||||
|
|
|
@ -1,27 +1,33 @@
|
||||||
import { defineConfig } from 'astro/config';
|
import { defineConfig } from "astro/config";
|
||||||
import starlight from '@astrojs/starlight';
|
import starlight from "@astrojs/starlight";
|
||||||
|
import rehypeKatex from "rehype-katex";
|
||||||
|
import remarkMath from "remark-math";
|
||||||
|
|
||||||
// https://astro.build/config
|
// https://astro.build/config
|
||||||
export default defineConfig({
|
export default defineConfig({
|
||||||
|
base: process.env.BASE_URL ?? "/",
|
||||||
integrations: [
|
integrations: [
|
||||||
starlight({
|
starlight({
|
||||||
title: 'My Docs',
|
title: "Panorama",
|
||||||
social: {
|
social: {
|
||||||
github: 'https://github.com/withastro/starlight',
|
github: "https://git.mzhang.io/michael/panorama",
|
||||||
},
|
},
|
||||||
sidebar: [
|
sidebar: [
|
||||||
|
{ label: "The panorama dream", link: "/dream" },
|
||||||
{
|
{
|
||||||
label: 'Guides',
|
label: "High Level Design",
|
||||||
items: [
|
autogenerate: { directory: "high-level-design" },
|
||||||
// Each item here is one entry in the navigation menu.
|
|
||||||
{ label: 'Example Guide', link: '/guides/example/' },
|
|
||||||
],
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
label: 'Reference',
|
label: "Technical Docs",
|
||||||
autogenerate: { directory: 'reference' },
|
autogenerate: { directory: "technical-docs" },
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
|
customCss: ["./node_modules/katex/dist/katex.min.css"],
|
||||||
}),
|
}),
|
||||||
],
|
],
|
||||||
|
markdown: {
|
||||||
|
remarkPlugins: [remarkMath],
|
||||||
|
rehypePlugins: [rehypeKatex],
|
||||||
|
},
|
||||||
});
|
});
|
||||||
|
|
BIN
docs/bun.lockb
Executable file
BIN
docs/bun.lockb
Executable file
Binary file not shown.
7721
docs/package-lock.json
generated
7721
docs/package-lock.json
generated
File diff suppressed because it is too large
Load diff
|
@ -10,10 +10,13 @@
|
||||||
"astro": "astro"
|
"astro": "astro"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
|
"@astrojs/check": "^0.7.0",
|
||||||
"@astrojs/starlight": "^0.24.5",
|
"@astrojs/starlight": "^0.24.5",
|
||||||
"astro": "^4.10.2",
|
"astro": "^4.10.2",
|
||||||
|
"katex": "^0.16.10",
|
||||||
|
"rehype-katex": "^7.0.0",
|
||||||
|
"remark-math": "^6.0.0",
|
||||||
"sharp": "^0.32.5",
|
"sharp": "^0.32.5",
|
||||||
"@astrojs/check": "^0.7.0",
|
|
||||||
"typescript": "^5.5.2"
|
"typescript": "^5.5.2"
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -1,5 +1,5 @@
|
||||||
import { defineCollection } from 'astro:content';
|
import { defineCollection } from "astro:content";
|
||||||
import { docsSchema } from '@astrojs/starlight/schema';
|
import { docsSchema } from "@astrojs/starlight/schema";
|
||||||
|
|
||||||
export const collections = {
|
export const collections = {
|
||||||
docs: defineCollection({ schema: docsSchema() }),
|
docs: defineCollection({ schema: docsSchema() }),
|
||||||
|
|
63
docs/src/content/docs/dream.md
Normal file
63
docs/src/content/docs/dream.md
Normal file
|
@ -0,0 +1,63 @@
|
||||||
|
---
|
||||||
|
title: The panorama dream
|
||||||
|
---
|
||||||
|
|
||||||
|
In the ideal world, you're reading this via panorama right now.
|
||||||
|
|
||||||
|
The panorama dream is to have an "everything" app that is fully managed by the user.
|
||||||
|
This page describes the vision for the app.
|
||||||
|
|
||||||
|
Almost everything on this list is something that I self host, or want to self
|
||||||
|
host, but hosts its own database separately. I want to unify the data source in
|
||||||
|
a very flexible way so that it can be shared among apps.
|
||||||
|
|
||||||
|
This app takes inspiration from many similar apps, such as Anytype, Logseq, Notion, etc.
|
||||||
|
|
||||||
|
## Features I want
|
||||||
|
|
||||||
|
- Graph view
|
||||||
|
- Instantly share/publish anything
|
||||||
|
- Full text+OCR search
|
||||||
|
- IFTTT workflows
|
||||||
|
- Notifications
|
||||||
|
- Multiuser
|
||||||
|
- Google docs like interface for docs / typst
|
||||||
|
|
||||||
|
## Custom Apps List
|
||||||
|
|
||||||
|
- File Backup
|
||||||
|
- Object storage
|
||||||
|
- Archivebox like system, bookmarking
|
||||||
|
- Journal
|
||||||
|
- Block-based editor
|
||||||
|
- Embed any node type into journal
|
||||||
|
- Food
|
||||||
|
- Recipe tracker
|
||||||
|
- Grocery list (adds to my todo list)
|
||||||
|
- Meal planner
|
||||||
|
- Food blogging
|
||||||
|
- Health+Fitness
|
||||||
|
- Running progress (incl. saving GPS waypoints)
|
||||||
|
- Workout log for various workouts
|
||||||
|
- Weight tracking
|
||||||
|
- Connect to smartwatch?
|
||||||
|
- Pictures
|
||||||
|
- Face recognition
|
||||||
|
- Map view
|
||||||
|
- Coding
|
||||||
|
- Code tracking like Wakatime
|
||||||
|
- Git forge???
|
||||||
|
- Calendar
|
||||||
|
- Calendly-like appointment booking system
|
||||||
|
- Social
|
||||||
|
- Store people into people app
|
||||||
|
- Email+matrix chat
|
||||||
|
- Video conferencing?
|
||||||
|
- Feed readers / RSS
|
||||||
|
- Media
|
||||||
|
- Music and video hosting / streaming i.e Navidrome
|
||||||
|
- Money tracking
|
||||||
|
- Education
|
||||||
|
- Anki flashcards
|
||||||
|
- Canvas???
|
||||||
|
- Dashboards
|
|
@ -1,11 +0,0 @@
|
||||||
---
|
|
||||||
title: Example Guide
|
|
||||||
description: A guide in my new Starlight docs site.
|
|
||||||
---
|
|
||||||
|
|
||||||
Guides lead a user through a specific task they want to accomplish, often with a sequence of steps.
|
|
||||||
Writing a good guide requires thinking about what your users are trying to do.
|
|
||||||
|
|
||||||
## Further reading
|
|
||||||
|
|
||||||
- Read [about how-to guides](https://diataxis.fr/how-to-guides/) in the Diátaxis framework
|
|
11
docs/src/content/docs/high-level-design/attributes.md
Normal file
11
docs/src/content/docs/high-level-design/attributes.md
Normal file
|
@ -0,0 +1,11 @@
|
||||||
|
---
|
||||||
|
title: Attributes
|
||||||
|
---
|
||||||
|
|
||||||
|
The core idea behind panorama is that apps can choose to define attributes, which you can think of as slots.
|
||||||
|
|
||||||
|
The slots have some particular type, which can be filled with some node.
|
||||||
|
|
||||||
|
:::caution
|
||||||
|
The absence of an attribute is different from the existence of the $\textsf{None}$ value.
|
||||||
|
:::
|
10
docs/src/content/docs/high-level-design/indexing.md
Normal file
10
docs/src/content/docs/high-level-design/indexing.md
Normal file
|
@ -0,0 +1,10 @@
|
||||||
|
---
|
||||||
|
title: Indexing
|
||||||
|
---
|
||||||
|
|
||||||
|
There are several types of indexes in panorama.
|
||||||
|
Some are the database kind that updates immediately.
|
||||||
|
Others are the search kind that updates asynchronously.
|
||||||
|
|
||||||
|
Custom app authors can specify how their attributes should be indexed.
|
||||||
|
Then, whenever
|
21
docs/src/content/docs/high-level-design/nodes.md
Normal file
21
docs/src/content/docs/high-level-design/nodes.md
Normal file
|
@ -0,0 +1,21 @@
|
||||||
|
---
|
||||||
|
title: Nodes
|
||||||
|
---
|
||||||
|
|
||||||
|
Everything is organized into nodes.
|
||||||
|
|
||||||
|
Each app (journal, mail, etc.) creates nodes to represent their information.
|
||||||
|
These nodes are linked to each other through attributes.
|
||||||
|
|
||||||
|
When retrieving its contents, a closure-like query is conducted and all the
|
||||||
|
nodes reachable through its attributes are returned.
|
||||||
|
|
||||||
|
Think of a node as being represented like this:
|
||||||
|
|
||||||
|
```ts
|
||||||
|
interface Node {
|
||||||
|
id: string;
|
||||||
|
type: string;
|
||||||
|
attributes: string[];
|
||||||
|
}
|
||||||
|
```
|
10
docs/src/content/docs/high-level-design/permissions.md
Normal file
10
docs/src/content/docs/high-level-design/permissions.md
Normal file
|
@ -0,0 +1,10 @@
|
||||||
|
---
|
||||||
|
title: Permissions
|
||||||
|
---
|
||||||
|
|
||||||
|
## Goals
|
||||||
|
|
||||||
|
- Apps should probably not be allowed to read attributes they didn't explicitly request access to
|
||||||
|
- (there should be an option "Unless they created the node")
|
||||||
|
|
||||||
|
## Design
|
20
docs/src/content/docs/high-level-design/sync.md
Normal file
20
docs/src/content/docs/high-level-design/sync.md
Normal file
|
@ -0,0 +1,20 @@
|
||||||
|
---
|
||||||
|
title: Sync
|
||||||
|
---
|
||||||
|
|
||||||
|
:::caution
|
||||||
|
This is documentation for a feature that is in development.
|
||||||
|
|
||||||
|
Almost none of this is implemented and most of it will probably change in the future.
|
||||||
|
:::
|
||||||
|
|
||||||
|
This **only** deals with syncing nodes and files between devices owned by the same person. Permissions are not considered here.
|
||||||
|
|
||||||
|
## Design notes
|
||||||
|
|
||||||
|
-
|
||||||
|
Devices need to have some kind of knowledge of each other's existence. This may not necessarily be exposed to apps, but the thing that's responsible for syncing needs to know which nodes have which files.
|
||||||
|
-
|
||||||
|
Slow internet connections and largely offline usage patterns need to be considered.
|
||||||
|
-
|
||||||
|
**TODO:** does this need to be deeply integrated within the panorama daemon itself or is there a way to expose enough APIs for this to just be an app?
|
71
docs/src/content/docs/high-level-design/types.md
Normal file
71
docs/src/content/docs/high-level-design/types.md
Normal file
|
@ -0,0 +1,71 @@
|
||||||
|
---
|
||||||
|
title: Types
|
||||||
|
---
|
||||||
|
|
||||||
|
Types exist to ensure that apps are treating data properly.
|
||||||
|
|
||||||
|
## Formal definition
|
||||||
|
|
||||||
|
A node's type can be one of the following:
|
||||||
|
|
||||||
|
$\tau :\equiv$
|
||||||
|
|
||||||
|
- $c$ (constant)
|
||||||
|
- $\alpha$ (type variable)
|
||||||
|
- $\mu \alpha . \tau$ (inductive type)
|
||||||
|
- $( \ell_k : \tau_k )_k$ (record type)
|
||||||
|
- $\{ \ell_k : \tau_k \}_k$ (sum type)
|
||||||
|
- $\#n$ (singleton type)
|
||||||
|
|
||||||
|
Constants may be node references, unit, unsigned/signed integers, decimal,
|
||||||
|
strings, booleans, instant (or timezone-aware timestamp), or URL
|
||||||
|
|
||||||
|
It is possible in the future that node references are also made using URLs, but
|
||||||
|
the URL format will need to be decided upon by then.
|
||||||
|
|
||||||
|
## Notes
|
||||||
|
|
||||||
|
- All nodes must belong to _closed_ types.
|
||||||
|
This means type variables cannot exist at the top-level.
|
||||||
|
- When shown in the panorama UI, the constant type will not be shown as a separate type.
|
||||||
|
Instead the actual type itself will be inlined.
|
||||||
|
- The type registry doesn't canonically exist in the database (it may exist in the form of system logs).
|
||||||
|
Instead, apps register their types on boot.
|
||||||
|
Everything is known to the panorama daemon after app initialization.
|
||||||
|
- The following constant types have their fields embedded directly into the node table:
|
||||||
|
- Number (integer, bigdecimal), string, boolean: `value`
|
||||||
|
- Sum: `label` (which variant is used?)
|
||||||
|
- Record types are essentially a collection of forced attributes.
|
||||||
|
A node with a record type _must_ contain every field listed in the labels of the record type.
|
||||||
|
- The panorama type system is _structurally_ typed.
|
||||||
|
#TODO Maybe add some convenient way of introducing ways to distinguish types apart?
|
||||||
|
|
||||||
|
### Convenient types
|
||||||
|
|
||||||
|
- $\textsf{Optional}(\tau) :\equiv \{ \texttt{'none} : () , \texttt{'some} : \tau \}$ \
|
||||||
|
The optional type.
|
||||||
|
|
||||||
|
### What is the point of a singleton type?
|
||||||
|
|
||||||
|
Singleton types only consist of a node ID.
|
||||||
|
The point of this is so apps can create types that are forced to have exactly a single node.
|
||||||
|
|
||||||
|
:::note
|
||||||
|
Apps with dashboards (mail) may create a type that represents the "entrypoint" into their application.
|
||||||
|
The process of creating it would look like this:
|
||||||
|
|
||||||
|
+ Upon app registration, I declare that I want a singleton type to be registered as `panorama-mail/entry`.
|
||||||
|
+ A node id will be assigned, if it doesn't already exist.
|
||||||
|
+ The application is returned the node ID.
|
||||||
|
+ The application can then register links to that node ID, and it can register a handler.
|
||||||
|
:::
|
||||||
|
|
||||||
|
When an app is registered, its types are parsed and registered into the database.
|
||||||
|
At the time of writing, if the node ID it refers to has already been found in the database, the type of the node will be checked against the given type.
|
||||||
|
If it doesn't match #TODO
|
||||||
|
|
||||||
|
## Attributes
|
||||||
|
|
||||||
|
Nodes contain attributes.
|
||||||
|
An attribute is a link to another node.
|
||||||
|
Attributes are typed, and the node it's linked to must have that type.
|
|
@ -1,36 +1,14 @@
|
||||||
---
|
---
|
||||||
title: Welcome to Starlight
|
title: Welcome to Panorama
|
||||||
description: Get started building your docs site with Starlight.
|
description: Get started building your docs site with Starlight.
|
||||||
template: splash
|
template: splash
|
||||||
hero:
|
hero:
|
||||||
tagline: Congrats on setting up a new Starlight project!
|
tagline: I love scope creep...
|
||||||
image:
|
image:
|
||||||
file: ../../assets/houston.webp
|
file: ../../assets/houston.webp
|
||||||
actions:
|
actions:
|
||||||
- text: Example Guide
|
- text: Read the docs
|
||||||
link: /guides/example/
|
link: /dream
|
||||||
icon: right-arrow
|
icon: right-arrow
|
||||||
variant: primary
|
variant: primary
|
||||||
- text: Read the Starlight docs
|
|
||||||
link: https://starlight.astro.build
|
|
||||||
icon: external
|
|
||||||
---
|
---
|
||||||
|
|
||||||
import { Card, CardGrid } from '@astrojs/starlight/components';
|
|
||||||
|
|
||||||
## Next steps
|
|
||||||
|
|
||||||
<CardGrid stagger>
|
|
||||||
<Card title="Update content" icon="pencil">
|
|
||||||
Edit `src/content/docs/index.mdx` to see this page change.
|
|
||||||
</Card>
|
|
||||||
<Card title="Add new content" icon="add-document">
|
|
||||||
Add Markdown or MDX files to `src/content/docs` to create new pages.
|
|
||||||
</Card>
|
|
||||||
<Card title="Configure your site" icon="setting">
|
|
||||||
Edit your `sidebar` and other config in `astro.config.mjs`.
|
|
||||||
</Card>
|
|
||||||
<Card title="Read the docs" icon="open-book">
|
|
||||||
Learn more in [the Starlight Docs](https://starlight.astro.build/).
|
|
||||||
</Card>
|
|
||||||
</CardGrid>
|
|
||||||
|
|
|
@ -1,11 +0,0 @@
|
||||||
---
|
|
||||||
title: Example Reference
|
|
||||||
description: A reference page in my new Starlight docs site.
|
|
||||||
---
|
|
||||||
|
|
||||||
Reference pages are ideal for outlining how things work in terse and clear terms.
|
|
||||||
Less concerned with telling a story or addressing a specific use case, they should give a comprehensive outline of what you're documenting.
|
|
||||||
|
|
||||||
## Further reading
|
|
||||||
|
|
||||||
- Read [about reference](https://diataxis.fr/reference/) in the Diátaxis framework
|
|
|
@ -0,0 +1,23 @@
|
||||||
|
---
|
||||||
|
title: Custom App Sandboxing
|
||||||
|
---
|
||||||
|
|
||||||
|
:::caution
|
||||||
|
For the initial releases of panorama, I am not planning on including _any_
|
||||||
|
sandboxing whatsoever. The development overhead will be far too great to warrant supporting it.
|
||||||
|
|
||||||
|
The entire app _will_ be rewritten before the public alpha release, which will
|
||||||
|
include proper custom app sandboxing. This page lists some ideas.
|
||||||
|
:::
|
||||||
|
|
||||||
|
Custom apps are made up of two parts:
|
||||||
|
|
||||||
|
- The backend, which talks to the database
|
||||||
|
- The frontend, which talks to the user
|
||||||
|
|
||||||
|
I say "the" frontend, but there could possibly be multiple frontends. (TUI, headless, etc.)
|
||||||
|
Each part needs to be sandboxed individually.
|
||||||
|
|
||||||
|
## Backend sandboxing
|
||||||
|
|
||||||
|
This will be done via a WASM runtime. The custom app's backend software will
|
6
docs/src/content/docs/technical-docs/loading_process.md
Normal file
6
docs/src/content/docs/technical-docs/loading_process.md
Normal file
|
@ -0,0 +1,6 @@
|
||||||
|
---
|
||||||
|
title: Loading process
|
||||||
|
---
|
||||||
|
|
||||||
|
The goal of panorama is to start up as quickly as possible.
|
||||||
|
The following tasks need to be performed on start:
|
5
docs/src/content/docs/technical-docs/notifications.md
Normal file
5
docs/src/content/docs/technical-docs/notifications.md
Normal file
|
@ -0,0 +1,5 @@
|
||||||
|
---
|
||||||
|
title: Notifications
|
||||||
|
---
|
||||||
|
|
||||||
|
https://unifiedpush.org/
|
10
docs/src/content/docs/technical-docs/protected_namespace.md
Normal file
10
docs/src/content/docs/technical-docs/protected_namespace.md
Normal file
|
@ -0,0 +1,10 @@
|
||||||
|
---
|
||||||
|
title: Protected Namespaces
|
||||||
|
---
|
||||||
|
|
||||||
|
There's some protected namespace of nodes that's used to keep track of the
|
||||||
|
actual database functionality. For example:
|
||||||
|
|
||||||
|
- List of installed apps
|
||||||
|
- List of currently registered types (maybe not keep this?)
|
||||||
|
- System log
|
|
@ -1,3 +1,5 @@
|
||||||
{
|
{
|
||||||
"extends": "astro/tsconfigs/strict"
|
"extends": "astro/tsconfigs/strict",
|
||||||
|
"compilerOptions": { "skipLibCheck": true },
|
||||||
|
"exclude": ["dist"]
|
||||||
}
|
}
|
4581
pnpm-lock.yaml
4581
pnpm-lock.yaml
File diff suppressed because it is too large
Load diff
|
@ -1,3 +1,3 @@
|
||||||
packages:
|
packages:
|
||||||
# - 'react'
|
|
||||||
- 'app'
|
- 'app'
|
||||||
|
- 'docs'
|
33
proto/panorama.proto
Normal file
33
proto/panorama.proto
Normal file
|
@ -0,0 +1,33 @@
|
||||||
|
syntax = "proto3";
|
||||||
|
package io.mzhang.panorama;
|
||||||
|
|
||||||
|
service PanoramaHost {
|
||||||
|
rpc Hello (HelloRequest) returns (HelloResponse) {}
|
||||||
|
rpc RegisterSingletonType (RegisterSingletonTypeRequest) returns (RegisterSingletonTypeResponse) {}
|
||||||
|
rpc RegisterType (RegisterTypeRequest) returns (RegisterTypeResponse) {}
|
||||||
|
}
|
||||||
|
|
||||||
|
message HelloRequest {}
|
||||||
|
message HelloResponse {
|
||||||
|
// What the actual given name of your app is installed as; this is not easily changed
|
||||||
|
string appName = 1;
|
||||||
|
string panoramaVersion = 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
message RegisterTypeRequest {
|
||||||
|
string typeName = 1;
|
||||||
|
string typeExpr = 2;
|
||||||
|
}
|
||||||
|
message RegisterTypeResponse {}
|
||||||
|
|
||||||
|
message RegisterSingletonTypeRequest {
|
||||||
|
// The name given to the attribute you want to reserve
|
||||||
|
string attributeName = 1;
|
||||||
|
}
|
||||||
|
message RegisterSingletonTypeResponse {
|
||||||
|
// Node id corresponding to the Singleton type
|
||||||
|
string nodeId = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
service PanoramaApp {
|
||||||
|
}
|
Loading…
Reference in a new issue