Skip to content

Commit

Permalink
Add lots of documentation directly in types
Browse files Browse the repository at this point in the history
  • Loading branch information
Pierstoval committed Feb 13, 2024
1 parent c9e7758 commit 6c1e45f
Show file tree
Hide file tree
Showing 39 changed files with 349 additions and 59 deletions.
15 changes: 10 additions & 5 deletions .github/workflows/pages.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -31,20 +31,25 @@ jobs:
steps:
- uses: actions/checkout@v3

- name: Use Node.js ${{ matrix.node-version }}
- name: 🟢 Use Node.js ${{ matrix.node-version }}
uses: actions/setup-node@v3
with:
node-version: ${{ matrix.node-version }}
cache: 'yarn'

- run: yarn install --frozen-lockfile
- name: 🧰 Install dependencies
run: yarn install --frozen-lockfile

- run: yarn run build
- name: 🔨 Build demo app
run: yarn run build

- name: Prepare Github Pages
- name: 📄 Build types documentation
run: yarn run typedoc

- name: 🌐 Configure Github Pages domain
run: echo "svelte-admin-demo.orbitale.io" > build/CNAME

- name: Deploy
- name: 🚀 Deploy
uses: peaceiris/actions-gh-pages@v3
with:
github_token: ${{ secrets.GITHUB_TOKEN }}
Expand Down
6 changes: 3 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,9 @@

