Merge pull request #935 from toeverything/feat/client-app

feat: tauri desktop client app
This commit is contained in:
DarkSky
2023-02-10 19:38:44 +08:00
committed by GitHub
78 changed files with 14027 additions and 90 deletions

View File

@@ -43,6 +43,7 @@ export const EditorHeader = () => {
>
{title && (
<StyledTitle
data-tauri-drag-region
onMouseEnter={() => {
if (isTrash) return;

View File

@@ -56,7 +56,11 @@ export const Header = ({
setShowWarning(false);
}}
/>
<StyledHeader hasWarning={showWarning} data-testid="editor-header-items">
<StyledHeader
hasWarning={showWarning}
data-testid="editor-header-items"
data-tauri-drag-region
>
{children}
<StyledHeaderRightSide>
{rightItems.map(itemName => {

View File

@@ -79,7 +79,7 @@ const AppDefender = ({ children }: PropsWithChildren) => {
const { synced } = useAppState();
useEffect(() => {
if (router.asPath === '/') {
if (['/index.html', '/'].includes(router.asPath)) {
router.replace('/workspace');
}
}, [router]);

View File

@@ -32,7 +32,9 @@ export const AppStateProvider = ({
if (dataCenter.workspaces.length === 0) {
await createDefaultWorkspace(dataCenter);
}
setUser((await dataCenter.getUserInfo()) || null);
setUser(
(await dataCenter.getUserInfo(dataCenter.providers[0]?.id)) || null
);
setAppState({
dataCenter,
workspaceList: dataCenter.workspaces,

View File

@@ -29,6 +29,7 @@
"dependencies": {
"@blocksuite/blocks": "0.4.0-20230210031655-264744e",
"@blocksuite/store": "0.4.0-20230210031655-264744e",
"@tauri-apps/api": "^1.2.0",
"debug": "^4.3.4",
"encoding": "^0.1.13",
"firebase": "^9.15.0",

View File

@@ -46,7 +46,16 @@ export class DataCenter {
};
};
// TODO: switch different provider
await dc.registerProvider(new LocalProvider(getInitParams()));
if (
typeof window !== 'undefined' &&
window.CLIENT_APP &&
typeof window.__TAURI_IPC__ === 'function'
) {
const { TauriIPCProvider } = await import('./provider/tauri-ipc');
await dc.registerProvider(new TauriIPCProvider(getInitParams()));
} else {
await dc.registerProvider(new LocalProvider(getInitParams()));
}
await dc.registerProvider(new AffineProvider(getInitParams()));
for (const provider of dc.providerMap.values()) {

View File

@@ -0,0 +1,8 @@
declare global {
interface Window {
CLIENT_APP?: boolean;
__editoVersion?: string;
}
}
export {};

View File

@@ -27,7 +27,7 @@ export enum WorkspaceType {
export enum PermissionType {
Read = 0,
Write = 1,
Admin = 2,
Admin = 10,
Owner = 99,
}

View File

@@ -0,0 +1,75 @@
import { PutBlob, GetBlob } from '../ipc/types/blob';
import {
YDocumentUpdate,
GetDocumentParameter,
GetDocumentResponse,
} from '../ipc/types/document';
import { CreateUser, GetUserParameters, User } from '../ipc/types/user';
import {
CreateWorkspace,
CreateWorkspaceResult,
GetWorkspaces,
GetWorkspacesResult,
GetWorkspace,
GetWorkspaceResult,
} from '../ipc/types/workspace';
export const updateYDocument = async (parameters: YDocumentUpdate) =>
await true;
export const getYDocument = async (
parameters: GetDocumentParameter
): Promise<GetDocumentResponse> =>
await {
updates: [],
};
export const createWorkspace = async (
parameters: CreateWorkspace
): Promise<CreateWorkspaceResult> => await { id: 'xxx', name: 'xxx' };
export const getWorkspaces = async (
parameters: GetWorkspaces
): Promise<GetWorkspacesResult> =>
await {
workspaces: [],
};
export const getWorkspace = async (
parameters: GetWorkspace
): Promise<GetWorkspaceResult> =>
await {
workspace: {
created_at: 0,
id: '',
member_count: 1,
public: true,
type: 0,
},
};
export const putBlob = async (parameters: PutBlob): Promise<string> =>
await 'path/xxx';
export const getBlob = async (parameters: GetBlob): Promise<number[]> =>
await [];
/**
* This will create a private workspace too.
* @returns
*/
export const createUser = async (parameters: CreateUser): Promise<User> =>
await {
created_at: 0,
id: '1',
email: 'xxx@xxx.xxx',
name: 'xxx',
};
export const getUser = async (parameters: GetUserParameters): Promise<User> =>
await {
created_at: 0,
id: '1',
email: 'xxx@xxx.xxx',
name: 'xxx',
};

View File

@@ -0,0 +1,54 @@
import { test, expect } from '@playwright/test';
import { WorkspaceUnitCollection } from '../../../workspace-unit-collection.js';
import { TauriIPCProvider } from '../index.js';
import { MessageCenter } from '../../../message/index.js';
import * as ipcMethods from './mock-apis.js';
import 'fake-indexeddb/auto';
test.describe.serial('tauri-ipc provider', async () => {
const workspaceMetaCollection = new WorkspaceUnitCollection();
const provider = new TauriIPCProvider({
workspaces: workspaceMetaCollection.createScope(),
messageCenter: new MessageCenter(),
});
provider.init(ipcMethods);
const workspaceName = 'workspace-test';
let workspaceId: string | undefined;
test('create workspace', async () => {
const workspaceUnit = await provider.createWorkspace({
name: workspaceName,
});
workspaceId = workspaceUnit?.id;
expect(workspaceMetaCollection.workspaces.length).toEqual(1);
expect(workspaceMetaCollection.workspaces[0].name).toEqual(workspaceName);
});
test('workspace list', async () => {
const workspacesMetaCollection1 = new WorkspaceUnitCollection();
const provider1 = new TauriIPCProvider({
workspaces: workspacesMetaCollection1.createScope(),
messageCenter: new MessageCenter(),
});
provider1.init(ipcMethods);
await provider1.getUserInfo();
await provider1.loadWorkspaces();
expect(workspacesMetaCollection1.workspaces.length).toEqual(0);
await provider1.createWorkspace({
name: workspaceName,
});
expect(workspacesMetaCollection1.workspaces[0].name).toEqual(workspaceName);
expect(workspacesMetaCollection1.workspaces[0].id).toEqual(workspaceId);
});
test('update workspace', async () => {
await provider.updateWorkspaceMeta(workspaceId!, {
name: '1111',
});
expect(workspaceMetaCollection.workspaces[0].name).toEqual('1111');
});
});

View File

@@ -0,0 +1,70 @@
import { BlobSyncState } from '@blocksuite/store';
import * as ipcMethods from '../ipc/methods.js';
import { Signal } from '@blocksuite/store';
import type {
BlobProvider,
BlobSyncStateChangeEvent,
BlobId,
BlobURL,
} from '@blocksuite/store/dist/persistence/blob/types.js';
export class IPCBlobProvider implements BlobProvider {
#ipc = ipcMethods;
#workspace: string;
readonly signals = {
onBlobSyncStateChange: new Signal<BlobSyncStateChangeEvent>(),
};
private constructor(workspace: string) {
this.#workspace = workspace;
}
static async init(workspace: string): Promise<IPCBlobProvider> {
const provider = new IPCBlobProvider(workspace);
return provider;
}
get uploading() {
return false;
}
get blobs() {
// TODO: implement blob list in Octobase
return Promise.resolve([]) as Promise<string[]>;
}
async get(id: BlobId): Promise<BlobURL | null> {
const blobArray = await this.#ipc.getBlob({
id,
});
// Make a Blob from the bytes
const blob = new Blob([new Uint8Array(blobArray)], { type: 'image/bmp' });
this.signals.onBlobSyncStateChange.emit({
id,
state: BlobSyncState.Success,
});
return window.URL.createObjectURL(blob);
}
async set(blob: Blob): Promise<BlobId> {
// TODO: skip if already has
const blobID = await this.#ipc.putBlob({
blob: Array.from(new Uint8Array(await blob.arrayBuffer())),
});
this.signals.onBlobSyncStateChange.emit({
id: blobID,
state: BlobSyncState.Success,
});
return blobID;
}
async delete(id: BlobId): Promise<void> {
// TODO: implement blob delete in Octobase
}
async clear(): Promise<void> {
// TODO: implement blob clear in Octobase, use workspace id #workspace
}
}

View File

@@ -0,0 +1,194 @@
import * as Y from 'yjs';
import assert from 'assert';
import { LocalProvider } from '../local/index.js';
import type { IPCMethodsType } from './ipc/methods.js';
import {
CreateWorkspaceInfoParams,
ProviderConstructorParams,
} from '../base.js';
import { Workspace as BlocksuiteWorkspace } from '@blocksuite/store';
import { IPCBlobProvider } from './blocksuite-provider/blob.js';
import type { WorkspaceUnit } from 'src/workspace-unit.js';
import { createWorkspaceUnit, loadWorkspaceUnit } from '../local/utils.js';
import { WorkspaceWithPermission } from './ipc/types/workspace.js';
import { applyUpdate } from '../../utils/index.js';
import { User } from 'src/types/index.js';
/**
* init - createUser - create first workspace and ydoc - loadWorkspace - return the first workspace - wrapWorkspace - #initDocFromIPC - applyUpdate - on('update') - updateYDocument
*
* (init - createUser - error) loadWorkspace - return the first workspace - wrapWorkspace - #initDocFromIPC - applyUpdate - on('update') - updateYDocument
*/
export class TauriIPCProvider extends LocalProvider {
public id = 'tauri-ipc';
static defaultUserEmail = 'xxx@xx.xx';
/**
* // TODO: We only have one user in this version of app client. But may support switch user later.
*/
#userID?: string;
#ipc: IPCMethodsType | undefined;
constructor(params: ProviderConstructorParams) {
super(params);
}
async init(ipc?: IPCMethodsType) {
if (ipc) {
this.#ipc = ipc;
} else {
this.#ipc = await import('./ipc/methods.js');
}
try {
const user = await this.#ipc?.getUser({
email: TauriIPCProvider.defaultUserEmail,
});
this.#userID = user.id;
} catch (error) {
// maybe user not existed, we create a default user if we don't have one.
try {
const user = await this.#ipc?.createUser({
email: TauriIPCProvider.defaultUserEmail,
name: 'xxx',
password: 'xxx',
avatar_url: '',
});
this.#userID = user.id;
} catch (error) {
// maybe user existed, which can be omited
console.error(error);
}
}
}
/**
* get auth user info
* @returns
*/
public async getUserInfo(): Promise<User | undefined> {
const user = await this.#ipc?.getUser({
email: TauriIPCProvider.defaultUserEmail,
});
if (user?.name !== undefined) {
return {
...user,
avatar: user?.avatar_url || '',
};
}
}
async #initDocFromIPC(
workspaceID: string,
blocksuiteWorkspace: BlocksuiteWorkspace
) {
this._logger(`Loading ${workspaceID}...`);
const result = await this.#ipc?.getYDocument({ id: workspaceID });
if (result) {
const updates = result.updates.map(
binaryUpdate => new Uint8Array(binaryUpdate)
);
const mergedUpdate = Y.mergeUpdates(updates);
await applyUpdate(blocksuiteWorkspace, mergedUpdate);
this._logger(`Loaded: ${workspaceID}`);
}
}
async #connectDocToIPC(
workspaceID: string,
blocksuiteWorkspace: BlocksuiteWorkspace
) {
this._logger(`Connecting yDoc for ${workspaceID}...`);
blocksuiteWorkspace.doc.on('update', async (update: Uint8Array) => {
try {
const binary = Y.encodeStateAsUpdate(blocksuiteWorkspace.doc);
const success = await this.#ipc?.updateYDocument({
update: Array.from(binary),
id: workspaceID,
});
if (!success) {
throw new Error(`YDoc update failed, id: ${workspaceID}`);
}
} catch (error) {
// TODO: write error log to disk, and add button to open them in settings panel
console.error("#yDocument.on('update'", error);
}
});
}
async clear() {
await super.clear();
}
override async warpWorkspace(blocksuiteWorkspace: BlocksuiteWorkspace) {
const { room } = blocksuiteWorkspace;
assert(room);
(await blocksuiteWorkspace.blobs)?.setProvider(
await IPCBlobProvider.init(room)
);
await this.#initDocFromIPC(room, blocksuiteWorkspace);
await this.#connectDocToIPC(room, blocksuiteWorkspace);
return blocksuiteWorkspace;
}
public override async createWorkspace(
meta: CreateWorkspaceInfoParams
): Promise<WorkspaceUnit | undefined> {
this._logger('Creating client app workspace');
assert(this.#ipc);
assert(this.#userID);
const { id } = await this.#ipc.createWorkspace({
name: meta.name,
// TODO: get userID here
user_id: this.#userID,
});
const workspaceUnit = await createWorkspaceUnit({
name: meta.name,
id,
published: false,
avatar: '',
owner: undefined,
syncMode: 'core',
memberCount: 1,
provider: this.id,
});
this._workspaces.add(workspaceUnit);
const doc = workspaceUnit?.blocksuiteWorkspace?.doc;
if (doc) {
const update = Y.encodeStateAsUpdate(doc);
const success = await this.#ipc?.updateYDocument({
update: Array.from(update),
id,
});
if (!success) {
throw new Error(`YDoc update failed, id: ${id}`);
}
}
return workspaceUnit;
}
override async loadWorkspaces(): Promise<WorkspaceUnit[]> {
assert(this.#ipc);
assert(this.#userID);
const { workspaces } = await this.#ipc.getWorkspaces({
user_id: this.#userID,
});
const workspaceUnits = await Promise.all(
workspaces.map((meta: WorkspaceWithPermission) => {
return loadWorkspaceUnit({
...meta,
memberCount: 1,
// TODO: load name here
name: '',
provider: this.id,
syncMode: 'all',
});
})
);
this._workspaces.add(workspaceUnits);
return workspaceUnits;
}
}

