@tailor-platform/sdk-plugin-app-shell 0.1.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/LICENSE.md ADDED
@@ -0,0 +1,21 @@
1
+ The MIT License (MIT)
2
+
3
+ Copyright © 2025 Tailor Inc.
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in
13
+ all copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21
+ THE SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,64 @@
1
+ # @tailor-platform/sdk-plugin-app-shell
2
+
3
+ Tailor Platform SDK plugin that generates `tableMetadata` from TailorDB table definitions for use with `@tailor-platform/app-shell`'s `DataTable` component.
4
+
5
+ ## What it does
6
+
7
+ `tableMetadata` bridges your TailorDB schema to the DataTable. It tells `inferColumns` how to render and filter each field — for example, which fields get a date picker, which get an enum dropdown (and with what options), and which are numeric. Without it, you would need to declare all of this manually per column.
8
+
9
+ The metadata is generated at SDK generate time from your TailorDB table definitions, so it stays in sync with your schema automatically.
10
+
11
+ ## Installation
12
+
13
+ ```sh
14
+ pnpm add -D @tailor-platform/sdk-plugin-app-shell
15
+ ```
16
+
17
+ ## Setup
18
+
19
+ Supports `@tailor-platform/sdk` `^1 || ^2`. The examples below use the v2 CLI and TailorDB table API.
20
+
21
+ Register the plugin in `tailor.config.ts`:
22
+
23
+ ```ts
24
+ import { definePlugins } from "@tailor-platform/sdk";
25
+ import { appShellPlugin } from "@tailor-platform/sdk-plugin-app-shell";
26
+
27
+ export const plugins = definePlugins(
28
+ appShellPlugin({
29
+ dataTable: {
30
+ metadataOutputPath: "src/generated/app-shell-datatable.generated.ts",
31
+ },
32
+ }),
33
+ );
34
+ ```
35
+
36
+ Then run `tailor generate` to produce the metadata file.
37
+
38
+ ## Usage
39
+
40
+ Pass `tableMetadata` to `inferColumns` to get type-safe column definitions with filter editors automatically configured:
41
+
42
+ ```ts
43
+ import { tableMetadata } from "@/generated/app-shell-datatable.generated";
44
+ import { createColumnHelper } from "@tailor-platform/app-shell";
45
+
46
+ const { column, inferColumns } = createColumnHelper<Order>();
47
+ const infer = inferColumns(tableMetadata.order);
48
+
49
+ const columns = [
50
+ column(infer("title")), // string column → text filter
51
+ column(infer("status")), // enum column → dropdown filter with generated values
52
+ column(infer("createdAt")), // datetime column → date picker filter
53
+ ];
54
+ ```
55
+
56
+ You can still override per-column defaults when needed. For example, pass a non-empty `filter.operators` allowlist to narrow the built-in DataTable filter UI for one field:
57
+
58
+ ```ts
59
+ const columns = [column(infer("title", { filter: { operators: ["contains", "eq"] } }))];
60
+ ```
61
+
62
+ `operators` only affects the built-in DataTable filter UI. Programmatic `CollectionControl.addFilter(...)`, URL state, and saved/persisted filters still use the broader backend operator set.
63
+
64
+ For full `DataTable` usage, see [`@tailor-platform/app-shell`](../core/README.md).
@@ -0,0 +1,17 @@
1
+ import { Plugin } from "@tailor-platform/sdk";
2
+ //#region src/plugin.d.ts
3
+ /**
4
+ * Options for the AppShell plugin.
5
+ */
6
+ interface AppShellPluginOptions {
7
+ dataTable?: {
8
+ /**
9
+ * Output file path for generated DataTable metadata (relative to project root).
10
+ * @default "app-shell-datatable.generated.ts"
11
+ */
12
+ metadataOutputPath?: string;
13
+ };
14
+ }
15
+ declare function appShellPlugin(options?: AppShellPluginOptions): Plugin<void, AppShellPluginOptions>;
16
+ //#endregion
17
+ export { type AppShellPluginOptions, appShellPlugin };
package/dist/index.mjs ADDED
@@ -0,0 +1,119 @@
1
+ //#region src/plugin.ts
2
+ /**
3
+ * Map TailorDB field type to AppShell FieldType.
4
+ */
5
+ function mapFieldType(tailorType, isArray) {
6
+ const mappedType = {
7
+ string: "string",
8
+ integer: "number",
9
+ float: "number",
10
+ decimal: "number",
11
+ boolean: "boolean",
12
+ uuid: "uuid",
13
+ datetime: "datetime",
14
+ date: "date",
15
+ time: "time",
16
+ enum: "enum",
17
+ nested: "nested",
18
+ file: "file"
19
+ }[tailorType] ?? "string";
20
+ if (isArray) return {
21
+ type: "array",
22
+ arrayItemType: mappedType
23
+ };
24
+ return { type: mappedType };
25
+ }
26
+ /**
27
+ * Convert PascalCase to camelCase.
28
+ */
29
+ function toCamelCase(str) {
30
+ return str.charAt(0).toLowerCase() + str.slice(1);
31
+ }
32
+ function appShellPlugin(options = {}) {
33
+ const { metadataOutputPath = "app-shell-datatable.generated.ts" } = options.dataTable ?? {};
34
+ return {
35
+ id: "app-shell-metadata",
36
+ description: "Generates table metadata for AppShell DataTable (inferColumns, createColumnHelper)",
37
+ pluginConfig: options,
38
+ onTailorDBReady(context) {
39
+ const metadataMap = {};
40
+ for (const ns of context.tailordb) {
41
+ const schemaEntries = "tables" in ns ? ns.tables : ns.types;
42
+ for (const type of Object.values(schemaEntries)) {
43
+ const fields = [];
44
+ const relations = [];
45
+ for (const [fieldName, field] of Object.entries(type.fields)) {
46
+ const config = field.config;
47
+ const { type: fieldType, arrayItemType } = mapFieldType(config.type, config.array);
48
+ let fieldRelation;
49
+ if (config.rawRelation) {
50
+ const raw = config.rawRelation;
51
+ if ((raw.type === "manyToOne" || raw.type === "n-1" || raw.type === "N-1" || raw.type === "oneToOne" || raw.type === "1-1") && raw.toward) {
52
+ const targetName = raw.toward.table ?? raw.toward.type;
53
+ if (targetName) {
54
+ const targetTableName = toCamelCase(targetName);
55
+ fieldRelation = {
56
+ fieldName: raw.toward.as ?? targetTableName,
57
+ targetTable: targetTableName
58
+ };
59
+ }
60
+ }
61
+ }
62
+ const enumValues = config.allowedValues && config.allowedValues.length > 0 ? config.allowedValues.map((v) => typeof v === "string" ? v : v.value) : void 0;
63
+ const fieldMetadata = {
64
+ name: fieldName,
65
+ type: fieldType,
66
+ required: config.required ?? false,
67
+ ...config.description && { description: config.description },
68
+ ...enumValues && { enumValues },
69
+ ...arrayItemType && { arrayItemType },
70
+ ...fieldRelation && { relation: fieldRelation }
71
+ };
72
+ fields.push(fieldMetadata);
73
+ }
74
+ for (const [relName, rel] of Object.entries(type.forwardRelationships ?? {})) {
75
+ const fkField = type.fields[rel.sourceField];
76
+ const isOneToOne = fkField?.config.rawRelation?.type === "1-1" || fkField?.config.rawRelation?.type === "oneToOne";
77
+ relations.push({
78
+ fieldName: relName,
79
+ targetTable: toCamelCase(rel.targetType),
80
+ relationType: isOneToOne ? "oneToOne" : "manyToOne",
81
+ foreignKeyField: rel.sourceField
82
+ });
83
+ }
84
+ for (const [relName, rel] of Object.entries(type.backwardRelationships ?? {})) relations.push({
85
+ fieldName: relName,
86
+ targetTable: toCamelCase(rel.targetType),
87
+ relationType: "oneToMany",
88
+ foreignKeyField: rel.sourceField
89
+ });
90
+ const camelName = toCamelCase(type.name);
91
+ metadataMap[camelName] = {
92
+ name: camelName,
93
+ pluralForm: toCamelCase(type.pluralForm),
94
+ ...type.description && { description: type.description },
95
+ fields,
96
+ ...relations.length > 0 && { relations }
97
+ };
98
+ }
99
+ }
100
+ const content = [
101
+ "// This file is auto-generated by app-shell-metadata plugin",
102
+ "// Do not edit manually",
103
+ "",
104
+ `export const tableMetadata = ${JSON.stringify(metadataMap, null, 2)} as const;`,
105
+ "",
106
+ `export const tableNames = ${JSON.stringify(Object.keys(metadataMap), null, 2)} as const;`,
107
+ "",
108
+ `export type TableName = (typeof tableNames)[number];`,
109
+ ""
110
+ ].join("\n");
111
+ return { files: [{
112
+ path: metadataOutputPath,
113
+ content
114
+ }] };
115
+ }
116
+ };
117
+ }
118
+ //#endregion
119
+ export { appShellPlugin };
package/package.json ADDED
@@ -0,0 +1,54 @@
1
+ {
2
+ "name": "@tailor-platform/sdk-plugin-app-shell",
3
+ "version": "0.1.1",
4
+ "description": "Tailor Platform SDK plugins for AppShell (metadata generator)",
5
+ "keywords": [
6
+ "app-shell",
7
+ "metadata-generator",
8
+ "sdk-plugin",
9
+ "tailor-platform"
10
+ ],
11
+ "homepage": "https://github.com/tailor-platform/app-shell/tree/main/packages/sdk-plugin#readme",
12
+ "bugs": {
13
+ "url": "https://github.com/tailor-platform"
14
+ },
15
+ "license": "MIT",
16
+ "repository": {
17
+ "type": "git",
18
+ "url": "https://github.com/tailor-platform/app-shell",
19
+ "directory": "packages/sdk-plugin"
20
+ },
21
+ "files": [
22
+ "dist/**"
23
+ ],
24
+ "type": "module",
25
+ "exports": {
26
+ ".": {
27
+ "types": "./dist/index.d.mts",
28
+ "default": "./dist/index.mjs"
29
+ }
30
+ },
31
+ "publishConfig": {
32
+ "access": "public"
33
+ },
34
+ "dependencies": {},
35
+ "devDependencies": {
36
+ "@tailor-platform/sdk": "^2.7.0",
37
+ "@tailor-platform/sdk-v1": "npm:@tailor-platform/sdk@1.85.1",
38
+ "oxlint": "^1.64.0",
39
+ "tsdown": "^0.22.14",
40
+ "typescript": "5.9.3",
41
+ "vitest": "^4.1.10",
42
+ "@tailor-platform/app-shell": "1.13.0"
43
+ },
44
+ "peerDependencies": {
45
+ "@tailor-platform/sdk": "^1.0.0 || ^2.0.0"
46
+ },
47
+ "scripts": {
48
+ "dev": "tsdown --watch",
49
+ "build": "tsdown",
50
+ "lint": "oxlint -c .oxlintrc.jsonc",
51
+ "test": "vitest run",
52
+ "type-check": "tsc --incremental"
53
+ }
54
+ }