infaira-canvas 0.1.10 → 0.3.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/README.md +7 -0
- package/dist/commands/init.js +37 -0
- package/dist/index.js +0 -0
- package/package.json +5 -3
- package/templates/ICan-Widget-Development-Guide.md +112 -1
- package/templates/ICan-Widget-Theming-Guide.md +14 -1
- package/templates/ican.d.ts +66 -2
- package/templates/index.html +34 -1
- package/templates/ui.html +28 -1
package/README.md
CHANGED
|
@@ -11,6 +11,13 @@ CLI toolkit for building and publishing widgets for the **InfAIra Canvas (ICan)*
|
|
|
11
11
|
1. **Scaffold** a new widget project with all required files
|
|
12
12
|
2. **Upload** a built widget bundle to an ICan portal
|
|
13
13
|
|
|
14
|
+
Widgets scaffolded with this CLI can call:
|
|
15
|
+
|
|
16
|
+
- **ICan native actions** — `icanContext.executeAction('Buildings', 'List', { siteId })`
|
|
17
|
+
- **Mythos workflow actions** — `icanContext.executeAction('mythos:Inventory', 'UpdateStock', { sku, qty })`
|
|
18
|
+
|
|
19
|
+
The only difference at the call site is the `mythos:` prefix on the model name. The ICan backend handles routing (set `MYTHOS_BASE_URL` on the backend to enable). See **section 2a** of the bundled `ICan-Widget-Development-Guide.md` for the full Mythos integration walkthrough.
|
|
20
|
+
|
|
14
21
|
---
|
|
15
22
|
|
|
16
23
|
## Installation
|
package/dist/commands/init.js
CHANGED
|
@@ -288,20 +288,57 @@ import LocalizationMessages from '../localization.json';
|
|
|
288
288
|
// ─── Types ────────────────────────────────────────────────────────────────────
|
|
289
289
|
|
|
290
290
|
export interface IActionOptions {
|
|
291
|
+
/** Parse response body as JSON before resolving. */
|
|
291
292
|
json?: boolean;
|
|
293
|
+
/** Stable identifier for cancellation. Required when cancelPrevious is set. */
|
|
292
294
|
key?: string;
|
|
295
|
+
/** When true and "key" is also set, any prior in-flight call sharing the
|
|
296
|
+
* same key is cancelled (its Promise resolves to null). Use for live-filter
|
|
297
|
+
* widgets where only the latest call result should land in state. */
|
|
293
298
|
cancelPrevious?: boolean;
|
|
299
|
+
/** Skip the 100ms batch window and fire immediately. */
|
|
294
300
|
executeImmediately?: boolean;
|
|
295
301
|
}
|
|
296
302
|
|
|
303
|
+
/** A Mythos action published and callable from this widget. Returned by
|
|
304
|
+
* IContextProvider.listMythosActions. Invoke one via
|
|
305
|
+
* executeAction('mythos:' + model_name, action_name, params). */
|
|
306
|
+
export interface IMythosAction {
|
|
307
|
+
model_id: string;
|
|
308
|
+
model_name: string;
|
|
309
|
+
action_id: string;
|
|
310
|
+
action_name: string;
|
|
311
|
+
description?: string;
|
|
312
|
+
capability?: string;
|
|
313
|
+
}
|
|
314
|
+
|
|
297
315
|
export interface IContextProvider {
|
|
298
316
|
environment: 'dev' | 'prod';
|
|
299
317
|
orchUrl?: string;
|
|
300
318
|
userKey: string;
|
|
301
319
|
root: string;
|
|
302
320
|
scriptFiles?: string[];
|
|
321
|
+
/** Invoke a model action.
|
|
322
|
+
* - executeAction('Buildings', 'List', { siteId }) → ICan native
|
|
323
|
+
* - executeAction('mythos:Inventory', 'UpdateStock', p) → Mythos engine
|
|
324
|
+
* The 'mythos:' prefix is the only difference at the call site; the
|
|
325
|
+
* ICan backend routes the call appropriately.
|
|
326
|
+
* options.cancelPrevious + options.key: when set, an in-flight call with
|
|
327
|
+
* the same key is cancelled (resolves null) and the new call wins. */
|
|
303
328
|
executeAction(model: string, action: string, parameters: unknown, options?: IActionOptions): Promise<unknown>;
|
|
304
329
|
executeService(app: string, service: string, parameters: unknown, options?: IActionOptions): Promise<unknown>;
|
|
330
|
+
/** List Mythos actions callable via executeAction('mythos:...', ...).
|
|
331
|
+
* Optional — present only when MYTHOS_BASE_URL is configured on the ICan
|
|
332
|
+
* backend. Treat absence as "Mythos integration disabled". */
|
|
333
|
+
listMythosActions?(): Promise<IMythosAction[]>;
|
|
334
|
+
/** Fire a Mythos external event with an optional payload. */
|
|
335
|
+
fireMythosEvent?(eventType: string, payload?: Record<string, unknown>): Promise<void>;
|
|
336
|
+
/** Build an IDataFunction over a Mythos collection for DataList/DataTable. */
|
|
337
|
+
fromMythosCollection?(model: string, collection: string): (
|
|
338
|
+
max: number,
|
|
339
|
+
lastPageToken: string,
|
|
340
|
+
args?: { search?: string } & Record<string, unknown>,
|
|
341
|
+
) => Promise<{ items: Array<Record<string, unknown>>; pageToken: string }>;
|
|
305
342
|
fireEvent(eventId: string): Promise<void>;
|
|
306
343
|
hasAppRole(app: string, role: string): boolean;
|
|
307
344
|
themeName?: string;
|
package/dist/index.js
CHANGED
|
File without changes
|
package/package.json
CHANGED
|
@@ -1,13 +1,15 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "infaira-canvas",
|
|
3
|
-
"version": "0.
|
|
4
|
-
"description": "InfAIra Canvas CLI —
|
|
3
|
+
"version": "0.3.0",
|
|
4
|
+
"description": "InfAIra Canvas CLI — scaffold widgets that talk to ICan and Mythos (actions, events, public portals, paginated collections).",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"infaira",
|
|
7
7
|
"ican",
|
|
8
|
+
"mythos",
|
|
8
9
|
"widget",
|
|
9
10
|
"cli",
|
|
10
|
-
"scaffold"
|
|
11
|
+
"scaffold",
|
|
12
|
+
"workflow"
|
|
11
13
|
],
|
|
12
14
|
"homepage": "https://infaira.co",
|
|
13
15
|
"license": "MIT",
|
|
@@ -38,7 +38,10 @@ In the portal, `icanContext` is always defined — the widget is never mounted u
|
|
|
38
38
|
| `language` | `string` | Active language code, e.g. `'en'` |
|
|
39
39
|
| `themeName` | `string \| undefined` | e.g. `'Dark'`, `'Glass Light'` |
|
|
40
40
|
| `themeType` | `'Dark' \| 'Light' \| 'Glass-Dark' \| 'Glass-Light' \| undefined` | Structured theme type for chart colours |
|
|
41
|
-
| `executeAction` | `(model, action, params?, options?) => Promise<unknown>` | Call an
|
|
41
|
+
| `executeAction` | `(model, action, params?, options?) => Promise<unknown>` | Call an action. ICan native by default; prefix `model` with `mythos:` to route to the Mythos engine instead. `options.cancelPrevious` + `options.key` to deduplicate live-filter calls. |
|
|
42
|
+
| `listMythosActions` | `() => Promise<IMythosAction[]> \| undefined` | List Mythos actions callable from this widget. Present only when the ICan backend has `MYTHOS_BASE_URL` configured. |
|
|
43
|
+
| `fireMythosEvent` | `(event_type, payload?) => Promise<void> \| undefined` | Fire a named external event into the Mythos bus. Triggers any matching Mythos event handlers. |
|
|
44
|
+
| `fromMythosCollection` | `(model, collection) => IDataFunction \| undefined` | Build a paginated data source over a Mythos collection — drops into DataList / DataTable. |
|
|
42
45
|
| `fireEvent` | `(eventId) => Promise<void>` | Trigger a portal event |
|
|
43
46
|
| `hasAppRole` | `(app, role) => boolean` | Check if the user has a role |
|
|
44
47
|
| `$L` | `(code, params?) => string` | Translate a localisation key |
|
|
@@ -73,6 +76,114 @@ The dev harness always sets `environment: 'dev'`. The portal always sets `enviro
|
|
|
73
76
|
|
|
74
77
|
---
|
|
75
78
|
|
|
79
|
+
## 2a. Calling Mythos actions — the `mythos:` prefix
|
|
80
|
+
|
|
81
|
+
ICan widgets can invoke actions running in the Mythos workflow engine through the exact same `executeAction` call, just by prefixing the `model` argument with `mythos:`. The host backend inspects the prefix and routes the request to the Mythos engine via the shared JWT.
|
|
82
|
+
|
|
83
|
+
```tsx
|
|
84
|
+
// 1. Discover what's available (call once at mount and cache)
|
|
85
|
+
const actions = await icanContext.listMythosActions?.();
|
|
86
|
+
// → [{ model_id, model_name: 'Inventory', action_id, action_name: 'UpdateStock', description }]
|
|
87
|
+
|
|
88
|
+
// 2. Invoke a Mythos action — only the `mythos:` prefix differs from a
|
|
89
|
+
// native ICan call
|
|
90
|
+
const result = await icanContext.executeAction(
|
|
91
|
+
'mythos:Inventory', // <- the prefix is what triggers Mythos routing
|
|
92
|
+
'UpdateStock',
|
|
93
|
+
{ sku: 'ABC-123', qty: 5 },
|
|
94
|
+
);
|
|
95
|
+
// → { run_id: '...', status: 'ok', output?: {...} }
|
|
96
|
+
```
|
|
97
|
+
|
|
98
|
+
### When to use Mythos vs native
|
|
99
|
+
|
|
100
|
+
| Use Mythos when… | Use native ICan when… |
|
|
101
|
+
|---|---|
|
|
102
|
+
| The logic is a multi-step workflow with branches, retries, or external calls | The call is a direct read/write to a backing service (Locations, Assets, etc.) |
|
|
103
|
+
| You want the call recorded in Mythos's execution log + debugger | You don't need step-level tracing |
|
|
104
|
+
| Multiple widgets need to call the same business operation | The operation is widget-local |
|
|
105
|
+
| You want to publish the same logic over a REST endpoint too | The widget owns the orchestration |
|
|
106
|
+
|
|
107
|
+
### Failure modes to handle
|
|
108
|
+
|
|
109
|
+
`executeAction('mythos:...')` can reject with:
|
|
110
|
+
|
|
111
|
+
- **`mythos integration not configured`** — the ICan backend doesn't have `MYTHOS_BASE_URL` set. Surface this to the user and fall back gracefully.
|
|
112
|
+
- **`mythos model "X" not found or not published`** — the action either doesn't exist or isn't toggled `published: true` in Mythos.
|
|
113
|
+
- **HTTP / network errors** — same as any `executeAction` call.
|
|
114
|
+
|
|
115
|
+
`listMythosActions` is also `undefined` when integration is disabled — so guard with `?.()`.
|
|
116
|
+
|
|
117
|
+
```tsx
|
|
118
|
+
const handleRun = async () => {
|
|
119
|
+
try {
|
|
120
|
+
const r = await icanContext.executeAction('mythos:Inventory', 'UpdateStock', { sku, qty });
|
|
121
|
+
setResult(r);
|
|
122
|
+
} catch (e) {
|
|
123
|
+
setError(e instanceof Error ? e.message : 'Failed');
|
|
124
|
+
}
|
|
125
|
+
};
|
|
126
|
+
```
|
|
127
|
+
|
|
128
|
+
A working reference widget lives at `Widgets/ICan widgets/mythosdemo/` — pick an action, fill params, run, render the response.
|
|
129
|
+
|
|
130
|
+
### Cancelling stale calls (`options.cancelPrevious`)
|
|
131
|
+
|
|
132
|
+
Widgets that fire on every keystroke — search bars, live filters — end up racing requests against themselves. Use `cancelPrevious` + `key` to ensure only the latest call's result lands:
|
|
133
|
+
|
|
134
|
+
```tsx
|
|
135
|
+
const onSearch = (text: string) => {
|
|
136
|
+
icanContext.executeAction(
|
|
137
|
+
'mythos:Inventory',
|
|
138
|
+
'Search',
|
|
139
|
+
{ q: text },
|
|
140
|
+
{ cancelPrevious: true, key: 'inventory-search' },
|
|
141
|
+
).then((res) => {
|
|
142
|
+
if (res !== null) setResults(res); // null means this call was cancelled
|
|
143
|
+
});
|
|
144
|
+
};
|
|
145
|
+
```
|
|
146
|
+
|
|
147
|
+
Calls with the same `key` are tracked; when a newer one is issued, older ones resolve to `null` instead of delivering stale data into your state.
|
|
148
|
+
|
|
149
|
+
### Firing Mythos events
|
|
150
|
+
|
|
151
|
+
`icanContext.fireMythosEvent('order_placed', { id: 4821 })` publishes the event into Mythos's bus. Any Mythos workflow with a matching External Event trigger fires. Useful for widget → workflow dispatch where you don't need a return value.
|
|
152
|
+
|
|
153
|
+
```tsx
|
|
154
|
+
await icanContext.fireMythosEvent?.('user_logged_in', { userId });
|
|
155
|
+
```
|
|
156
|
+
|
|
157
|
+
Optional — `fireMythosEvent` is `undefined` when Mythos integration is disabled. Guard with `?.()`.
|
|
158
|
+
|
|
159
|
+
### Reading from a Mythos collection
|
|
160
|
+
|
|
161
|
+
`icanContext.fromMythosCollection(model, collection)` returns a function with the same shape ICan's DataList / DataTable already accept:
|
|
162
|
+
|
|
163
|
+
```tsx
|
|
164
|
+
const fetchPage = icanContext.fromMythosCollection!('Inventory', 'items');
|
|
165
|
+
|
|
166
|
+
<DataList
|
|
167
|
+
dataFunction={fetchPage}
|
|
168
|
+
pageSize={50}
|
|
169
|
+
renderItem={(item) => <div>{item.sku} — {item.qty}</div>}
|
|
170
|
+
/>
|
|
171
|
+
```
|
|
172
|
+
|
|
173
|
+
The function takes `(max, lastPageToken, args?)` and returns `{ items, pageToken }`. Empty `pageToken` means "no more pages". Supports `args.search` for text filtering against the collection's searchable fields.
|
|
174
|
+
|
|
175
|
+
### Public portals (anonymous Mythos access)
|
|
176
|
+
|
|
177
|
+
When a widget runs on a `is_public: true` portal, the host calls `/api/public/execute-batch` instead of the authenticated endpoint. For `mythos:` calls in that batch:
|
|
178
|
+
|
|
179
|
+
- The Mythos action **must** have `no_auth: true` set in its API Route config
|
|
180
|
+
- The call is forwarded to Mythos's public route `/api/<scope>/models/{name}/actions/{name}` with no JWT
|
|
181
|
+
- Mythos enforces `no_auth` at its middleware layer — actions without that flag return `401` to the widget
|
|
182
|
+
|
|
183
|
+
No code change in the widget itself — the same `executeAction('mythos:X', 'Y', params)` call works in both authenticated and public portals.
|
|
184
|
+
|
|
185
|
+
---
|
|
186
|
+
|
|
76
187
|
## 3. Widget settings panel — `IWidgetPropConfig`
|
|
77
188
|
|
|
78
189
|
Widgets can expose a settings form in the portal. Users open it by clicking the ⚙ button on a widget cell in edit mode. You define the fields in `registerWidget`:
|
|
@@ -594,7 +594,10 @@ interface IContextProvider {
|
|
|
594
594
|
orchUrl?: string;
|
|
595
595
|
apiKey?: string;
|
|
596
596
|
|
|
597
|
-
//
|
|
597
|
+
// Invoke an action. Prefix model with `mythos:` to route to the Mythos
|
|
598
|
+
// workflow engine instead of the default ICan native pipeline:
|
|
599
|
+
// executeAction('Buildings', 'List', { siteId }) → ICan native
|
|
600
|
+
// executeAction('mythos:Inventory', 'UpdateStock', { ... }) → Mythos engine
|
|
598
601
|
executeAction(
|
|
599
602
|
model: string,
|
|
600
603
|
action: string,
|
|
@@ -602,6 +605,16 @@ interface IContextProvider {
|
|
|
602
605
|
options?: IActionOptions
|
|
603
606
|
): Promise<unknown>;
|
|
604
607
|
|
|
608
|
+
// List Mythos actions callable via executeAction('mythos:...', ...).
|
|
609
|
+
// Optional — present only when MYTHOS_BASE_URL is set on the ICan backend.
|
|
610
|
+
listMythosActions?(): Promise<Array<{
|
|
611
|
+
model_id: string;
|
|
612
|
+
model_name: string;
|
|
613
|
+
action_id: string;
|
|
614
|
+
action_name: string;
|
|
615
|
+
description?: string;
|
|
616
|
+
}>>;
|
|
617
|
+
|
|
605
618
|
executeService(
|
|
606
619
|
app: string,
|
|
607
620
|
service: string,
|
package/templates/ican.d.ts
CHANGED
|
@@ -701,17 +701,81 @@ declare module "ican/context" {
|
|
|
701
701
|
email?: string;
|
|
702
702
|
roles?: string[];
|
|
703
703
|
};
|
|
704
|
-
/**
|
|
704
|
+
/**
|
|
705
|
+
* Invoke a model action on this dashboard.
|
|
706
|
+
*
|
|
707
|
+
* Routing happens server-side by inspecting `model`:
|
|
708
|
+
* - `executeAction('Buildings', 'List', { siteId })`
|
|
709
|
+
* → ICan native action (existing Orch pipeline).
|
|
710
|
+
* - `executeAction('mythos:Inventory', 'UpdateStock', { sku, qty })`
|
|
711
|
+
* → routed to the Mythos engine via the `mythos:` prefix. Resolves
|
|
712
|
+
* to the published Mythos action with that (model_name, action_name)
|
|
713
|
+
* and POSTs to `/api/models/{id}/actions/{id}/run`.
|
|
714
|
+
*
|
|
715
|
+
* Both call shapes return a Promise that resolves to the action's output
|
|
716
|
+
* envelope. For Mythos, the envelope is `{ run_id, status, output? }`.
|
|
717
|
+
*
|
|
718
|
+
* `options.cancelPrevious` + `options.key`: when an in-flight call shares
|
|
719
|
+
* the same key, its Promise resolves to `null` and the newer call wins.
|
|
720
|
+
* Designed for live-filter widgets where only the latest result matters.
|
|
721
|
+
*/
|
|
705
722
|
executeAction(
|
|
706
723
|
model: string,
|
|
707
724
|
action: string,
|
|
708
|
-
params?: Record<string, unknown
|
|
725
|
+
params?: Record<string, unknown>,
|
|
726
|
+
options?: { cancelPrevious?: boolean; key?: string }
|
|
709
727
|
): Promise<unknown>;
|
|
728
|
+
/**
|
|
729
|
+
* List every Mythos action published and callable from this widget.
|
|
730
|
+
* Optional — present only when the ICan backend has MYTHOS_BASE_URL set.
|
|
731
|
+
* Widgets that build action pickers (settings panels, etc.) call this
|
|
732
|
+
* once at mount and cache the result themselves.
|
|
733
|
+
*/
|
|
734
|
+
listMythosActions?: () => Promise<IMythosAction[]>;
|
|
735
|
+
/**
|
|
736
|
+
* Fire an external event into the Mythos engine. The event_type matches
|
|
737
|
+
* what Mythos event-handlers subscribe to (configured in the model's
|
|
738
|
+
* Events tab). Mirrors UXP's fireEvent, with an optional payload.
|
|
739
|
+
* Optional — present only when MYTHOS_BASE_URL is configured.
|
|
740
|
+
*/
|
|
741
|
+
fireMythosEvent?: (
|
|
742
|
+
eventType: string,
|
|
743
|
+
payload?: Record<string, unknown>
|
|
744
|
+
) => Promise<void>;
|
|
745
|
+
/**
|
|
746
|
+
* Build an IDataFunction over a Mythos collection — drop-in data source
|
|
747
|
+
* for DataList / DataTable. Mirrors UXP's fromLucyDataCollection.
|
|
748
|
+
* const fn = icanContext.fromMythosCollection('Inventory', 'items')
|
|
749
|
+
* const { items, pageToken } = await fn(50, '', { search: 'foo' })
|
|
750
|
+
* Optional — present only when MYTHOS_BASE_URL is configured.
|
|
751
|
+
*/
|
|
752
|
+
fromMythosCollection?: (
|
|
753
|
+
model: string,
|
|
754
|
+
collection: string
|
|
755
|
+
) => (
|
|
756
|
+
max: number,
|
|
757
|
+
lastPageToken: string,
|
|
758
|
+
args?: { search?: string } & Record<string, unknown>
|
|
759
|
+
) => Promise<{ items: Array<Record<string, unknown>>; pageToken: string }>;
|
|
710
760
|
/** Resolve a relative ICan backend path against the portal base URL. */
|
|
711
761
|
resolveUrl(path: string): string;
|
|
712
762
|
/** Logging helper namespaced to this widget instance. */
|
|
713
763
|
log(level: "info" | "warn" | "error", ...args: unknown[]): void;
|
|
714
764
|
}
|
|
765
|
+
|
|
766
|
+
/**
|
|
767
|
+
* A single Mythos action published as callable from a widget. Returned by
|
|
768
|
+
* `icanContext.listMythosActions()`. To invoke one, call
|
|
769
|
+
* `icanContext.executeAction('mythos:' + model_name, action_name, params)`.
|
|
770
|
+
*/
|
|
771
|
+
export interface IMythosAction {
|
|
772
|
+
model_id: string;
|
|
773
|
+
model_name: string;
|
|
774
|
+
action_id: string;
|
|
775
|
+
action_name: string;
|
|
776
|
+
description?: string;
|
|
777
|
+
capability?: string;
|
|
778
|
+
}
|
|
715
779
|
}
|
|
716
780
|
|
|
717
781
|
// ─── Global runtime declarations ─────────────────────────────────────────────
|
package/templates/index.html
CHANGED
|
@@ -1419,13 +1419,46 @@
|
|
|
1419
1419
|
orchUrl: localStorage.getItem(LS_ORCH_URL) || '',
|
|
1420
1420
|
apiKey: localStorage.getItem(LS_API_KEY) || '',
|
|
1421
1421
|
executeAction: function (model, action, params) {
|
|
1422
|
-
|
|
1422
|
+
// Mythos-routed calls use the `mythos:<ModelName>` prefix in production.
|
|
1423
|
+
// In the dev harness we just log them distinctively so authors can see
|
|
1424
|
+
// whether their widget is targeting ICan native or Mythos.
|
|
1425
|
+
var isMythos = typeof model === 'string' && model.toLowerCase().indexOf('mythos:') === 0;
|
|
1426
|
+
console.log('[ICan Dev]' + (isMythos ? ' [Mythos]' : '') + ' executeAction:', model, action, params);
|
|
1427
|
+
if (isMythos) {
|
|
1428
|
+
// Mock the Mythos response envelope: { run_id, status, output }.
|
|
1429
|
+
return Promise.resolve({ run_id: 'dev-' + Date.now(), status: 'ok', output: {} });
|
|
1430
|
+
}
|
|
1423
1431
|
return Promise.resolve([]);
|
|
1424
1432
|
},
|
|
1425
1433
|
executeService: function (app, service, params) {
|
|
1426
1434
|
console.log('[ICan Dev] executeService:', app, service, params);
|
|
1427
1435
|
return Promise.resolve(null);
|
|
1428
1436
|
},
|
|
1437
|
+
listMythosActions: function () {
|
|
1438
|
+
// Dev stub — returns a couple of synthetic actions so widgets that
|
|
1439
|
+
// populate dropdowns from discovery don't render empty.
|
|
1440
|
+
console.log('[ICan Dev] listMythosActions');
|
|
1441
|
+
return Promise.resolve([
|
|
1442
|
+
{ model_id: 'dev-model-1', model_name: 'Inventory', action_id: 'dev-action-1', action_name: 'UpdateStock', description: 'Dev stub' },
|
|
1443
|
+
{ model_id: 'dev-model-2', model_name: 'Buildings', action_id: 'dev-action-2', action_name: 'List', description: 'Dev stub' },
|
|
1444
|
+
]);
|
|
1445
|
+
},
|
|
1446
|
+
fireMythosEvent: function (eventType, payload) {
|
|
1447
|
+
console.log('[ICan Dev] fireMythosEvent:', eventType, payload);
|
|
1448
|
+
return Promise.resolve();
|
|
1449
|
+
},
|
|
1450
|
+
fromMythosCollection: function (model, collection) {
|
|
1451
|
+
return function (max, lastPageToken, args) {
|
|
1452
|
+
console.log('[ICan Dev] fromMythosCollection:', model, collection, { max: max, lastPageToken: lastPageToken, args: args });
|
|
1453
|
+
// Return one page of synthetic docs so DataList renders something.
|
|
1454
|
+
return Promise.resolve({
|
|
1455
|
+
items: Array.from({ length: Math.min(max, 5) }, function (_, i) {
|
|
1456
|
+
return { id: 'dev-' + i, name: model + ' row ' + i, value: i * 10 };
|
|
1457
|
+
}),
|
|
1458
|
+
pageToken: '',
|
|
1459
|
+
});
|
|
1460
|
+
};
|
|
1461
|
+
},
|
|
1429
1462
|
fireEvent: function (id) {
|
|
1430
1463
|
console.log('[ICan Dev] fireEvent:', id);
|
|
1431
1464
|
return Promise.resolve();
|
package/templates/ui.html
CHANGED
|
@@ -1123,13 +1123,40 @@
|
|
|
1123
1123
|
orchUrl: localStorage.getItem(LS_ORCH_URL) || '',
|
|
1124
1124
|
apiKey: localStorage.getItem(LS_API_KEY) || '',
|
|
1125
1125
|
executeAction: function (model, action, params) {
|
|
1126
|
-
|
|
1126
|
+
// Mythos-routed calls use the `mythos:<ModelName>` prefix.
|
|
1127
|
+
var isMythos = typeof model === 'string' && model.toLowerCase().indexOf('mythos:') === 0;
|
|
1128
|
+
console.log('[ICan Dev]' + (isMythos ? ' [Mythos]' : '') + ' executeAction:', model, action, params);
|
|
1129
|
+
if (isMythos) {
|
|
1130
|
+
return Promise.resolve({ run_id: 'dev-' + Date.now(), status: 'ok', output: {} });
|
|
1131
|
+
}
|
|
1127
1132
|
return Promise.resolve([]);
|
|
1128
1133
|
},
|
|
1129
1134
|
executeService: function (app, service, params) {
|
|
1130
1135
|
console.log('[ICan Dev] executeService:', app, service, params);
|
|
1131
1136
|
return Promise.resolve(null);
|
|
1132
1137
|
},
|
|
1138
|
+
listMythosActions: function () {
|
|
1139
|
+
console.log('[ICan Dev] listMythosActions');
|
|
1140
|
+
return Promise.resolve([
|
|
1141
|
+
{ model_id: 'dev-model-1', model_name: 'Inventory', action_id: 'dev-action-1', action_name: 'UpdateStock', description: 'Dev stub' },
|
|
1142
|
+
{ model_id: 'dev-model-2', model_name: 'Buildings', action_id: 'dev-action-2', action_name: 'List', description: 'Dev stub' },
|
|
1143
|
+
]);
|
|
1144
|
+
},
|
|
1145
|
+
fireMythosEvent: function (eventType, payload) {
|
|
1146
|
+
console.log('[ICan Dev] fireMythosEvent:', eventType, payload);
|
|
1147
|
+
return Promise.resolve();
|
|
1148
|
+
},
|
|
1149
|
+
fromMythosCollection: function (model, collection) {
|
|
1150
|
+
return function (max, lastPageToken, args) {
|
|
1151
|
+
console.log('[ICan Dev] fromMythosCollection:', model, collection, { max: max, lastPageToken: lastPageToken, args: args });
|
|
1152
|
+
return Promise.resolve({
|
|
1153
|
+
items: Array.from({ length: Math.min(max, 5) }, function (_, i) {
|
|
1154
|
+
return { id: 'dev-' + i, name: model + ' row ' + i, value: i * 10 };
|
|
1155
|
+
}),
|
|
1156
|
+
pageToken: '',
|
|
1157
|
+
});
|
|
1158
|
+
};
|
|
1159
|
+
},
|
|
1133
1160
|
fireEvent: function (id) {
|
|
1134
1161
|
console.log('[ICan Dev] fireEvent:', id);
|
|
1135
1162
|
return Promise.resolve();
|