View File

@@ -0,0 +1,78 @@
import { invoke } from '@tauri-apps/api';
import {
GetDocumentParameter,
GetDocumentResponse,
YDocumentUpdate,
} from './types/document';
import {
CreateWorkspace,
CreateWorkspaceResult,
GetWorkspace,
GetWorkspaceResult,
GetWorkspaces,
GetWorkspacesResult,
User,
} from './types/workspace';
import { GetBlob, PutBlob } from './types/blob';
import { CreateUser, GetUserParameters } from './types/user';
export interface IPCMethodsType {
updateYDocument: typeof updateYDocument;
getYDocument: typeof getYDocument;
createWorkspace: typeof createWorkspace;
getWorkspaces: typeof getWorkspaces;
getWorkspace: typeof getWorkspace;
putBlob: typeof putBlob;
getBlob: typeof getBlob;
createUser: typeof createUser;
getUser: typeof getUser;
}
export const updateYDocument = async (parameters: YDocumentUpdate) =>
await invoke<boolean>('update_y_document', {
parameters,
});
export const getYDocument = async (parameters: GetDocumentParameter) =>
await invoke<GetDocumentResponse>('get_doc', {
parameters,
});
export const createWorkspace = async (parameters: CreateWorkspace) =>
await invoke<CreateWorkspaceResult>('create_workspace', {
parameters,
});
export const getWorkspaces = async (parameters: GetWorkspaces) =>
await invoke<GetWorkspacesResult>('get_workspaces', {
parameters,
});
export const getWorkspace = async (parameters: GetWorkspace) =>
await invoke<GetWorkspaceResult>('get_workspace', {
parameters,
});
export const putBlob = async (parameters: PutBlob) =>
await invoke<string>('put_blob', {
parameters,
});
export const getBlob = async (parameters: GetBlob) =>
await invoke<number[]>('get_blob', {
parameters,
});
/**
* This will create a private workspace too.
* @returns
*/
export const createUser = async (parameters: CreateUser) =>
await invoke<User>('create_user', {
parameters,
});
export const getUser = async (parameters: GetUserParameters) =>
await invoke<User>('get_user', {
parameters,
});

