@datamagik/cli 0.1.0
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 +21 -0
- package/assets/dm-script-globals.d.ts +181 -0
- package/dist/api.d.ts +247 -0
- package/dist/api.js +200 -0
- package/dist/api.js.map +1 -0
- package/dist/commands/add.d.ts +28 -0
- package/dist/commands/add.js +260 -0
- package/dist/commands/add.js.map +1 -0
- package/dist/commands/dev.d.ts +25 -0
- package/dist/commands/dev.js +113 -0
- package/dist/commands/dev.js.map +1 -0
- package/dist/commands/init.d.ts +23 -0
- package/dist/commands/init.js +136 -0
- package/dist/commands/init.js.map +1 -0
- package/dist/commands/login.d.ts +16 -0
- package/dist/commands/login.js +42 -0
- package/dist/commands/login.js.map +1 -0
- package/dist/commands/publish.d.ts +23 -0
- package/dist/commands/publish.js +113 -0
- package/dist/commands/publish.js.map +1 -0
- package/dist/commands/script.d.ts +69 -0
- package/dist/commands/script.js +289 -0
- package/dist/commands/script.js.map +1 -0
- package/dist/commands/sql.d.ts +28 -0
- package/dist/commands/sql.js +124 -0
- package/dist/commands/sql.js.map +1 -0
- package/dist/commands/typegen.d.ts +13 -0
- package/dist/commands/typegen.js +50 -0
- package/dist/commands/typegen.js.map +1 -0
- package/dist/config.d.ts +45 -0
- package/dist/config.js +118 -0
- package/dist/config.js.map +1 -0
- package/dist/credentials.d.ts +17 -0
- package/dist/credentials.js +49 -0
- package/dist/credentials.js.map +1 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.js +268 -0
- package/dist/index.js.map +1 -0
- package/dist/scriptfile.d.ts +10 -0
- package/dist/scriptfile.js +91 -0
- package/dist/scriptfile.js.map +1 -0
- package/dist/sqlfile.d.ts +9 -0
- package/dist/sqlfile.js +75 -0
- package/dist/sqlfile.js.map +1 -0
- package/dist/typegen/emit.d.ts +22 -0
- package/dist/typegen/emit.js +255 -0
- package/dist/typegen/emit.js.map +1 -0
- package/dist/typegen/meta.d.ts +84 -0
- package/dist/typegen/meta.js +209 -0
- package/dist/typegen/meta.js.map +1 -0
- package/package.json +35 -0
- package/templates/showcase/README.md +55 -0
- package/templates/showcase/_gitignore +4 -0
- package/templates/showcase/dm.config.json +16 -0
- package/templates/showcase/env.d.ts +7 -0
- package/templates/showcase/index.html +12 -0
- package/templates/showcase/package.json +25 -0
- package/templates/showcase/src/App.vue +67 -0
- package/templates/showcase/src/assets/datamagik-logo.png +0 -0
- package/templates/showcase/src/components/ShowcasePanel.vue +47 -0
- package/templates/showcase/src/components/panels/ContextPanel.vue +35 -0
- package/templates/showcase/src/components/panels/NavigatePanel.vue +38 -0
- package/templates/showcase/src/components/panels/OutputPanel.vue +50 -0
- package/templates/showcase/src/components/panels/PrintPanel.vue +68 -0
- package/templates/showcase/src/components/panels/QueryPanel.vue +52 -0
- package/templates/showcase/src/components/panels/ScriptPanel.vue +55 -0
- package/templates/showcase/src/components/panels/SerialPanel.vue +64 -0
- package/templates/showcase/src/dm-script-types.d.ts +13 -0
- package/templates/showcase/src/dm.generated.ts +65 -0
- package/templates/showcase/src/format.ts +13 -0
- package/templates/showcase/src/main.ts +5 -0
- package/templates/showcase/src/style.css +134 -0
- package/templates/showcase/tsconfig.json +17 -0
- package/templates/showcase/vite.config.ts +9 -0
- package/templates/simple/README.md +37 -0
- package/templates/simple/_gitignore +4 -0
- package/templates/simple/dm.config.json +10 -0
- package/templates/simple/env.d.ts +7 -0
- package/templates/simple/index.html +12 -0
- package/templates/simple/package.json +25 -0
- package/templates/simple/src/App.vue +71 -0
- package/templates/simple/src/dm.generated.ts +32 -0
- package/templates/simple/src/main.ts +5 -0
- package/templates/simple/src/style.css +63 -0
- package/templates/simple/tsconfig.json +17 -0
- package/templates/simple/vite.config.ts +9 -0
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
/* eslint-disable */
|
|
2
|
+
// ----------------------------------------------------------------------------
|
|
3
|
+
// Generated by `dm typegen` — DO NOT EDIT.
|
|
4
|
+
// This is a starter STUB so the showcase type-checks before you connect. Set a
|
|
5
|
+
// real "appId" + resource ids in dm.config.json (use `dm add`) and run
|
|
6
|
+
// `dm typegen`; that overwrites this file with types fetched from your tenant.
|
|
7
|
+
// ----------------------------------------------------------------------------
|
|
8
|
+
import { createDm } from '@datamagik/app-sdk';
|
|
9
|
+
import type { AliasRegistry, ScriptTypeOf } from '@datamagik/app-sdk';
|
|
10
|
+
|
|
11
|
+
/** Row of lookup table "Parts" (replaced by real columns on `dm typegen`). */
|
|
12
|
+
export interface PartsRow {
|
|
13
|
+
display_text: string;
|
|
14
|
+
unit_cost: number;
|
|
15
|
+
[key: string]: unknown;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
/** Parameters of ODBC query "Open Orders". */
|
|
19
|
+
export interface OpenOrdersParams {
|
|
20
|
+
status?: string;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
/** Row of ODBC query "Open Orders" — columns are not statically declared. */
|
|
24
|
+
export type OpenOrdersRow = Record<string, unknown>;
|
|
25
|
+
|
|
26
|
+
/** Generation context for serial series "Lot Serial". */
|
|
27
|
+
export interface LotSerialContext {
|
|
28
|
+
PART?: string;
|
|
29
|
+
LINE?: string;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
/**
|
|
33
|
+
* Typed alias surface for this app. Passed as the generic of `createDm` so
|
|
34
|
+
* every alias autocompletes in any TypeScript-aware editor.
|
|
35
|
+
*/
|
|
36
|
+
export interface DmGenerated {
|
|
37
|
+
tables: {
|
|
38
|
+
parts: PartsRow;
|
|
39
|
+
};
|
|
40
|
+
odbc: {
|
|
41
|
+
openOrders: { params: OpenOrdersParams; row: OpenOrdersRow };
|
|
42
|
+
};
|
|
43
|
+
scripts: {
|
|
44
|
+
// IO comes from the DmScriptTypes augmentation in src/dm-script-types.d.ts.
|
|
45
|
+
postReceipt: ScriptTypeOf<'postReceipt'>;
|
|
46
|
+
};
|
|
47
|
+
serials: {
|
|
48
|
+
lotSerial: { context: LotSerialContext };
|
|
49
|
+
};
|
|
50
|
+
printers: {
|
|
51
|
+
line1Zebra: { formats: 'zpl' | 'html' };
|
|
52
|
+
};
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
/** Runtime alias → { type, id } registry (placeholder ids — replace via `dm add`). */
|
|
56
|
+
export const dmRegistry: AliasRegistry = {
|
|
57
|
+
line1Zebra: { type: 'printer', id: 1 },
|
|
58
|
+
lotSerial: { type: 'serial_series', id: 1 },
|
|
59
|
+
openOrders: { type: 'odbc_query', id: 2 },
|
|
60
|
+
parts: { type: 'lookup_table', id: 1 },
|
|
61
|
+
postReceipt: { type: 'script', id: 3 },
|
|
62
|
+
};
|
|
63
|
+
|
|
64
|
+
/** Ready-to-use, fully typed SDK instance for this app. */
|
|
65
|
+
export const dm = createDm<DmGenerated>(dmRegistry);
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { DmError } from '@datamagik/app-sdk';
|
|
2
|
+
|
|
3
|
+
/** Human-readable one-liner for any thrown value. */
|
|
4
|
+
export function fmtErr(e: unknown): string {
|
|
5
|
+
if (e instanceof DmError) return `${e.code}: ${e.message}`;
|
|
6
|
+
if (e instanceof Error) return e.message;
|
|
7
|
+
return String(e);
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
/** Pretty-print a value for a result box. */
|
|
11
|
+
export function pretty(v: unknown): string {
|
|
12
|
+
return typeof v === 'string' ? v : JSON.stringify(v, null, 2);
|
|
13
|
+
}
|
|
@@ -0,0 +1,134 @@
|
|
|
1
|
+
:root {
|
|
2
|
+
/* DataMagik brand palette (matches the platform). */
|
|
3
|
+
--dm-purple: #9333ea;
|
|
4
|
+
--dm-purple-light: #a855f7;
|
|
5
|
+
--dm-purple-dark: #7e22ce;
|
|
6
|
+
--dm-purple-50: #faf5ff;
|
|
7
|
+
--dm-purple-100: #f3e8ff;
|
|
8
|
+
|
|
9
|
+
--dm-bg: #f9fafb;
|
|
10
|
+
--dm-card: #ffffff;
|
|
11
|
+
--dm-border: #e5e7eb;
|
|
12
|
+
--dm-border-soft: #f3f4f6;
|
|
13
|
+
|
|
14
|
+
--dm-ink: #111827;
|
|
15
|
+
--dm-ink-soft: #6b7280;
|
|
16
|
+
--dm-ink-faint: #9ca3af;
|
|
17
|
+
|
|
18
|
+
--dm-ok: #059669;
|
|
19
|
+
--dm-ok-bg: #ecfdf5;
|
|
20
|
+
--dm-ok-border: #a7f3d0;
|
|
21
|
+
--dm-err: #dc2626;
|
|
22
|
+
--dm-err-bg: #fef2f2;
|
|
23
|
+
--dm-err-border: #fecaca;
|
|
24
|
+
|
|
25
|
+
--dm-code-bg: #1e1b2e;
|
|
26
|
+
--dm-code-ink: #e9d5ff;
|
|
27
|
+
|
|
28
|
+
font-family: system-ui, -apple-system, "Segoe UI", Roboto, Helvetica, Arial, sans-serif;
|
|
29
|
+
color: var(--dm-ink);
|
|
30
|
+
-webkit-font-smoothing: antialiased;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
* { box-sizing: border-box; }
|
|
34
|
+
body { margin: 0; background: var(--dm-bg); }
|
|
35
|
+
code { font-family: ui-monospace, "SF Mono", Menlo, Consolas, monospace; }
|
|
36
|
+
|
|
37
|
+
.shell { max-width: 1040px; margin: 0 auto; padding: 1.5rem 1rem 4rem; }
|
|
38
|
+
|
|
39
|
+
/* ---- Header ---- */
|
|
40
|
+
.app-header {
|
|
41
|
+
display: flex; align-items: center; gap: 1rem;
|
|
42
|
+
background: linear-gradient(135deg, var(--dm-purple), var(--dm-purple-dark));
|
|
43
|
+
color: #fff; border-radius: 1rem; padding: 1.25rem 1.5rem;
|
|
44
|
+
box-shadow: 0 10px 25px -10px rgba(147, 51, 234, 0.5);
|
|
45
|
+
}
|
|
46
|
+
.app-header img.logo { height: 38px; width: auto; }
|
|
47
|
+
.app-header .titles { min-width: 0; flex: 1; }
|
|
48
|
+
.app-header h1 { font-size: 1.4rem; font-weight: 700; margin: 0; line-height: 1.2; }
|
|
49
|
+
.app-header p { margin: 0.15rem 0 0; font-size: 0.85rem; color: rgba(255, 255, 255, 0.85); }
|
|
50
|
+
.app-header .status {
|
|
51
|
+
display: inline-flex; align-items: center; gap: 0.45rem;
|
|
52
|
+
background: rgba(255, 255, 255, 0.15); border: 1px solid rgba(255, 255, 255, 0.25);
|
|
53
|
+
border-radius: 999px; padding: 0.35rem 0.75rem; font-size: 0.8rem; font-weight: 600;
|
|
54
|
+
white-space: nowrap;
|
|
55
|
+
}
|
|
56
|
+
.status .dot { width: 0.55rem; height: 0.55rem; border-radius: 50%; background: #fde68a; }
|
|
57
|
+
.status .dot.ok { background: #6ee7b7; }
|
|
58
|
+
.status .dot.err { background: #fca5a5; }
|
|
59
|
+
|
|
60
|
+
.notice {
|
|
61
|
+
margin: 1rem 0 0; padding: 0.75rem 1rem; font-size: 0.85rem;
|
|
62
|
+
background: var(--dm-purple-50); border: 1px solid var(--dm-purple-100);
|
|
63
|
+
color: #6b21a8; border-radius: 0.75rem;
|
|
64
|
+
}
|
|
65
|
+
.notice code { color: var(--dm-purple-dark); font-weight: 600; }
|
|
66
|
+
|
|
67
|
+
/* ---- Panel grid ---- */
|
|
68
|
+
.grid {
|
|
69
|
+
display: grid; gap: 1rem; margin-top: 1.25rem;
|
|
70
|
+
grid-template-columns: repeat(auto-fill, minmax(320px, 1fr));
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
.panel {
|
|
74
|
+
background: var(--dm-card); border: 1px solid var(--dm-border-soft);
|
|
75
|
+
border-radius: 0.85rem; padding: 1.1rem 1.15rem;
|
|
76
|
+
box-shadow: 0 1px 2px rgba(0, 0, 0, 0.04); display: flex; flex-direction: column;
|
|
77
|
+
}
|
|
78
|
+
.panel-head { display: flex; align-items: center; gap: 0.6rem; margin-bottom: 0.35rem; }
|
|
79
|
+
.panel-icon {
|
|
80
|
+
width: 2rem; height: 2rem; border-radius: 0.55rem; flex: none;
|
|
81
|
+
display: flex; align-items: center; justify-content: center;
|
|
82
|
+
background: var(--dm-purple-50); color: var(--dm-purple);
|
|
83
|
+
}
|
|
84
|
+
.panel-icon svg { width: 1.05rem; height: 1.05rem; }
|
|
85
|
+
.panel h2 { font-size: 0.98rem; font-weight: 700; margin: 0; }
|
|
86
|
+
.panel .desc { font-size: 0.83rem; color: var(--dm-ink-soft); margin: 0 0 0.75rem; }
|
|
87
|
+
|
|
88
|
+
.code {
|
|
89
|
+
background: var(--dm-code-bg); color: var(--dm-code-ink);
|
|
90
|
+
border-radius: 0.55rem; padding: 0.65rem 0.75rem; margin: 0 0 0.75rem;
|
|
91
|
+
font-family: ui-monospace, "SF Mono", Menlo, Consolas, monospace;
|
|
92
|
+
font-size: 0.78rem; line-height: 1.5; white-space: pre; overflow-x: auto;
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
.controls { display: flex; flex-wrap: wrap; gap: 0.5rem; align-items: center; margin-bottom: 0.6rem; }
|
|
96
|
+
|
|
97
|
+
.btn {
|
|
98
|
+
background: linear-gradient(135deg, var(--dm-purple), var(--dm-purple-dark));
|
|
99
|
+
color: #fff; border: none; border-radius: 0.5rem;
|
|
100
|
+
padding: 0.45rem 0.9rem; font-size: 0.82rem; font-weight: 600; cursor: pointer;
|
|
101
|
+
}
|
|
102
|
+
.btn:hover { filter: brightness(1.05); }
|
|
103
|
+
.btn:disabled { opacity: 0.5; cursor: default; filter: none; }
|
|
104
|
+
.btn.secondary {
|
|
105
|
+
background: #fff; color: var(--dm-purple-dark);
|
|
106
|
+
border: 1px solid var(--dm-border);
|
|
107
|
+
}
|
|
108
|
+
.btn.secondary:hover { background: var(--dm-purple-50); }
|
|
109
|
+
|
|
110
|
+
input.text {
|
|
111
|
+
border: 1px solid var(--dm-border); border-radius: 0.5rem;
|
|
112
|
+
padding: 0.4rem 0.6rem; font-size: 0.82rem; min-width: 0; flex: 1;
|
|
113
|
+
}
|
|
114
|
+
input.text:focus { outline: 2px solid var(--dm-purple-light); border-color: var(--dm-purple); }
|
|
115
|
+
|
|
116
|
+
.result {
|
|
117
|
+
margin-top: auto; font-size: 0.82rem; border-radius: 0.55rem;
|
|
118
|
+
padding: 0.6rem 0.7rem; background: var(--dm-ok-bg);
|
|
119
|
+
border: 1px solid var(--dm-ok-border); color: #065f46;
|
|
120
|
+
white-space: pre-wrap; word-break: break-word; max-height: 180px; overflow: auto;
|
|
121
|
+
}
|
|
122
|
+
.result.err { background: var(--dm-err-bg); border-color: var(--dm-err-border); color: var(--dm-err); }
|
|
123
|
+
.result.hint { background: var(--dm-purple-50); border-color: var(--dm-purple-100); color: #6b21a8; }
|
|
124
|
+
|
|
125
|
+
.kv { display: grid; grid-template-columns: max-content 1fr; gap: 0.2rem 0.9rem; font-size: 0.83rem; }
|
|
126
|
+
.kv dt { color: var(--dm-ink-soft); }
|
|
127
|
+
.kv dd { margin: 0; font-weight: 500; word-break: break-word; }
|
|
128
|
+
|
|
129
|
+
ul.rows { list-style: none; padding: 0; margin: 0.25rem 0 0; font-size: 0.82rem; }
|
|
130
|
+
ul.rows li { padding: 0.3rem 0; border-bottom: 1px solid var(--dm-border-soft); }
|
|
131
|
+
ul.rows li:last-child { border-bottom: none; }
|
|
132
|
+
|
|
133
|
+
.footer { margin-top: 2rem; text-align: center; font-size: 0.78rem; color: var(--dm-ink-faint); }
|
|
134
|
+
.footer a { color: var(--dm-purple); text-decoration: none; }
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
{
|
|
2
|
+
"compilerOptions": {
|
|
3
|
+
"target": "ES2022",
|
|
4
|
+
"module": "ESNext",
|
|
5
|
+
"moduleResolution": "Bundler",
|
|
6
|
+
"lib": ["ES2022", "DOM", "DOM.Iterable"],
|
|
7
|
+
"strict": true,
|
|
8
|
+
"noEmit": true,
|
|
9
|
+
"jsx": "preserve",
|
|
10
|
+
"skipLibCheck": true,
|
|
11
|
+
"esModuleInterop": true,
|
|
12
|
+
"isolatedModules": true,
|
|
13
|
+
"verbatimModuleSyntax": true,
|
|
14
|
+
"types": []
|
|
15
|
+
},
|
|
16
|
+
"include": ["src", "env.d.ts"]
|
|
17
|
+
}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { defineConfig } from 'vite';
|
|
2
|
+
import vue from '@vitejs/plugin-vue';
|
|
3
|
+
|
|
4
|
+
// base './' is required: published bundles are served under a signed token
|
|
5
|
+
// path prefix, so every asset URL must stay relative.
|
|
6
|
+
export default defineConfig({
|
|
7
|
+
base: './',
|
|
8
|
+
plugins: [vue()],
|
|
9
|
+
});
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
# __APP_NAME__
|
|
2
|
+
|
|
3
|
+
A minimal DataMagik SPA app (Vue 3 + Vite + `@datamagik/app-sdk`). It connects
|
|
4
|
+
to the platform, shows the app context, and runs one lookup-table query.
|
|
5
|
+
|
|
6
|
+
## Get started
|
|
7
|
+
|
|
8
|
+
```bash
|
|
9
|
+
npm install
|
|
10
|
+
# set "appId" in dm.config.json to your application id (App Studio header)
|
|
11
|
+
npx dm login --url https://staging.data-magik.com # or https://data-magik.com
|
|
12
|
+
npx dm dev # run it now — uses the bundled demo types
|
|
13
|
+
```
|
|
14
|
+
|
|
15
|
+
## Add real resources
|
|
16
|
+
|
|
17
|
+
The starter ships a placeholder `parts` lookup table. Replace it with your own:
|
|
18
|
+
|
|
19
|
+
```bash
|
|
20
|
+
npx dm add lookup_table # search the tenant, pick one, name an alias
|
|
21
|
+
# remove the placeholder `parts` entry from dm.config.json, then:
|
|
22
|
+
npx dm typegen # refresh the typed surface (src/dm.generated.ts)
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
`dm add` also handles ODBC queries, scripts, serial series, and printers.
|
|
26
|
+
|
|
27
|
+
## Ship it
|
|
28
|
+
|
|
29
|
+
```bash
|
|
30
|
+
npx dm publish --message "first version" # builds and goes live immediately
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
## Files
|
|
34
|
+
|
|
35
|
+
- `dm.config.json` — your app id + declared resources (commit it).
|
|
36
|
+
- `src/dm.generated.ts` — typed alias surface, regenerated by `dm typegen` (commit it).
|
|
37
|
+
- `src/App.vue` — the app.
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
<!doctype html>
|
|
2
|
+
<html lang="en">
|
|
3
|
+
<head>
|
|
4
|
+
<meta charset="UTF-8" />
|
|
5
|
+
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
|
6
|
+
<title>__APP_NAME__ — DataMagik</title>
|
|
7
|
+
</head>
|
|
8
|
+
<body>
|
|
9
|
+
<div id="app"></div>
|
|
10
|
+
<script type="module" src="/src/main.ts"></script>
|
|
11
|
+
</body>
|
|
12
|
+
</html>
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "__PKG_NAME__",
|
|
3
|
+
"private": true,
|
|
4
|
+
"version": "0.1.0",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"scripts": {
|
|
7
|
+
"dev": "dm dev",
|
|
8
|
+
"build": "vue-tsc --noEmit -p tsconfig.json && vite build",
|
|
9
|
+
"typecheck": "vue-tsc --noEmit -p tsconfig.json",
|
|
10
|
+
"preview": "vite preview",
|
|
11
|
+
"typegen": "dm typegen",
|
|
12
|
+
"deploy": "dm publish"
|
|
13
|
+
},
|
|
14
|
+
"dependencies": {
|
|
15
|
+
"@datamagik/app-sdk": "^0.1.0",
|
|
16
|
+
"vue": "^3.5.13"
|
|
17
|
+
},
|
|
18
|
+
"devDependencies": {
|
|
19
|
+
"@datamagik/cli": "^0.1.0",
|
|
20
|
+
"@vitejs/plugin-vue": "^5.2.0",
|
|
21
|
+
"typescript": "^5.6.0",
|
|
22
|
+
"vite": "^6.3.5",
|
|
23
|
+
"vue-tsc": "^2.2.0"
|
|
24
|
+
}
|
|
25
|
+
}
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
<script setup lang="ts">
|
|
2
|
+
import { onMounted, ref } from 'vue';
|
|
3
|
+
import { DmError } from '@datamagik/app-sdk';
|
|
4
|
+
import type { DmContext } from '@datamagik/app-sdk';
|
|
5
|
+
import { dm } from './dm.generated';
|
|
6
|
+
import type { PartsRow } from './dm.generated';
|
|
7
|
+
|
|
8
|
+
const status = ref<'connecting' | 'ok' | 'error'>('connecting');
|
|
9
|
+
const ctx = ref<DmContext | null>(null);
|
|
10
|
+
const rows = ref<PartsRow[]>([]);
|
|
11
|
+
const dataError = ref('');
|
|
12
|
+
const fatal = ref('');
|
|
13
|
+
|
|
14
|
+
onMounted(async () => {
|
|
15
|
+
try {
|
|
16
|
+
ctx.value = await dm.init();
|
|
17
|
+
status.value = 'ok';
|
|
18
|
+
} catch (e) {
|
|
19
|
+
status.value = 'error';
|
|
20
|
+
fatal.value = e instanceof DmError ? `${e.code}: ${e.message}` : String(e);
|
|
21
|
+
return;
|
|
22
|
+
}
|
|
23
|
+
try {
|
|
24
|
+
const result = await dm.data.query('parts', { pageSize: 25 });
|
|
25
|
+
rows.value = result.rows;
|
|
26
|
+
} catch (e) {
|
|
27
|
+
// The starter declares a placeholder `parts` id. Wire a real lookup table
|
|
28
|
+
// with `dm add lookup_table` (then `dm typegen`) to see live data here.
|
|
29
|
+
dataError.value = e instanceof DmError ? `${e.code}: ${e.message}` : String(e);
|
|
30
|
+
}
|
|
31
|
+
});
|
|
32
|
+
|
|
33
|
+
function rowText(row: PartsRow): string {
|
|
34
|
+
return typeof row.display_text === 'string' ? row.display_text : JSON.stringify(row);
|
|
35
|
+
}
|
|
36
|
+
</script>
|
|
37
|
+
|
|
38
|
+
<template>
|
|
39
|
+
<header>
|
|
40
|
+
<span class="dot" :class="{ ok: status === 'ok', err: status === 'error' }"></span>
|
|
41
|
+
<h1>{{ ctx?.appName || '__APP_NAME__' }}</h1>
|
|
42
|
+
</header>
|
|
43
|
+
|
|
44
|
+
<div class="card">
|
|
45
|
+
<h2>Connection</h2>
|
|
46
|
+
<p v-if="status === 'connecting'" class="muted">Connecting to the platform…</p>
|
|
47
|
+
<dl v-else-if="ctx" class="kv">
|
|
48
|
+
<dt>App</dt>
|
|
49
|
+
<dd>{{ ctx.appName }} (v{{ ctx.version }})</dd>
|
|
50
|
+
<dt>Surface</dt>
|
|
51
|
+
<dd>{{ ctx.surface }}</dd>
|
|
52
|
+
<dt>User</dt>
|
|
53
|
+
<dd>{{ ctx.user.name }}</dd>
|
|
54
|
+
<dt>Company</dt>
|
|
55
|
+
<dd>{{ ctx.company.name }}</dd>
|
|
56
|
+
</dl>
|
|
57
|
+
<p v-else class="error">{{ fatal }}</p>
|
|
58
|
+
</div>
|
|
59
|
+
|
|
60
|
+
<div class="card">
|
|
61
|
+
<h2><code>parts</code> — lookup table query</h2>
|
|
62
|
+
<ul v-if="rows.length" class="rows">
|
|
63
|
+
<li v-for="(row, i) in rows" :key="i">{{ rowText(row) }}</li>
|
|
64
|
+
</ul>
|
|
65
|
+
<p v-else-if="dataError" class="error">
|
|
66
|
+
No data yet — {{ dataError }}.<br />
|
|
67
|
+
Declare a real lookup table with <code>dm add lookup_table</code>, then run <code>dm typegen</code>.
|
|
68
|
+
</p>
|
|
69
|
+
<p v-else class="muted">No rows returned.</p>
|
|
70
|
+
</div>
|
|
71
|
+
</template>
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
/* eslint-disable */
|
|
2
|
+
// ----------------------------------------------------------------------------
|
|
3
|
+
// Generated by `dm typegen` — DO NOT EDIT.
|
|
4
|
+
// This is a starter STUB so the project type-checks before you connect. Set a
|
|
5
|
+
// real "appId" + resource ids in dm.config.json and run `dm typegen`; that
|
|
6
|
+
// overwrites this file with types fetched from your tenant.
|
|
7
|
+
// ----------------------------------------------------------------------------
|
|
8
|
+
import { createDm } from '@datamagik/app-sdk';
|
|
9
|
+
import type { AliasRegistry } from '@datamagik/app-sdk';
|
|
10
|
+
|
|
11
|
+
/** Row of the `parts` lookup table (replaced by real columns on `dm typegen`). */
|
|
12
|
+
export interface PartsRow {
|
|
13
|
+
display_text: string;
|
|
14
|
+
[key: string]: unknown;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
/** Typed alias surface for this app (the generic of `createDm`). */
|
|
18
|
+
export interface DmGenerated {
|
|
19
|
+
tables: { parts: PartsRow };
|
|
20
|
+
odbc: {};
|
|
21
|
+
scripts: {};
|
|
22
|
+
serials: {};
|
|
23
|
+
printers: {};
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
/** Runtime alias → { type, id } registry. */
|
|
27
|
+
export const dmRegistry: AliasRegistry = {
|
|
28
|
+
parts: { type: 'lookup_table', id: 1 },
|
|
29
|
+
};
|
|
30
|
+
|
|
31
|
+
/** Ready-to-use, fully typed SDK instance for this app. */
|
|
32
|
+
export const dm = createDm<DmGenerated>(dmRegistry);
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
:root {
|
|
2
|
+
--dm-purple: #9333ea;
|
|
3
|
+
--dm-purple-dark: #7e22ce;
|
|
4
|
+
--dm-bg: #f9fafb;
|
|
5
|
+
--dm-card: #ffffff;
|
|
6
|
+
--dm-border: #e5e7eb;
|
|
7
|
+
--dm-ink: #111827;
|
|
8
|
+
--dm-ink-soft: #6b7280;
|
|
9
|
+
--dm-err: #dc2626;
|
|
10
|
+
--dm-err-bg: #fef2f2;
|
|
11
|
+
|
|
12
|
+
font-family: system-ui, -apple-system, "Segoe UI", Roboto, sans-serif;
|
|
13
|
+
color: var(--dm-ink);
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
* { box-sizing: border-box; }
|
|
17
|
+
body { margin: 0; background: var(--dm-bg); }
|
|
18
|
+
|
|
19
|
+
#app { max-width: 720px; margin: 0 auto; padding: 2rem 1rem; }
|
|
20
|
+
|
|
21
|
+
header { display: flex; align-items: center; gap: 0.75rem; margin-bottom: 1.5rem; }
|
|
22
|
+
header h1 { font-size: 1.5rem; font-weight: 700; margin: 0; }
|
|
23
|
+
|
|
24
|
+
.dot {
|
|
25
|
+
width: 0.6rem; height: 0.6rem; border-radius: 50%;
|
|
26
|
+
background: var(--dm-ink-soft); flex: none;
|
|
27
|
+
}
|
|
28
|
+
.dot.ok { background: #059669; }
|
|
29
|
+
.dot.err { background: var(--dm-err); }
|
|
30
|
+
|
|
31
|
+
.card {
|
|
32
|
+
background: var(--dm-card);
|
|
33
|
+
border: 1px solid var(--dm-border);
|
|
34
|
+
border-radius: 0.75rem;
|
|
35
|
+
padding: 1.25rem;
|
|
36
|
+
box-shadow: 0 1px 2px rgba(0, 0, 0, 0.04);
|
|
37
|
+
margin-bottom: 1rem;
|
|
38
|
+
}
|
|
39
|
+
.card h2 { font-size: 1rem; margin: 0 0 0.75rem; }
|
|
40
|
+
|
|
41
|
+
.muted { color: var(--dm-ink-soft); font-size: 0.875rem; }
|
|
42
|
+
|
|
43
|
+
.kv { display: grid; grid-template-columns: max-content 1fr; gap: 0.25rem 1rem; font-size: 0.9rem; }
|
|
44
|
+
.kv dt { color: var(--dm-ink-soft); }
|
|
45
|
+
.kv dd { margin: 0; font-weight: 500; }
|
|
46
|
+
|
|
47
|
+
ul.rows { list-style: none; padding: 0; margin: 0; }
|
|
48
|
+
ul.rows li { padding: 0.4rem 0; border-bottom: 1px solid var(--dm-border); font-size: 0.9rem; }
|
|
49
|
+
ul.rows li:last-child { border-bottom: none; }
|
|
50
|
+
|
|
51
|
+
.error {
|
|
52
|
+
background: var(--dm-err-bg); border: 1px solid #fecaca;
|
|
53
|
+
color: var(--dm-err); border-radius: 0.5rem; padding: 0.75rem;
|
|
54
|
+
font-size: 0.85rem;
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
button {
|
|
58
|
+
background: var(--dm-purple); color: #fff; border: none;
|
|
59
|
+
border-radius: 0.5rem; padding: 0.5rem 1rem; font-size: 0.875rem;
|
|
60
|
+
font-weight: 600; cursor: pointer;
|
|
61
|
+
}
|
|
62
|
+
button:hover { background: var(--dm-purple-dark); }
|
|
63
|
+
button:disabled { opacity: 0.5; cursor: default; }
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
{
|
|
2
|
+
"compilerOptions": {
|
|
3
|
+
"target": "ES2022",
|
|
4
|
+
"module": "ESNext",
|
|
5
|
+
"moduleResolution": "Bundler",
|
|
6
|
+
"lib": ["ES2022", "DOM", "DOM.Iterable"],
|
|
7
|
+
"strict": true,
|
|
8
|
+
"noEmit": true,
|
|
9
|
+
"jsx": "preserve",
|
|
10
|
+
"skipLibCheck": true,
|
|
11
|
+
"esModuleInterop": true,
|
|
12
|
+
"isolatedModules": true,
|
|
13
|
+
"verbatimModuleSyntax": true,
|
|
14
|
+
"types": []
|
|
15
|
+
},
|
|
16
|
+
"include": ["src", "env.d.ts"]
|
|
17
|
+
}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { defineConfig } from 'vite';
|
|
2
|
+
import vue from '@vitejs/plugin-vue';
|
|
3
|
+
|
|
4
|
+
// base './' is required: published bundles are served under a signed token
|
|
5
|
+
// path prefix, so every asset URL must stay relative.
|
|
6
|
+
export default defineConfig({
|
|
7
|
+
base: './',
|
|
8
|
+
plugins: [vue()],
|
|
9
|
+
});
|