@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,55 @@
|
|
|
1
|
+
# __APP_NAME__
|
|
2
|
+
|
|
3
|
+
A platform-styled DataMagik SPA **showcase** (Vue 3 + Vite + `@datamagik/app-sdk`)
|
|
4
|
+
with a working example of every SDK area:
|
|
5
|
+
|
|
6
|
+
| Panel | SDK |
|
|
7
|
+
|---|---|
|
|
8
|
+
| Context | `dm.init()`, `dm.context` |
|
|
9
|
+
| Data query | `dm.data.query(alias, opts)` |
|
|
10
|
+
| Scripts | `dm.scripts.run(alias, inputs)` |
|
|
11
|
+
| Serial numbers | `dm.serials.preview / generate` |
|
|
12
|
+
| Printing | `dm.printers.list`, `dm.print.submit` |
|
|
13
|
+
| Navigation | `dm.navigate(target)` |
|
|
14
|
+
| Output events | `dm.emitOutput`, `dm.on('app-output')` |
|
|
15
|
+
|
|
16
|
+
## Get started
|
|
17
|
+
|
|
18
|
+
```bash
|
|
19
|
+
npm install
|
|
20
|
+
# set "appId" in dm.config.json to your application id (App Studio header)
|
|
21
|
+
npx dm login --url https://staging.data-magik.com # or https://data-magik.com
|
|
22
|
+
npx dm dev # run it now — uses the bundled demo types
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
## Placeholder resources
|
|
26
|
+
|
|
27
|
+
The data/script/serial/print panels are declared against **placeholder** ids, so
|
|
28
|
+
they show a “wire it up” hint until you connect real resources. Add your own:
|
|
29
|
+
|
|
30
|
+
```bash
|
|
31
|
+
npx dm add # interactive: pick a type, search, name an alias
|
|
32
|
+
npx dm add lookup_table # or jump straight to a type
|
|
33
|
+
# remove the unused placeholder entries from dm.config.json, then:
|
|
34
|
+
npx dm typegen # refresh the typed surface (src/dm.generated.ts)
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
> `dm typegen` fetches every resource declared in dm.config.json, so it errors
|
|
38
|
+
> on the demo placeholder ids until you replace them with real ones. `dm dev`
|
|
39
|
+
> tolerates this (it falls back to the bundled types), so develop with `dm dev`.
|
|
40
|
+
|
|
41
|
+
`dm add` covers lookup tables, ODBC queries, scripts, serial series, and printers.
|
|
42
|
+
|
|
43
|
+
## Ship it
|
|
44
|
+
|
|
45
|
+
```bash
|
|
46
|
+
npx dm publish --message "first version" # builds and goes live immediately
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
## Structure
|
|
50
|
+
|
|
51
|
+
- `dm.config.json` — app id + declared resources (commit it).
|
|
52
|
+
- `src/dm.generated.ts` — typed alias surface, regenerated by `dm typegen` (commit it).
|
|
53
|
+
- `src/dm-script-types.d.ts` — type your scripts' inputs/outputs here.
|
|
54
|
+
- `src/components/panels/` — one component per SDK area; copy what you need.
|
|
55
|
+
- `src/components/ShowcasePanel.vue` — the presentational card shell.
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
{
|
|
2
|
+
"appId": __APP_ID__,
|
|
3
|
+
"entry": "index.html",
|
|
4
|
+
"sources": [
|
|
5
|
+
{ "sourceId": 1, "type": "lookup_table", "alias": "parts" },
|
|
6
|
+
{ "sourceId": 2, "type": "odbc_query", "alias": "openOrders" },
|
|
7
|
+
{ "sourceId": 3, "type": "script", "alias": "postReceipt" }
|
|
8
|
+
],
|
|
9
|
+
"serialSeries": [
|
|
10
|
+
{ "seriesId": 1, "alias": "lotSerial" }
|
|
11
|
+
],
|
|
12
|
+
"printers": [
|
|
13
|
+
{ "printerId": 1, "alias": "line1Zebra" }
|
|
14
|
+
],
|
|
15
|
+
"appContract": { "inputs": [], "outputs": [], "events": [] }
|
|
16
|
+
}
|
|
@@ -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,67 @@
|
|
|
1
|
+
<script setup lang="ts">
|
|
2
|
+
import { computed, onMounted, ref } from 'vue';
|
|
3
|
+
import type { DmContext } from '@datamagik/app-sdk';
|
|
4
|
+
import { dm } from './dm.generated';
|
|
5
|
+
import { fmtErr } from './format';
|
|
6
|
+
import logoUrl from './assets/datamagik-logo.png';
|
|
7
|
+
import ContextPanel from './components/panels/ContextPanel.vue';
|
|
8
|
+
import QueryPanel from './components/panels/QueryPanel.vue';
|
|
9
|
+
import ScriptPanel from './components/panels/ScriptPanel.vue';
|
|
10
|
+
import SerialPanel from './components/panels/SerialPanel.vue';
|
|
11
|
+
import PrintPanel from './components/panels/PrintPanel.vue';
|
|
12
|
+
import NavigatePanel from './components/panels/NavigatePanel.vue';
|
|
13
|
+
import OutputPanel from './components/panels/OutputPanel.vue';
|
|
14
|
+
|
|
15
|
+
const status = ref<'connecting' | 'ok' | 'error'>('connecting');
|
|
16
|
+
const ctx = ref<DmContext | null>(null);
|
|
17
|
+
const fatal = ref('');
|
|
18
|
+
const ready = computed(() => status.value === 'ok');
|
|
19
|
+
|
|
20
|
+
onMounted(async () => {
|
|
21
|
+
try {
|
|
22
|
+
ctx.value = await dm.init();
|
|
23
|
+
status.value = 'ok';
|
|
24
|
+
} catch (e) {
|
|
25
|
+
status.value = 'error';
|
|
26
|
+
fatal.value = fmtErr(e);
|
|
27
|
+
}
|
|
28
|
+
});
|
|
29
|
+
</script>
|
|
30
|
+
|
|
31
|
+
<template>
|
|
32
|
+
<div class="shell">
|
|
33
|
+
<header class="app-header">
|
|
34
|
+
<img class="logo" :src="logoUrl" alt="DataMagik" />
|
|
35
|
+
<div class="titles">
|
|
36
|
+
<h1>{{ ctx?.appName || '__APP_NAME__' }}</h1>
|
|
37
|
+
<p>App SDK showcase — a working example of every platform capability</p>
|
|
38
|
+
</div>
|
|
39
|
+
<span class="status">
|
|
40
|
+
<span class="dot" :class="{ ok: status === 'ok', err: status === 'error' }"></span>
|
|
41
|
+
{{ status === 'ok' ? 'Connected' : status === 'error' ? 'Disconnected' : 'Connecting…' }}
|
|
42
|
+
</span>
|
|
43
|
+
</header>
|
|
44
|
+
|
|
45
|
+
<div v-if="status === 'error'" class="notice">Could not connect: {{ fatal }}</div>
|
|
46
|
+
<div class="notice">
|
|
47
|
+
This starter declares <strong>placeholder</strong> resource ids, so the data panels show a
|
|
48
|
+
“wire it up” hint until you connect real resources. Run <code>dm add</code>, then
|
|
49
|
+
<code>dm typegen</code>.
|
|
50
|
+
</div>
|
|
51
|
+
|
|
52
|
+
<div class="grid">
|
|
53
|
+
<ContextPanel :ctx="ctx" />
|
|
54
|
+
<QueryPanel :ready="ready" />
|
|
55
|
+
<ScriptPanel :ready="ready" />
|
|
56
|
+
<SerialPanel :ready="ready" />
|
|
57
|
+
<PrintPanel :ready="ready" />
|
|
58
|
+
<NavigatePanel :ready="ready" />
|
|
59
|
+
<OutputPanel :ready="ready" />
|
|
60
|
+
</div>
|
|
61
|
+
|
|
62
|
+
<p class="footer">
|
|
63
|
+
Built with
|
|
64
|
+
<a href="https://www.npmjs.com/package/@datamagik/app-sdk" target="_blank" rel="noopener">@datamagik/app-sdk</a>
|
|
65
|
+
</p>
|
|
66
|
+
</div>
|
|
67
|
+
</template>
|
|
Binary file
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
<script setup lang="ts">
|
|
2
|
+
import { computed } from 'vue';
|
|
3
|
+
|
|
4
|
+
const props = defineProps<{
|
|
5
|
+
title: string;
|
|
6
|
+
description: string;
|
|
7
|
+
code: string;
|
|
8
|
+
icon: string;
|
|
9
|
+
}>();
|
|
10
|
+
|
|
11
|
+
// Inline SVG inner markup keyed by name — keeps the app self-contained (no
|
|
12
|
+
// icon-font CDN, which a sandboxed iframe / offline plant floor may block).
|
|
13
|
+
const ICONS: Record<string, string> = {
|
|
14
|
+
link: '<path d="M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71"/><path d="M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71"/>',
|
|
15
|
+
database: '<ellipse cx="12" cy="5" rx="9" ry="3"/><path d="M3 5v14a9 3 0 0 0 18 0V5"/><path d="M3 12a9 3 0 0 0 18 0"/>',
|
|
16
|
+
code: '<polyline points="16 18 22 12 16 6"/><polyline points="8 6 2 12 8 18"/>',
|
|
17
|
+
hash: '<line x1="4" y1="9" x2="20" y2="9"/><line x1="4" y1="15" x2="20" y2="15"/><line x1="10" y1="3" x2="8" y2="21"/><line x1="16" y1="3" x2="14" y2="21"/>',
|
|
18
|
+
printer: '<polyline points="6 9 6 2 18 2 18 9"/><path d="M6 18H4a2 2 0 0 1-2-2v-5a2 2 0 0 1 2-2h16a2 2 0 0 1 2 2v5a2 2 0 0 1-2 2h-2"/><rect x="6" y="14" width="12" height="8"/>',
|
|
19
|
+
compass: '<circle cx="12" cy="12" r="10"/><polygon points="16.24 7.76 14.12 14.12 7.76 16.24 9.88 9.88 16.24 7.76"/>',
|
|
20
|
+
broadcast: '<circle cx="12" cy="12" r="2"/><path d="M16.24 7.76a6 6 0 0 1 0 8.49M7.76 16.24a6 6 0 0 1 0-8.49M19.07 4.93a10 10 0 0 1 0 14.14M4.93 19.07a10 10 0 0 1 0-14.14"/>',
|
|
21
|
+
};
|
|
22
|
+
|
|
23
|
+
const iconSvg = computed(() => ICONS[props.icon] ?? ICONS['link']);
|
|
24
|
+
</script>
|
|
25
|
+
|
|
26
|
+
<template>
|
|
27
|
+
<section class="panel">
|
|
28
|
+
<div class="panel-head">
|
|
29
|
+
<span class="panel-icon">
|
|
30
|
+
<svg
|
|
31
|
+
viewBox="0 0 24 24"
|
|
32
|
+
fill="none"
|
|
33
|
+
stroke="currentColor"
|
|
34
|
+
stroke-width="2"
|
|
35
|
+
stroke-linecap="round"
|
|
36
|
+
stroke-linejoin="round"
|
|
37
|
+
v-html="iconSvg"
|
|
38
|
+
></svg>
|
|
39
|
+
</span>
|
|
40
|
+
<h2>{{ title }}</h2>
|
|
41
|
+
</div>
|
|
42
|
+
<p class="desc">{{ description }}</p>
|
|
43
|
+
<pre class="code">{{ code }}</pre>
|
|
44
|
+
<div v-if="$slots.controls" class="controls"><slot name="controls" /></div>
|
|
45
|
+
<slot name="result" />
|
|
46
|
+
</section>
|
|
47
|
+
</template>
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
<script setup lang="ts">
|
|
2
|
+
import type { DmContext } from '@datamagik/app-sdk';
|
|
3
|
+
import ShowcasePanel from '../ShowcasePanel.vue';
|
|
4
|
+
|
|
5
|
+
defineProps<{ ctx: DmContext | null }>();
|
|
6
|
+
|
|
7
|
+
const code = `const ctx = await dm.init();
|
|
8
|
+
// ctx.appName, ctx.surface,
|
|
9
|
+
// ctx.user, ctx.company, ctx.params`;
|
|
10
|
+
</script>
|
|
11
|
+
|
|
12
|
+
<template>
|
|
13
|
+
<ShowcasePanel
|
|
14
|
+
icon="link"
|
|
15
|
+
title="Context"
|
|
16
|
+
description="dm.init() resolves with the app context: who, where, and which screen params the host injected."
|
|
17
|
+
:code="code"
|
|
18
|
+
>
|
|
19
|
+
<template #result>
|
|
20
|
+
<dl v-if="ctx" class="kv">
|
|
21
|
+
<dt>App</dt>
|
|
22
|
+
<dd>{{ ctx.appName }} (v{{ ctx.version }})</dd>
|
|
23
|
+
<dt>Surface</dt>
|
|
24
|
+
<dd>{{ ctx.surface }}</dd>
|
|
25
|
+
<dt>User</dt>
|
|
26
|
+
<dd>{{ ctx.user.name }}</dd>
|
|
27
|
+
<dt>Company</dt>
|
|
28
|
+
<dd>{{ ctx.company.name }}</dd>
|
|
29
|
+
<dt>Params</dt>
|
|
30
|
+
<dd>{{ Object.keys(ctx.params).length ? JSON.stringify(ctx.params) : '—' }}</dd>
|
|
31
|
+
</dl>
|
|
32
|
+
<div v-else class="result hint">Connecting to the platform…</div>
|
|
33
|
+
</template>
|
|
34
|
+
</ShowcasePanel>
|
|
35
|
+
</template>
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
<script setup lang="ts">
|
|
2
|
+
import { ref } from 'vue';
|
|
3
|
+
import ShowcasePanel from '../ShowcasePanel.vue';
|
|
4
|
+
import { dm } from '../../dm.generated';
|
|
5
|
+
|
|
6
|
+
defineProps<{ ready: boolean }>();
|
|
7
|
+
|
|
8
|
+
const code = `dm.navigate({
|
|
9
|
+
appId: 12,
|
|
10
|
+
params: { order: '42' }
|
|
11
|
+
});`;
|
|
12
|
+
|
|
13
|
+
const appId = ref(12);
|
|
14
|
+
const value = ref('');
|
|
15
|
+
|
|
16
|
+
function go(): void {
|
|
17
|
+
// Fire-and-forget: the host shell handles the navigation request.
|
|
18
|
+
dm.navigate({ appId: Number(appId.value), params: { order: '42' } });
|
|
19
|
+
value.value = `Requested navigation to app #${appId.value} (handled by the host shell).`;
|
|
20
|
+
}
|
|
21
|
+
</script>
|
|
22
|
+
|
|
23
|
+
<template>
|
|
24
|
+
<ShowcasePanel
|
|
25
|
+
icon="compass"
|
|
26
|
+
title="Navigation"
|
|
27
|
+
description="Ask the host shell to open another app. Fire-and-forget — the platform performs the navigation."
|
|
28
|
+
:code="code"
|
|
29
|
+
>
|
|
30
|
+
<template #controls>
|
|
31
|
+
<input class="text" v-model.number="appId" type="number" aria-label="Target app id" style="max-width: 6rem" />
|
|
32
|
+
<button class="btn" :disabled="!ready" @click="go">Navigate</button>
|
|
33
|
+
</template>
|
|
34
|
+
<template #result>
|
|
35
|
+
<div v-if="value" class="result">{{ value }}</div>
|
|
36
|
+
</template>
|
|
37
|
+
</ShowcasePanel>
|
|
38
|
+
</template>
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
<script setup lang="ts">
|
|
2
|
+
import { onMounted, onUnmounted, ref } from 'vue';
|
|
3
|
+
import type { AppOutput } from '@datamagik/app-sdk';
|
|
4
|
+
import ShowcasePanel from '../ShowcasePanel.vue';
|
|
5
|
+
import { dm } from '../../dm.generated';
|
|
6
|
+
import { pretty } from '../../format';
|
|
7
|
+
|
|
8
|
+
defineProps<{ ready: boolean }>();
|
|
9
|
+
|
|
10
|
+
const code = `dm.emitOutput('completed', payload);
|
|
11
|
+
dm.on('app-output', (msg) => {
|
|
12
|
+
// react to other apps' output
|
|
13
|
+
});`;
|
|
14
|
+
|
|
15
|
+
const log = ref<string[]>([]);
|
|
16
|
+
let off: (() => void) | undefined;
|
|
17
|
+
|
|
18
|
+
onMounted(() => {
|
|
19
|
+
// Listen for output events broadcast by the host / other apps.
|
|
20
|
+
off = dm.on('app-output', (msg: AppOutput) => {
|
|
21
|
+
log.value = [`◀ ${msg.eventName}: ${pretty(msg.output)}`, ...log.value].slice(0, 5);
|
|
22
|
+
});
|
|
23
|
+
});
|
|
24
|
+
|
|
25
|
+
onUnmounted(() => off?.());
|
|
26
|
+
|
|
27
|
+
function emit(): void {
|
|
28
|
+
dm.emitOutput('completed', { at: new Date().toISOString(), ok: true });
|
|
29
|
+
log.value = ['▶ emitted "completed"', ...log.value].slice(0, 5);
|
|
30
|
+
}
|
|
31
|
+
</script>
|
|
32
|
+
|
|
33
|
+
<template>
|
|
34
|
+
<ShowcasePanel
|
|
35
|
+
icon="broadcast"
|
|
36
|
+
title="Output events"
|
|
37
|
+
description="Emit results to the host (and other apps), and subscribe to app-output events."
|
|
38
|
+
:code="code"
|
|
39
|
+
>
|
|
40
|
+
<template #controls>
|
|
41
|
+
<button class="btn" :disabled="!ready" @click="emit">Emit "completed"</button>
|
|
42
|
+
</template>
|
|
43
|
+
<template #result>
|
|
44
|
+
<ul v-if="log.length" class="rows">
|
|
45
|
+
<li v-for="(line, i) in log" :key="i">{{ line }}</li>
|
|
46
|
+
</ul>
|
|
47
|
+
<div v-else class="result hint">Emit an event, or wait for one from the host.</div>
|
|
48
|
+
</template>
|
|
49
|
+
</ShowcasePanel>
|
|
50
|
+
</template>
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
<script setup lang="ts">
|
|
2
|
+
import { ref } from 'vue';
|
|
3
|
+
import ShowcasePanel from '../ShowcasePanel.vue';
|
|
4
|
+
import { dm } from '../../dm.generated';
|
|
5
|
+
import { fmtErr } from '../../format';
|
|
6
|
+
|
|
7
|
+
defineProps<{ ready: boolean }>();
|
|
8
|
+
|
|
9
|
+
const code = `await dm.printers.list();
|
|
10
|
+
await dm.print.submit('line1Zebra', {
|
|
11
|
+
format: 'zpl', data: '^XA…^XZ'
|
|
12
|
+
});`;
|
|
13
|
+
|
|
14
|
+
const busy = ref(false);
|
|
15
|
+
const value = ref('');
|
|
16
|
+
const error = ref('');
|
|
17
|
+
|
|
18
|
+
async function list(): Promise<void> {
|
|
19
|
+
await act(async () => {
|
|
20
|
+
const printers = await dm.printers.list();
|
|
21
|
+
value.value = printers.length ? printers.map((p) => `• ${p.name} (${p.type})`).join('\n') : 'No printers configured.';
|
|
22
|
+
});
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
async function submit(): Promise<void> {
|
|
26
|
+
await act(async () => {
|
|
27
|
+
const { jobId } = await dm.print.submit('line1Zebra', {
|
|
28
|
+
format: 'zpl',
|
|
29
|
+
data: '^XA^FO50,50^ADN,36,20^FDDataMagik^FS^XZ',
|
|
30
|
+
});
|
|
31
|
+
value.value = `Print job ${jobId} queued.`;
|
|
32
|
+
});
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
async function act(fn: () => Promise<void>): Promise<void> {
|
|
36
|
+
busy.value = true;
|
|
37
|
+
error.value = '';
|
|
38
|
+
value.value = '';
|
|
39
|
+
try {
|
|
40
|
+
await fn();
|
|
41
|
+
} catch (e) {
|
|
42
|
+
error.value = fmtErr(e);
|
|
43
|
+
} finally {
|
|
44
|
+
busy.value = false;
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
</script>
|
|
48
|
+
|
|
49
|
+
<template>
|
|
50
|
+
<ShowcasePanel
|
|
51
|
+
icon="printer"
|
|
52
|
+
title="Printing"
|
|
53
|
+
description="List the company's printers and submit a label/document job to a declared printer."
|
|
54
|
+
:code="code"
|
|
55
|
+
>
|
|
56
|
+
<template #controls>
|
|
57
|
+
<button class="btn secondary" :disabled="!ready || busy" @click="list">List printers</button>
|
|
58
|
+
<button class="btn" :disabled="!ready || busy" @click="submit">Submit ZPL</button>
|
|
59
|
+
</template>
|
|
60
|
+
<template #result>
|
|
61
|
+
<div v-if="value" class="result">{{ value }}</div>
|
|
62
|
+
<div v-else-if="error" class="result hint">
|
|
63
|
+
{{ error }}
|
|
64
|
+
<br />Wire a real printer: <code>dm add printer</code> → <code>dm typegen</code>.
|
|
65
|
+
</div>
|
|
66
|
+
</template>
|
|
67
|
+
</ShowcasePanel>
|
|
68
|
+
</template>
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
<script setup lang="ts">
|
|
2
|
+
import { ref } from 'vue';
|
|
3
|
+
import ShowcasePanel from '../ShowcasePanel.vue';
|
|
4
|
+
import { dm } from '../../dm.generated';
|
|
5
|
+
import { fmtErr } from '../../format';
|
|
6
|
+
|
|
7
|
+
defineProps<{ ready: boolean }>();
|
|
8
|
+
|
|
9
|
+
const code = `const { rows } = await dm.data.query(
|
|
10
|
+
'parts', { pageSize: 5 }
|
|
11
|
+
);`;
|
|
12
|
+
|
|
13
|
+
const busy = ref(false);
|
|
14
|
+
const rows = ref<Record<string, unknown>[]>([]);
|
|
15
|
+
const error = ref('');
|
|
16
|
+
|
|
17
|
+
async function run(): Promise<void> {
|
|
18
|
+
busy.value = true;
|
|
19
|
+
error.value = '';
|
|
20
|
+
rows.value = [];
|
|
21
|
+
try {
|
|
22
|
+
const result = await dm.data.query('parts', { pageSize: 5 });
|
|
23
|
+
rows.value = result.rows;
|
|
24
|
+
} catch (e) {
|
|
25
|
+
error.value = fmtErr(e);
|
|
26
|
+
} finally {
|
|
27
|
+
busy.value = false;
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
</script>
|
|
31
|
+
|
|
32
|
+
<template>
|
|
33
|
+
<ShowcasePanel
|
|
34
|
+
icon="database"
|
|
35
|
+
title="Data query"
|
|
36
|
+
description="Query a declared lookup table or ODBC query. Rows are typed from dm.generated.ts."
|
|
37
|
+
:code="code"
|
|
38
|
+
>
|
|
39
|
+
<template #controls>
|
|
40
|
+
<button class="btn" :disabled="!ready || busy" @click="run">{{ busy ? 'Querying…' : 'Run query' }}</button>
|
|
41
|
+
</template>
|
|
42
|
+
<template #result>
|
|
43
|
+
<ul v-if="rows.length" class="rows">
|
|
44
|
+
<li v-for="(row, i) in rows" :key="i">{{ row.display_text ?? JSON.stringify(row) }}</li>
|
|
45
|
+
</ul>
|
|
46
|
+
<div v-else-if="error" class="result hint">
|
|
47
|
+
{{ error }}
|
|
48
|
+
<br />Wire a real lookup table: <code>dm add lookup_table</code> → <code>dm typegen</code>.
|
|
49
|
+
</div>
|
|
50
|
+
</template>
|
|
51
|
+
</ShowcasePanel>
|
|
52
|
+
</template>
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
<script setup lang="ts">
|
|
2
|
+
import { ref } from 'vue';
|
|
3
|
+
import ShowcasePanel from '../ShowcasePanel.vue';
|
|
4
|
+
import { dm } from '../../dm.generated';
|
|
5
|
+
import { fmtErr, pretty } from '../../format';
|
|
6
|
+
|
|
7
|
+
defineProps<{ ready: boolean }>();
|
|
8
|
+
|
|
9
|
+
const code = `const out = await dm.scripts.run(
|
|
10
|
+
'postReceipt',
|
|
11
|
+
{ poNumber, quantity }
|
|
12
|
+
);`;
|
|
13
|
+
|
|
14
|
+
const poNumber = ref('PO-1001');
|
|
15
|
+
const quantity = ref(5);
|
|
16
|
+
const busy = ref(false);
|
|
17
|
+
const output = ref('');
|
|
18
|
+
const error = ref('');
|
|
19
|
+
|
|
20
|
+
async function run(): Promise<void> {
|
|
21
|
+
busy.value = true;
|
|
22
|
+
error.value = '';
|
|
23
|
+
output.value = '';
|
|
24
|
+
try {
|
|
25
|
+
const out = await dm.scripts.run('postReceipt', { poNumber: poNumber.value, quantity: Number(quantity.value) });
|
|
26
|
+
output.value = pretty(out);
|
|
27
|
+
} catch (e) {
|
|
28
|
+
error.value = fmtErr(e);
|
|
29
|
+
} finally {
|
|
30
|
+
busy.value = false;
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
</script>
|
|
34
|
+
|
|
35
|
+
<template>
|
|
36
|
+
<ShowcasePanel
|
|
37
|
+
icon="code"
|
|
38
|
+
title="Scripts"
|
|
39
|
+
description="Run a server-side script. IO is typed via the DmScriptTypes augmentation (see src/dm-script-types.d.ts)."
|
|
40
|
+
:code="code"
|
|
41
|
+
>
|
|
42
|
+
<template #controls>
|
|
43
|
+
<input class="text" v-model="poNumber" aria-label="PO number" placeholder="PO number" />
|
|
44
|
+
<input class="text" v-model.number="quantity" type="number" aria-label="Quantity" style="max-width: 5rem" />
|
|
45
|
+
<button class="btn" :disabled="!ready || busy" @click="run">{{ busy ? 'Running…' : 'Run script' }}</button>
|
|
46
|
+
</template>
|
|
47
|
+
<template #result>
|
|
48
|
+
<div v-if="output" class="result">{{ output }}</div>
|
|
49
|
+
<div v-else-if="error" class="result hint">
|
|
50
|
+
{{ error }}
|
|
51
|
+
<br />Wire a real script: <code>dm add script</code> → <code>dm typegen</code>.
|
|
52
|
+
</div>
|
|
53
|
+
</template>
|
|
54
|
+
</ShowcasePanel>
|
|
55
|
+
</template>
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
<script setup lang="ts">
|
|
2
|
+
import { ref } from 'vue';
|
|
3
|
+
import ShowcasePanel from '../ShowcasePanel.vue';
|
|
4
|
+
import { dm } from '../../dm.generated';
|
|
5
|
+
import { fmtErr } from '../../format';
|
|
6
|
+
|
|
7
|
+
defineProps<{ ready: boolean }>();
|
|
8
|
+
|
|
9
|
+
const code = `await dm.serials.preview('lotSerial');
|
|
10
|
+
await dm.serials.generate(
|
|
11
|
+
'lotSerial', { PART: 'P-100' }
|
|
12
|
+
);`;
|
|
13
|
+
|
|
14
|
+
const busy = ref(false);
|
|
15
|
+
const value = ref('');
|
|
16
|
+
const error = ref('');
|
|
17
|
+
|
|
18
|
+
async function preview(): Promise<void> {
|
|
19
|
+
await act(async () => {
|
|
20
|
+
value.value = 'preview: ' + (await dm.serials.preview('lotSerial'));
|
|
21
|
+
});
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
async function generate(): Promise<void> {
|
|
25
|
+
await act(async () => {
|
|
26
|
+
const rec = await dm.serials.generate('lotSerial', { PART: 'P-100' });
|
|
27
|
+
value.value = 'generated: ' + rec.serialNumber;
|
|
28
|
+
});
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
async function act(fn: () => Promise<void>): Promise<void> {
|
|
32
|
+
busy.value = true;
|
|
33
|
+
error.value = '';
|
|
34
|
+
value.value = '';
|
|
35
|
+
try {
|
|
36
|
+
await fn();
|
|
37
|
+
} catch (e) {
|
|
38
|
+
error.value = fmtErr(e);
|
|
39
|
+
} finally {
|
|
40
|
+
busy.value = false;
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
</script>
|
|
44
|
+
|
|
45
|
+
<template>
|
|
46
|
+
<ShowcasePanel
|
|
47
|
+
icon="hash"
|
|
48
|
+
title="Serial numbers"
|
|
49
|
+
description="Preview or generate traceability serials. The context is typed from the series' schema."
|
|
50
|
+
:code="code"
|
|
51
|
+
>
|
|
52
|
+
<template #controls>
|
|
53
|
+
<button class="btn secondary" :disabled="!ready || busy" @click="preview">Preview</button>
|
|
54
|
+
<button class="btn" :disabled="!ready || busy" @click="generate">Generate</button>
|
|
55
|
+
</template>
|
|
56
|
+
<template #result>
|
|
57
|
+
<div v-if="value" class="result">{{ value }}</div>
|
|
58
|
+
<div v-else-if="error" class="result hint">
|
|
59
|
+
{{ error }}
|
|
60
|
+
<br />Wire a real series: <code>dm add serial_series</code> → <code>dm typegen</code>.
|
|
61
|
+
</div>
|
|
62
|
+
</template>
|
|
63
|
+
</ShowcasePanel>
|
|
64
|
+
</template>
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
// Type your scripts by augmenting `DmScriptTypes` (declaration merging). The
|
|
2
|
+
// platform stores no script IO schema, so without this a script's inputs/output
|
|
3
|
+
// are `unknown`. Add one block per script alias declared in dm.config.json.
|
|
4
|
+
import '@datamagik/app-sdk';
|
|
5
|
+
|
|
6
|
+
declare module '@datamagik/app-sdk' {
|
|
7
|
+
interface DmScriptTypes {
|
|
8
|
+
postReceipt: {
|
|
9
|
+
inputs: { poNumber: string; quantity: number };
|
|
10
|
+
output: { ok: boolean; receiptId: number };
|
|
11
|
+
};
|
|
12
|
+
}
|
|
13
|
+
}
|