View File

@@ -0,0 +1,57 @@
{
"$schema": "http://json-schema.org/draft-07/schema#",
"title": "IBlobParameters",
"oneOf": [
{
"type": "object",
"required": ["Put"],
"properties": {
"Put": {
"$ref": "#/definitions/PutBlob"
}
},
"additionalProperties": false
},
{
"type": "object",
"required": ["Get"],
"properties": {
"Get": {
"$ref": "#/definitions/GetBlob"
}
},
"additionalProperties": false
}
],
"definitions": {
"GetBlob": {
"type": "object",
"required": ["id"],
"properties": {
"id": {
"type": "string"
},
"workspace_id": {
"type": ["string", "null"]
}
}
},
"PutBlob": {
"type": "object",
"required": ["blob"],
"properties": {
"blob": {
"type": "array",
"items": {
"type": "integer",
"format": "uint8",
"minimum": 0.0
}
},
"workspace_id": {
"type": ["string", "null"]
}
}
}
}
}

View File

@@ -0,0 +1,24 @@
/**
* This file was automatically generated by json-schema-to-typescript.
* DO NOT MODIFY IT BY HAND. Instead, modify the source JSONSchema file,
* and run json-schema-to-typescript to regenerate this file.
*/
export type IBlobParameters =
| {
Put: PutBlob;
}
| {
Get: GetBlob;
};
export interface PutBlob {
blob: number[];
workspace_id?: string | null;
[k: string]: unknown;
}
export interface GetBlob {
id: string;
workspace_id?: string | null;
[k: string]: unknown;
}