This package is an **admin generator** for your JS/TS/Svelte projects. It can consume a distant API, a localStorage, or even an RPC-based data storage (like when using [Tauri](https://tauri.app/)).

| List | View | Edit |
| ---------------------------------------------------------- | ---------------------------------------------------------- | ---------------------------------------------------------- |
| ![SvelteAdmin Backoffice List](./docs/backoffice_list.png) | ![SvelteAdmin Backoffice View](./docs/backoffice_view.png) | ![SvelteAdmin Backoffice Edit](./docs/backoffice_edit.png) |
| List | View | Edit |
|----------------------------------------------------------------|----------------------------------------------------------------|----------------------------------------------------------------|
| ![SvelteAdmin Backoffice List](./docs-src/backoffice_list.png) | ![SvelteAdmin Backoffice View](./docs-src/backoffice_view.png) | ![SvelteAdmin Backoffice Edit](./docs-src/backoffice_edit.png) |

There is a [roadmap](#roadmap) at the end of this documentation to know what features are soon coming!

Expand Down
File renamed without changes
File renamed without changes
File renamed without changes
8 changes: 6 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,8 @@
"check:watch": "svelte-kit sync && svelte-check --tsconfig ./tsconfig.json --watch",
"lint": "prettier --plugin=prettier-plugin-svelte . --check . && eslint src",
"format": "prettier --plugin=prettier-plugin-svelte --write .",
"test:unit": "vitest"
"test:unit": "vitest",
"typedoc": "typedoc --options typedoc.json --readme none"
},
"exports": {
".": {
Expand Down Expand Up @@ -47,7 +48,8 @@
"carbon-icons-svelte": "^12.0.0",
"luxon": "^3.4.4",
"svelte": "^4.0.0",
"svelte-i18n": "^4.0.0"
"svelte-i18n": "^4.0.0",
"typedoc": "^0.25.8"
},
"devDependencies": {
"@faker-js/faker": "^8.3.1",
Expand All @@ -56,6 +58,7 @@
"@sveltejs/kit": "^2.0.0",
"@sveltejs/package": "^2.2.3",
"@sveltejs/vite-plugin-svelte": "^3.0.1",
"@types/node": "^20.11.17",
"@types/uuid": "^9.0.7",
"@typescript-eslint/eslint-plugin": "^6.13.2",
"@typescript-eslint/parser": "^6.13.2",
Expand All @@ -71,6 +74,7 @@
"sass": "^1.69.5",
"svelte-check": "^3.6.2",
"tslib": "^2.4.1",
"typedoc-plugin-mdn-links": "^3.1.16",
"typescript": "^5.3.3",
"vite": "^5.0.7",
"vitest": "^1.0.4"
Expand Down
90 changes: 75 additions & 15 deletions src/lib/Crud/Operations.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,8 @@
/**
* Operations are a class system that allows you to determine what grids or forms you will display in your {@link Dashboard.DashboardDefinition | Dashboard}
* @module
*/

import type { FieldOptions, FieldInterface } from '$lib/FieldDefinitions/definition';
import type { CrudDefinition } from '$lib/Crud/definition';
import type { DashboardDefinition } from '$lib/Dashboard/definition';
Expand All @@ -6,6 +11,7 @@ import type { CrudTheme } from '$lib/themes/ThemeConfig';
import { defaultPaginationOptions, type PaginationOptions } from '$lib/DataTable/Pagination';
import type { FilterInterface, FilterOptions } from '$lib/Filter';

/** */
export type CrudOperationName =
| 'new'
| 'edit'
Expand All @@ -16,33 +22,57 @@ export type CrudOperationName =
| 'entity_list'
| string;

/** */
export interface CrudOperation {
readonly name: CrudOperationName;
readonly label: string;
readonly displayComponentName: CrudTheme;
readonly fields: Array<FieldInterface<FieldOptions>>;
readonly actions: Array<Action>;
readonly options: Record<string, string | unknown>;

/** */ readonly name: CrudOperationName;
/** */ readonly label: string;
/** */ readonly displayComponentName: CrudTheme;
/** */ readonly fields: Array<FieldInterface<FieldOptions>>;
/** */ readonly actions: Array<Action>;
/** */ readonly options: Record<string, string | unknown>;

/** */
get dashboard(): DashboardDefinition;
set dashboard(dashboard: DashboardDefinition);

/** */
get crud(): CrudDefinition<unknown>;
set crud(crud: CrudDefinition<unknown>);
}

export class BaseCrudOperation implements CrudOperation {
/**
* @abstract
*
* @remark
* This class allows you to create your own classes and extend the base operation
* in case you need something else than the built-in ones.
*
* @example
* export class PreviewOperation extends BaseCrudOperation {
* // Your custom code
* constructor(
* fields: Array<FieldInterface<FieldOptions>>,
* actions: Array<Action> = [],
* options: FormOperationOptions = DEFAULT_FORM_OPERATION_OPTION
* ) {
* super('preview', 'crud.preview.label', 'preview', fields, actions, options);
* }
* }
**/
export abstract class BaseCrudOperation implements CrudOperation {
private _dashboard: DashboardDefinition | null = null;
private _crud: CrudDefinition<unknown> | null = null;

constructor(
public readonly name: CrudOperationName,
public readonly label: string,
public readonly displayComponentName: CrudTheme,
public readonly fields: Array<FieldInterface<FieldOptions>>,
public readonly actions: Array<Action>,
public readonly options: Record<string, string | unknown> = {}
protected constructor(
/** */ public readonly name: CrudOperationName,
/** */ public readonly label: string,
/** */ public readonly displayComponentName: CrudTheme,
/** */ public readonly fields: Array<FieldInterface<FieldOptions>>,
/** */ public readonly actions: Array<Action>,
/** */ public readonly options: Record<string, string | unknown> = {}
) {}

/** */
get dashboard(): DashboardDefinition {
if (!this._dashboard) {
throw new Error('Dashboard is not set in operation: did you try to bypass Crud setup?');
Expand All @@ -60,6 +90,7 @@ export class BaseCrudOperation implements CrudOperation {
this._dashboard = dashboard;
}

/** */
get crud(): CrudDefinition<unknown> {
if (!this._crud) {
throw new Error('Crud is not set in operation: did you try to bypass Crud setup?');
Expand All @@ -75,14 +106,24 @@ export class BaseCrudOperation implements CrudOperation {
}
}

/**
* @see {@link New}
* @see {@link Edit}
**/
export type FormOperationOptions = object & {
preventHttpFormSubmit: boolean;
};
/** */
const DEFAULT_FORM_OPERATION_OPTION: FormOperationOptions = {
preventHttpFormSubmit: true
};

/**
* @group Built-in operations
* @category Built-in operations
*/
export class New extends BaseCrudOperation {
/** */
constructor(
fields: Array<FieldInterface<FieldOptions>>,
actions: Array<Action> = [],
Expand All @@ -92,7 +133,10 @@ export class New extends BaseCrudOperation {
}
}

/**
*/
export class Edit extends BaseCrudOperation {
/** */
constructor(
fields: Array<FieldInterface<FieldOptions>>,
actions: Array<Action> = [],
Expand All @@ -102,13 +146,19 @@ export class Edit extends BaseCrudOperation {
}
}

/**
* @see {@link List}
**/
export type ListOperationOptions = object & {
globalActions?: Array<Action>;
pagination?: Partial<PaginationOptions>;
filters?: FilterInterface<FilterOptions>[];
};

/**
*/
export class List extends BaseCrudOperation {
/** */
constructor(
fields: Array<FieldInterface<FieldOptions>>,
actions: Array<Action> = [],
Expand All @@ -120,22 +170,32 @@ export class List extends BaseCrudOperation {
}
}

/**
*/
export class Delete extends BaseCrudOperation {
/** */
public readonly redirectTo: Action;

/** */
constructor(fields: Array<FieldInterface<FieldOptions>>, redirectTo: Action) {
super('delete', 'crud.delete.label', 'delete', fields, []);
this.redirectTo = redirectTo;
}
}

/**
*/
export class View extends BaseCrudOperation {
/** */
constructor(fields: Array<FieldInterface<FieldOptions>>) {
super('view', 'crud.view.label', 'view', fields, []);
}
}

/**
*/
export class Field extends BaseCrudOperation {
/** */
constructor(name: CrudOperationName = 'field', options: Record<string, string | unknown> = {}) {
super(name, '', 'field', [], [], options);
}
Expand Down
52 changes: 43 additions & 9 deletions src/lib/Crud/definition.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,29 +3,62 @@ import type { StateProvider } from '$lib/State/Provider';
import type { StateProcessor } from '$lib/State/Processor';
import { type DashboardDefinition } from '$lib/Dashboard/definition';

export type CrudDefinitionOptionsArgument<T> = {
/** */
export type CrudDefinitionOptionsArgument<EntityType> = {
name: string;
label: {
singular: string;
plural: string;
};
defaultOperationName?: string;
identifierFieldName?: 'id' | string;

/**
* Will apply a default minimum timeout (in milliseconds) when running a {@link StateProvider} or {@link StateProcessor}.
* If this option is defined, and the provider or processor call's duration is below this value, it will still wait this amount of time before returning the actual provider/processor value.
*
* The goal of this is to avoid epilepsy-like issues if providers or processors respond too quickly, especially when dealing with List operations and filters.
* This will create a "wait time" for the end user, so that the screen does not blink too much and there eyes (and brain) will not be stressed too much.
*/
minStateLoadingTimeMs?: number;

operations: Array<CrudOperation>;
stateProvider: StateProvider<T>;
stateProcessor: StateProcessor<T>;
stateProvider: StateProvider<EntityType>;
stateProcessor: StateProcessor<EntityType>;
};

export type CrudDefinitionOptions<T> = Required<CrudDefinitionOptionsArgument<T>>;
export type CrudDefinitionOptions<EntityType> = Required<CrudDefinitionOptionsArgument<EntityType>>;

export class CrudDefinition<T> {
public readonly name: string;
public readonly options: CrudDefinitionOptions<T>;
/**
* Crud definition, object used to create an abstract Crud.
*
* @remarks
* Crud objects are related to a single Entity type,
* and contain several Crud Operations, as well as the main
* objects that care about persistence: state providers and processors.
*
* @example
* type Book = {id: number, title: string, description: string};
*
* const BooksCrud = new CrudDefinition<Book>({
* name: 'books',
* label: {singular: 'Book', plural: 'Books'},
* operations: [],
* stateProvider: ...,
* stateProcessor: ...,
* });
*
* @typeParam EntityType - The object type that will be used by providers and processors.
*/
export class CrudDefinition<EntityType> {
/** */ public readonly name: string;
/** */ public readonly options: CrudDefinitionOptions<EntityType>;
private _dashboard: DashboardDefinition | null = null;

constructor(options: CrudDefinitionOptionsArgument<T>) {
/**
* @param {CrudDefinitionOptionsArgument} options
**/
constructor(options: CrudDefinitionOptionsArgument<EntityType>) {
const name = options.name;
this.name = name;

Expand Down Expand Up @@ -57,9 +90,10 @@ export class CrudDefinition<T> {
options.defaultOperationName = defaultOperation.name;
options.identifierFieldName ??= 'id';

this.options = options as CrudDefinitionOptions<T>;
this.options = options as CrudDefinitionOptions<EntityType>;
}

/** */
get dashboard(): DashboardDefinition {
if (!this._dashboard) {
throw new Error('Dashboard is not set in Crud definition: did you try to bypass Crud setup?');
Expand Down
3 changes: 3 additions & 0 deletions src/lib/Crud/form.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,8 @@
export type SubmittedData = Record<string, FormDataEntryValue>;

/**
* Function to get an record of {@link FormDataEntryValue} items from an "onSubmit" form {@link SubmitEvent} object.
*/
export function getSubmittedFormData(event: SubmitEvent): SubmittedData {
const normalizedData: SubmittedData = {};

Expand Down
Loading

0 comments on commit 6c1e45f

Please sign in to comment.