View File

@@ -0,0 +1,103 @@
{
"$schema": "http://json-schema.org/draft-07/schema#",
"title": "IDocumentParameters",
"oneOf": [
{
"type": "object",
"required": ["YDocumentUpdate"],
"properties": {
"YDocumentUpdate": {
"$ref": "#/definitions/YDocumentUpdate"
}
},
"additionalProperties": false
},
{
"type": "object",
"required": ["CreateDocumentParameter"],
"properties": {
"CreateDocumentParameter": {
"$ref": "#/definitions/CreateDocumentParameter"
}
},
"additionalProperties": false
},
{
"type": "object",
"required": ["GetDocumentParameter"],
"properties": {
"GetDocumentParameter": {
"$ref": "#/definitions/GetDocumentParameter"
}
},
"additionalProperties": false
},
{
"type": "object",
"required": ["GetDocumentResponse"],
"properties": {
"GetDocumentResponse": {
"$ref": "#/definitions/GetDocumentResponse"
}
},
"additionalProperties": false
}
],
"definitions": {
"CreateDocumentParameter": {
"type": "object",
"required": ["workspace_id", "workspace_name"],
"properties": {
"workspace_id": {
"type": "string"
},
"workspace_name": {
"type": "string"
}
}
},
"GetDocumentParameter": {
"type": "object",
"required": ["id"],
"properties": {
"id": {
"type": "string"
}
}
},
"GetDocumentResponse": {
"type": "object",
"required": ["updates"],
"properties": {
"updates": {
"type": "array",
"items": {
"type": "array",
"items": {
"type": "integer",
"format": "uint8",
"minimum": 0.0
}
}
}
}
},
"YDocumentUpdate": {
"type": "object",
"required": ["id", "update"],
"properties": {
"id": {
"type": "string"
},
"update": {
"type": "array",
"items": {
"type": "integer",
"format": "uint8",
"minimum": 0.0
}
}
}
}
}
}

View File

@@ -0,0 +1,38 @@
/**
* This file was automatically generated by json-schema-to-typescript.
* DO NOT MODIFY IT BY HAND. Instead, modify the source JSONSchema file,
* and run json-schema-to-typescript to regenerate this file.
*/
export type IDocumentParameters =
| {
YDocumentUpdate: YDocumentUpdate;
}
| {
CreateDocumentParameter: CreateDocumentParameter;
}
| {
GetDocumentParameter: GetDocumentParameter;
}
| {
GetDocumentResponse: GetDocumentResponse;
};
export interface YDocumentUpdate {
id: string;
update: number[];
[k: string]: unknown;
}
export interface CreateDocumentParameter {
workspace_id: string;
workspace_name: string;
[k: string]: unknown;
}
export interface GetDocumentParameter {
id: string;
[k: string]: unknown;
}
export interface GetDocumentResponse {
updates: number[][];
[k: string]: unknown;
}

View File

@@ -0,0 +1,87 @@
{
"$schema": "http://json-schema.org/draft-07/schema#",
"title": "IUserParameters",
"oneOf": [
{
"type": "object",
"required": ["CreateUser"],
"properties": {
"CreateUser": {
"$ref": "#/definitions/CreateUser"
}
},
"additionalProperties": false
},
{
"type": "object",
"required": ["User"],
"properties": {
"User": {
"$ref": "#/definitions/User"
}
},
"additionalProperties": false
},
{
"type": "object",
"required": ["GetUserParameters"],
"properties": {
"GetUserParameters": {
"$ref": "#/definitions/GetUserParameters"
}
},
"additionalProperties": false
}
],
"definitions": {
"CreateUser": {
"type": "object",
"required": ["email", "name", "password"],
"properties": {
"avatar_url": {
"type": ["string", "null"]
},
"email": {
"type": "string"
},
"name": {
"type": "string"
},
"password": {
"type": "string"
}
}
},
"GetUserParameters": {
"type": "object",
"required": ["email"],
"properties": {
"email": {
"type": "string"
}
}
},
"User": {
"type": "object",
"required": ["created_at", "email", "id", "name"],
"properties": {
"avatar_url": {
"type": ["string", "null"]
},
"created_at": {
"type": "integer",
"format": "int64"
},
"email": {
"type": "string"
},
"id": {
"type": "string"
},
"name": {
"type": "string"
}
}
}
}
}

View File

@@ -0,0 +1,36 @@
/**
* This file was automatically generated by json-schema-to-typescript.
* DO NOT MODIFY IT BY HAND. Instead, modify the source JSONSchema file,
* and run json-schema-to-typescript to regenerate this file.
*/
export type IUserParameters =
| {
CreateUser: CreateUser;
}
| {
User: User;
}
| {
GetUserParameters: GetUserParameters;
};
export interface CreateUser {
avatar_url?: string | null;
email: string;
name: string;
password: string;
[k: string]: unknown;
}
export interface User {
avatar_url?: string | null;
created_at: number;
email: string;
id: string;
name: string;
[k: string]: unknown;
}
export interface GetUserParameters {
email: string;
[k: string]: unknown;
}

View File

@@ -0,0 +1,240 @@
{
"$schema": "http://json-schema.org/draft-07/schema#",
"title": "IWorkspaceParameters",
"oneOf": [
{
"type": "object",
"required": ["CreateWorkspace"],
"properties": {
"CreateWorkspace": {
"$ref": "#/definitions/CreateWorkspace"
}
},
"additionalProperties": false
},
{
"type": "object",
"required": ["GetWorkspace"],
"properties": {
"GetWorkspace": {
"$ref": "#/definitions/GetWorkspace"
}
},
"additionalProperties": false
},
{
"type": "object",
"required": ["GetWorkspaces"],
"properties": {
"GetWorkspaces": {
"$ref": "#/definitions/GetWorkspaces"
}
},
"additionalProperties": false
},
{
"type": "object",
"required": ["GetWorkspaceResult"],
"properties": {
"GetWorkspaceResult": {
"$ref": "#/definitions/GetWorkspaceResult"
}
},
"additionalProperties": false
},
{
"type": "object",
"required": ["GetWorkspacesResult"],
"properties": {
"GetWorkspacesResult": {
"$ref": "#/definitions/GetWorkspacesResult"
}
},
"additionalProperties": false
},
{
"type": "object",
"required": ["UpdateWorkspace"],
"properties": {
"UpdateWorkspace": {
"$ref": "#/definitions/UpdateWorkspace"
}
},
"additionalProperties": false
},
{
"type": "object",
"required": ["CreateWorkspaceResult"],
"properties": {
"CreateWorkspaceResult": {
"$ref": "#/definitions/CreateWorkspaceResult"
}
},
"additionalProperties": false
}
],
"definitions": {
"CreateWorkspace": {
"type": "object",
"required": ["name", "user_id"],
"properties": {
"name": {
"description": "only set name, avatar is update in datacenter to yDoc directly",
"type": "string"
},
"user_id": {
"type": "string"
}
}
},
"CreateWorkspaceResult": {
"type": "object",
"required": ["id", "name"],
"properties": {
"id": {
"type": "string"
},
"name": {
"type": "string"
}
}
},
"GetWorkspace": {
"type": "object",
"required": ["id"],
"properties": {
"id": {
"type": "string"
}
}
},
"GetWorkspaceResult": {
"type": "object",
"required": ["workspace"],
"properties": {
"workspace": {
"$ref": "#/definitions/WorkspaceDetail"
}
}
},
"GetWorkspaces": {
"type": "object",
"required": ["user_id"],
"properties": {
"user_id": {
"type": "string"
}
}
},
"GetWorkspacesResult": {
"type": "object",
"required": ["workspaces"],
"properties": {
"workspaces": {
"type": "array",
"items": {
"$ref": "#/definitions/WorkspaceWithPermission"
}
}
}
},
"PermissionType": {
"type": "integer",
"enum": [0, 1, 10, 99]
},
"UpdateWorkspace": {
"type": "object",
"required": ["id", "public"],
"properties": {
"id": {
"type": "integer",
"format": "int64"
},
"public": {
"type": "boolean"
}
}
},
"User": {
"type": "object",
"required": ["created_at", "email", "id", "name"],
"properties": {
"avatar_url": {
"type": ["string", "null"]
},
"created_at": {
"type": "integer",
"format": "int64"
},
"email": {
"type": "string"
},
"id": {
"type": "string"
},
"name": {
"type": "string"
}
}
},
"WorkspaceDetail": {
"type": "object",
"required": ["created_at", "id", "member_count", "public", "type"],
"properties": {
"created_at": {
"type": "integer",
"format": "int64"
},
"id": {
"type": "string"
},
"member_count": {
"type": "integer",
"format": "int64"
},
"owner": {
"anyOf": [
{
"$ref": "#/definitions/User"
},
{
"type": "null"
}
]
},
"public": {
"type": "boolean"
},
"type": {
"$ref": "#/definitions/WorkspaceType"
}
}
},
"WorkspaceType": {
"type": "integer",
"enum": [0, 1]
},
"WorkspaceWithPermission": {
"type": "object",
"required": ["created_at", "id", "permission", "public", "type"],
"properties": {
"created_at": {
"type": "integer",
"format": "int64"
},
"id": {
"type": "string"
},
"permission": {
"$ref": "#/definitions/PermissionType"
},
"public": {
"type": "boolean"
},
"type": {
"$ref": "#/definitions/WorkspaceType"
}
}
}
}
}

View File

@@ -0,0 +1,90 @@
/**
* This file was automatically generated by json-schema-to-typescript.
* DO NOT MODIFY IT BY HAND. Instead, modify the source JSONSchema file,
* and run json-schema-to-typescript to regenerate this file.
*/
export type IWorkspaceParameters =
| {
CreateWorkspace: CreateWorkspace;
}
| {
GetWorkspace: GetWorkspace;
}
| {
GetWorkspaces: GetWorkspaces;
}
| {
GetWorkspaceResult: GetWorkspaceResult;
}
| {
GetWorkspacesResult: GetWorkspacesResult;
}
| {
UpdateWorkspace: UpdateWorkspace;
}
| {
CreateWorkspaceResult: CreateWorkspaceResult;
};
export type WorkspaceType = 0 | 1;
export type PermissionType = 0 | 1 | 10 | 99;
export interface CreateWorkspace {
/**
* only set name, avatar is update in datacenter to yDoc directly
*/
name: string;
user_id: string;
[k: string]: unknown;
}
export interface GetWorkspace {
id: string;
[k: string]: unknown;
}
export interface GetWorkspaces {
user_id: string;
[k: string]: unknown;
}
export interface GetWorkspaceResult {
workspace: WorkspaceDetail;
[k: string]: unknown;
}
export interface WorkspaceDetail {
created_at: number;
id: string;
member_count: number;
owner?: User | null;
public: boolean;
type: WorkspaceType;
[k: string]: unknown;
}
export interface User {
avatar_url?: string | null;
created_at: number;
email: string;
id: string;
name: string;
[k: string]: unknown;
}
export interface GetWorkspacesResult {
workspaces: WorkspaceWithPermission[];
[k: string]: unknown;
}
export interface WorkspaceWithPermission {
created_at: number;
id: string;
permission: PermissionType;
public: boolean;
type: WorkspaceType;
[k: string]: unknown;
}
export interface UpdateWorkspace {
id: number;
public: boolean;
[k: string]: unknown;
}
export interface CreateWorkspaceResult {
id: string;
name: string;
[k: string]: unknown;
}

View File

@@ -11,6 +11,13 @@ import { getLogger } from '../logger';
// provider: string;
// };
declare global {
interface Window {
// eslint-disable-next-line @typescript-eslint/ban-types
__TAURI_IPC__: Function;
}
}
export type User = {
name: string;
id: string;