@mintplayer/ng-spark 22.3.0 → 22.4.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/fesm2022/mintplayer-ng-spark-client-operations.mjs +10 -1
- package/fesm2022/mintplayer-ng-spark-client-operations.mjs.map +1 -1
- package/fesm2022/mintplayer-ng-spark-grid.mjs +772 -23
- package/fesm2022/mintplayer-ng-spark-grid.mjs.map +1 -1
- package/fesm2022/mintplayer-ng-spark-models.mjs +49 -1
- package/fesm2022/mintplayer-ng-spark-models.mjs.map +1 -1
- package/fesm2022/mintplayer-ng-spark-pipes.mjs +31 -5
- package/fesm2022/mintplayer-ng-spark-pipes.mjs.map +1 -1
- package/fesm2022/mintplayer-ng-spark-po-detail.mjs +28 -302
- package/fesm2022/mintplayer-ng-spark-po-detail.mjs.map +1 -1
- package/fesm2022/mintplayer-ng-spark-po-form.mjs +4 -4
- package/fesm2022/mintplayer-ng-spark-po-form.mjs.map +1 -1
- package/fesm2022/mintplayer-ng-spark-query-list.mjs +137 -308
- package/fesm2022/mintplayer-ng-spark-query-list.mjs.map +1 -1
- package/fesm2022/mintplayer-ng-spark-retry-action-modal.mjs +5 -3
- package/fesm2022/mintplayer-ng-spark-retry-action-modal.mjs.map +1 -1
- package/fesm2022/mintplayer-ng-spark.mjs +1 -1
- package/fesm2022/mintplayer-ng-spark.mjs.map +1 -1
- package/package.json +2 -2
- package/types/mintplayer-ng-spark-client-operations.d.ts +10 -1
- package/types/mintplayer-ng-spark-grid.d.ts +455 -19
- package/types/mintplayer-ng-spark-models.d.ts +26 -2
- package/types/mintplayer-ng-spark-po-detail.d.ts +18 -139
- package/types/mintplayer-ng-spark-query-list.d.ts +53 -66
|
@@ -166,7 +166,16 @@ class SparkQueryRefreshService {
|
|
|
166
166
|
return 0;
|
|
167
167
|
return this.tokens()[queryId] ?? 0;
|
|
168
168
|
}
|
|
169
|
-
/**
|
|
169
|
+
/**
|
|
170
|
+
* Ask every grid showing `queryId` to re-fetch.
|
|
171
|
+
*
|
|
172
|
+
* Matched on the EXACT string a grid passes to {@link tokenFor} -- whichever of id or alias
|
|
173
|
+
* its `queryId` input holds. A caller that knows only the other form will not reach it.
|
|
174
|
+
*
|
|
175
|
+
* Callers bumping several keys for one user action should do so in one synchronous run: the
|
|
176
|
+
* signal coalesces bumps within a tick into a single effect run, and bumps split across an
|
|
177
|
+
* await become one re-fetch each.
|
|
178
|
+
*/
|
|
170
179
|
request(queryId) {
|
|
171
180
|
this.tokens.update(current => ({ ...current, [queryId]: (current[queryId] ?? 0) + 1 }));
|
|
172
181
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"mintplayer-ng-spark-client-operations.mjs","sources":["../../client-operations/src/operations.ts","../../client-operations/src/handlers.token.ts","../../client-operations/src/dispatcher.service.ts","../../client-operations/src/notification.service.ts","../../client-operations/src/toast-container.component.ts","../../client-operations/src/query-refresh.service.ts","../../client-operations/src/provide.ts","../../client-operations/mintplayer-ng-spark-client-operations.ts"],"sourcesContent":["// Wire types matching MintPlayer.Spark.Abstractions.ClientOperations on the server.\n// Discriminator is the `type` field. Unknown operation types are silently dropped\n// by the dispatcher (forward-compat: new types can land server-side without updating\n// older clients).\n\nimport type { PersistentObject } from '@mintplayer/ng-spark/models';\n\nexport enum NotificationKind {\n Info = 0,\n Success = 1,\n Warning = 2,\n Error = 3,\n}\n\nexport interface NavigateOperation {\n type: 'navigate';\n objectTypeId?: string;\n id?: string;\n routeName?: string;\n}\n\nexport interface NotifyOperation {\n type: 'notify';\n message: string;\n kind: NotificationKind;\n durationMs?: number;\n}\n\nexport interface RefreshAttributeOperation {\n type: 'refreshAttribute';\n objectTypeId: string;\n id: string;\n attributeName: string;\n value?: unknown;\n}\n\nexport interface RefreshQueryOperation {\n type: 'refreshQuery';\n queryId: string;\n}\n\nexport type DisableTarget =\n | { kind: 'persistentObject'; objectTypeId: string; id: string }\n | { kind: 'query'; queryId: string }\n | { kind: 'currentResponse' }\n | { kind: 'session' };\n\nexport interface DisableActionOperation {\n type: 'disableAction';\n actionName: string;\n target: DisableTarget;\n}\n\nexport interface RetryOperation {\n type: 'retry';\n step: number;\n title: string;\n options: string[];\n defaultOption?: string | null;\n persistentObject?: PersistentObject | null;\n message?: string | null;\n}\n\n/**\n * Discriminated union of known operation types, plus an open shape for unknown\n * future operations. Handlers should narrow via the `type` discriminator before\n * accessing fields specific to their operation type.\n */\nexport type ClientOperation =\n | NavigateOperation\n | NotifyOperation\n | RefreshAttributeOperation\n | RefreshQueryOperation\n | DisableActionOperation\n | RetryOperation\n | { type: string; [key: string]: unknown };\n\n/**\n * Wire envelope returned by every action endpoint. `result` carries the primary\n * payload (the PersistentObject for a Create, the QueryResult for an Execute,\n * etc.); `operations` carries the side-effects the frontend dispatches.\n */\nexport interface ClientOperationEnvelope<T = unknown> {\n result: T | null;\n operations: ClientOperation[];\n}\n","import { InjectionToken } from '@angular/core';\nimport type { ClientOperation } from './operations';\n\n/**\n * A handler for a specific operation type. Receives the operation and\n * executes the side-effect (e.g. show a toast, navigate, refresh a query).\n * Handlers should `as`-narrow the operation to the type they registered for.\n */\nexport type ClientOperationHandler = (operation: ClientOperation) => void;\n\n/**\n * One entry in the multi-provider registration. Apps can register custom\n * handlers alongside the built-in ones to extend the operation set with\n * app-specific operation types.\n */\nexport interface ClientOperationHandlerRegistration {\n type: string;\n handler: ClientOperationHandler;\n}\n\n/**\n * Multi-provider token. `provideSparkClientOperations()` registers the\n * built-in handlers; apps can add their own with additional `multi: true`\n * providers using this token.\n */\nexport const SPARK_CLIENT_OPERATION_HANDLERS = new InjectionToken<readonly ClientOperationHandlerRegistration[]>(\n 'SPARK_CLIENT_OPERATION_HANDLERS',\n);\n","import { Injectable, inject } from '@angular/core';\nimport type { ClientOperation } from './operations';\nimport { SPARK_CLIENT_OPERATION_HANDLERS, type ClientOperationHandler } from './handlers.token';\n\n/**\n * Routes received operations to registered handlers. Unknown operation types\n * (no matching registration) are silently dropped — this is the forward-compat\n * contract that lets new operation types ship server-side without coordinated\n * client updates.\n *\n * Last-registered-wins on duplicate `type` values, matching standard\n * Angular multi-provider override semantics.\n *\n * R2-H19 — security contract for handler authors:\n * The dispatcher treats handler resolution as allow-list-by-type (unknown\n * types drop). It does NOT validate the *content* of each operation. Handlers\n * that act on URL-shaped fields (navigate, redirect, openWindow) MUST run\n * the value through `sanitizeReturnUrl` from `@mintplayer/ng-spark-auth/models`\n * (or an equivalent same-origin check) before acting on it. Otherwise a\n * single attribute-echo XSS or a single mid-channel byte flip on a non-TLS\n * path lets the server drive client navigation to an attacker host. The\n * built-in `notify` handler renders via Angular interpolation (escaped) so\n * it's safe to pass through, but anything more powerful must validate.\n */\n@Injectable({ providedIn: 'root' })\nexport class SparkClientOperationDispatcher {\n private readonly handlerMap: ReadonlyMap<string, ClientOperationHandler>;\n\n constructor() {\n const registrations = inject(SPARK_CLIENT_OPERATION_HANDLERS, { optional: true }) ?? [];\n const map = new Map<string, ClientOperationHandler>();\n for (const { type, handler } of registrations) {\n map.set(type, handler);\n }\n this.handlerMap = map;\n }\n\n dispatch(operations: readonly ClientOperation[] | null | undefined): void {\n if (!operations || operations.length === 0) return;\n for (const operation of operations) {\n const handler = this.handlerMap.get(operation.type);\n if (handler) {\n handler(operation);\n }\n // Unknown types: silently dropped (forward-compat).\n }\n }\n}\n","import { Injectable, signal } from '@angular/core';\nimport { NotificationKind } from './operations';\n\nexport interface SparkToast {\n id: string;\n message: string;\n kind: NotificationKind;\n durationMs: number;\n}\n\nconst DEFAULT_DURATION_MS = 4000;\n\n/**\n * Holds the active toasts as a signal. The `<spark-toast-container>` component\n * renders them; the built-in `notify` operation handler pushes new toasts here.\n *\n * Auto-dismissal: each toast schedules its own removal after `durationMs`. Pass\n * `0` to make a toast sticky (manual dismissal only).\n */\n@Injectable({ providedIn: 'root' })\nexport class SparkNotificationService {\n private readonly _toasts = signal<readonly SparkToast[]>([]);\n readonly toasts = this._toasts.asReadonly();\n\n show(message: string, kind: NotificationKind = NotificationKind.Info, durationMs?: number): void {\n const id = typeof crypto !== 'undefined' && crypto.randomUUID ? crypto.randomUUID() : `${Date.now()}-${Math.random()}`;\n const effectiveDuration = durationMs ?? DEFAULT_DURATION_MS;\n const toast: SparkToast = { id, message, kind, durationMs: effectiveDuration };\n this._toasts.update(toasts => [...toasts, toast]);\n\n if (effectiveDuration > 0) {\n setTimeout(() => this.dismiss(id), effectiveDuration);\n }\n }\n\n dismiss(id: string): void {\n this._toasts.update(toasts => toasts.filter(t => t.id !== id));\n }\n\n clear(): void {\n this._toasts.set([]);\n }\n}\n","import { ChangeDetectionStrategy, Component, inject } from '@angular/core';\nimport { SparkNotificationService } from './notification.service';\nimport { NotificationKind } from './operations';\n\n@Component({\n selector: 'spark-toast-container',\n standalone: true,\n template: `\n <div class=\"spark-toast-container\">\n @for (toast of notifications.toasts(); track toast.id) {\n <div\n class=\"spark-toast\"\n [class.spark-toast--info]=\"toast.kind === Kind.Info\"\n [class.spark-toast--success]=\"toast.kind === Kind.Success\"\n [class.spark-toast--warning]=\"toast.kind === Kind.Warning\"\n [class.spark-toast--error]=\"toast.kind === Kind.Error\"\n (click)=\"notifications.dismiss(toast.id)\"\n >\n {{ toast.message }}\n </div>\n }\n </div>\n `,\n styles: [`\n .spark-toast-container {\n position: fixed;\n top: 1rem;\n right: 1rem;\n z-index: 9999;\n display: flex;\n flex-direction: column;\n gap: 0.5rem;\n pointer-events: none;\n }\n .spark-toast {\n padding: 0.75rem 1rem;\n border-radius: 4px;\n box-shadow: 0 2px 8px rgba(0, 0, 0, 0.15);\n cursor: pointer;\n min-width: 220px;\n max-width: 400px;\n color: white;\n font-size: 0.95rem;\n pointer-events: auto;\n animation: spark-toast-in 0.18s ease-out;\n }\n .spark-toast--info { background: #0d6efd; }\n .spark-toast--success { background: #198754; }\n .spark-toast--warning { background: #ffc107; color: #000; }\n .spark-toast--error { background: #dc3545; }\n @keyframes spark-toast-in {\n from { opacity: 0; transform: translateX(8px); }\n to { opacity: 1; transform: translateX(0); }\n }\n `],\n changeDetection: ChangeDetectionStrategy.OnPush,\n})\nexport class SparkToastContainerComponent {\n protected readonly notifications = inject(SparkNotificationService);\n protected readonly Kind = NotificationKind;\n}\n","import { Injectable, signal } from '@angular/core';\n\n/**\n * Carries a server-issued `refreshQuery` to whichever grids are showing that query.\n *\n * A broadcast signal rather than a registry of component handles: grids come and go behind\n * `@if` and lazy routes, and nothing else in ng-spark holds a component reference. A grid\n * reads {@link tokenFor} in an effect and re-fetches when it changes, which is the same\n * declarative shape as the `reloadToken` input a host would use.\n *\n * Until this existed the server could emit the operation and the dispatcher dropped it: only\n * `notify` was registered, and unknown types are ignored silently — so `refreshOnCompleted`\n * on the server had no effect on any grid the action did not happen to be hosted in.\n */\n@Injectable({ providedIn: 'root' })\nexport class SparkQueryRefreshService {\n private readonly tokens = signal<Record<string, number>>({});\n\n /** Bumped every time the server asks for this query to refresh. */\n tokenFor(queryId: string | undefined): number {\n if (!queryId) return 0;\n return this.tokens()[queryId] ?? 0;\n }\n\n /** Ask every grid showing `queryId` to re-fetch. Matched on id AND alias, since a grid may hold either. */\n request(queryId: string): void {\n this.tokens.update(current => ({ ...current, [queryId]: (current[queryId] ?? 0) + 1 }));\n }\n}\n","import { type EnvironmentProviders, inject, makeEnvironmentProviders } from '@angular/core';\nimport type { ClientOperation, DisableActionOperation, NotifyOperation, RefreshQueryOperation } from './operations';\nimport { SPARK_CLIENT_OPERATION_HANDLERS } from './handlers.token';\nimport { SparkNotificationService } from './notification.service';\nimport { SparkQueryRefreshService } from './query-refresh.service';\n\n/**\n * Registers the built-in client-operation handlers: `notify` and `refreshQuery`.\n * Apps add this once in their bootstrap providers.\n *\n * Unregistered operation types are dropped SILENTLY by the dispatcher, which is why\n * `refreshQuery` did nothing at all for as long as it went unhandled — the server emitted\n * it, nothing listened, and no error said so. `disableAction` is in that state today: it is\n * registered below purely to log, so the gap is visible rather than invisible.\n *\n * To register custom operation types alongside the built-ins, add additional\n * `multi: true` providers using <see cref=\"SPARK_CLIENT_OPERATION_HANDLERS\" />.\n */\nexport function provideSparkClientOperations(): EnvironmentProviders {\n return makeEnvironmentProviders([\n {\n provide: SPARK_CLIENT_OPERATION_HANDLERS,\n useFactory: () => {\n const notifications = inject(SparkNotificationService);\n return {\n type: 'notify',\n handler: (operation: ClientOperation) => {\n const notify = operation as NotifyOperation;\n notifications.show(notify.message, notify.kind, notify.durationMs);\n },\n };\n },\n multi: true,\n },\n {\n provide: SPARK_CLIENT_OPERATION_HANDLERS,\n useFactory: () => {\n const refresh = inject(SparkQueryRefreshService);\n return {\n type: 'refreshQuery',\n handler: (operation: ClientOperation) => {\n refresh.request((operation as RefreshQueryOperation).queryId);\n },\n };\n },\n multi: true,\n },\n {\n provide: SPARK_CLIENT_OPERATION_HANDLERS,\n useFactory: () => ({\n type: 'disableAction',\n handler: (operation: ClientOperation) => {\n // Deliberately a no-op with a warning, not silence. The server's\n // IClientAccessor.DisableQueryActions presumes a client that honours it;\n // nothing renders the disabled state yet, and a silently dropped operation\n // reads as \"the server did not send it\" when debugging.\n const disable = operation as DisableActionOperation;\n console.warn(\n `[spark] disableAction('${disable.actionName}') is not implemented by this client; the action stays enabled.`);\n },\n }),\n multi: true,\n },\n ]);\n}\n","/**\n * Generated bundle index. Do not edit.\n */\n\nexport * from './index';\n"],"names":[],"mappings":";;;AAAA;AACA;AACA;AACA;IAIY;AAAZ,CAAA,UAAY,gBAAgB,EAAA;AACxB,IAAA,gBAAA,CAAA,gBAAA,CAAA,MAAA,CAAA,GAAA,CAAA,CAAA,GAAA,MAAQ;AACR,IAAA,gBAAA,CAAA,gBAAA,CAAA,SAAA,CAAA,GAAA,CAAA,CAAA,GAAA,SAAW;AACX,IAAA,gBAAA,CAAA,gBAAA,CAAA,SAAA,CAAA,GAAA,CAAA,CAAA,GAAA,SAAW;AACX,IAAA,gBAAA,CAAA,gBAAA,CAAA,OAAA,CAAA,GAAA,CAAA,CAAA,GAAA,OAAS;AACb,CAAC,EALW,gBAAgB,KAAhB,gBAAgB,GAAA,EAAA,CAAA,CAAA;;ACa5B;;;;AAIG;MACU,+BAA+B,GAAG,IAAI,cAAc,CAC7D,iCAAiC;;ACtBrC;;;;;;;;;;;;;;;;;;;AAmBG;MAEU,8BAA8B,CAAA;AACtB,IAAA,UAAU;AAE3B,IAAA,WAAA,GAAA;AACI,QAAA,MAAM,aAAa,GAAG,MAAM,CAAC,+BAA+B,EAAE,EAAE,QAAQ,EAAE,IAAI,EAAE,CAAC,IAAI,EAAE;AACvF,QAAA,MAAM,GAAG,GAAG,IAAI,GAAG,EAAkC;QACrD,KAAK,MAAM,EAAE,IAAI,EAAE,OAAO,EAAE,IAAI,aAAa,EAAE;AAC3C,YAAA,GAAG,CAAC,GAAG,CAAC,IAAI,EAAE,OAAO,CAAC;QAC1B;AACA,QAAA,IAAI,CAAC,UAAU,GAAG,GAAG;IACzB;AAEA,IAAA,QAAQ,CAAC,UAAyD,EAAA;AAC9D,QAAA,IAAI,CAAC,UAAU,IAAI,UAAU,CAAC,MAAM,KAAK,CAAC;YAAE;AAC5C,QAAA,KAAK,MAAM,SAAS,IAAI,UAAU,EAAE;AAChC,YAAA,MAAM,OAAO,GAAG,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC,SAAS,CAAC,IAAI,CAAC;YACnD,IAAI,OAAO,EAAE;gBACT,OAAO,CAAC,SAAS,CAAC;YACtB;;QAEJ;IACJ;uGArBS,8BAA8B,EAAA,IAAA,EAAA,EAAA,EAAA,MAAA,EAAA,EAAA,CAAA,eAAA,CAAA,UAAA,EAAA,CAAA;AAA9B,IAAA,OAAA,KAAA,GAAA,EAAA,CAAA,qBAAA,CAAA,EAAA,UAAA,EAAA,QAAA,EAAA,OAAA,EAAA,QAAA,EAAA,QAAA,EAAA,EAAA,EAAA,IAAA,EAAA,8BAA8B,cADjB,MAAM,EAAA,CAAA;;2FACnB,8BAA8B,EAAA,UAAA,EAAA,CAAA;kBAD1C,UAAU;mBAAC,EAAE,UAAU,EAAE,MAAM,EAAE;;;ACdlC,MAAM,mBAAmB,GAAG,IAAI;AAEhC;;;;;;AAMG;MAEU,wBAAwB,CAAA;IAChB,OAAO,GAAG,MAAM,CAAwB,EAAE;gFAAC;AACnD,IAAA,MAAM,GAAG,IAAI,CAAC,OAAO,CAAC,UAAU,EAAE;IAE3C,IAAI,CAAC,OAAe,EAAE,IAAA,GAAyB,gBAAgB,CAAC,IAAI,EAAE,UAAmB,EAAA;AACrF,QAAA,MAAM,EAAE,GAAG,OAAO,MAAM,KAAK,WAAW,IAAI,MAAM,CAAC,UAAU,GAAG,MAAM,CAAC,UAAU,EAAE,GAAG,CAAA,EAAG,IAAI,CAAC,GAAG,EAAE,CAAA,CAAA,EAAI,IAAI,CAAC,MAAM,EAAE,EAAE;AACtH,QAAA,MAAM,iBAAiB,GAAG,UAAU,IAAI,mBAAmB;AAC3D,QAAA,MAAM,KAAK,GAAe,EAAE,EAAE,EAAE,OAAO,EAAE,IAAI,EAAE,UAAU,EAAE,iBAAiB,EAAE;AAC9E,QAAA,IAAI,CAAC,OAAO,CAAC,MAAM,CAAC,MAAM,IAAI,CAAC,GAAG,MAAM,EAAE,KAAK,CAAC,CAAC;AAEjD,QAAA,IAAI,iBAAiB,GAAG,CAAC,EAAE;AACvB,YAAA,UAAU,CAAC,MAAM,IAAI,CAAC,OAAO,CAAC,EAAE,CAAC,EAAE,iBAAiB,CAAC;QACzD;IACJ;AAEA,IAAA,OAAO,CAAC,EAAU,EAAA;QACd,IAAI,CAAC,OAAO,CAAC,MAAM,CAAC,MAAM,IAAI,MAAM,CAAC,MAAM,CAAC,CAAC,IAAI,CAAC,CAAC,EAAE,KAAK,EAAE,CAAC,CAAC;IAClE;IAEA,KAAK,GAAA;AACD,QAAA,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,EAAE,CAAC;IACxB;uGArBS,wBAAwB,EAAA,IAAA,EAAA,EAAA,EAAA,MAAA,EAAA,EAAA,CAAA,eAAA,CAAA,UAAA,EAAA,CAAA;AAAxB,IAAA,OAAA,KAAA,GAAA,EAAA,CAAA,qBAAA,CAAA,EAAA,UAAA,EAAA,QAAA,EAAA,OAAA,EAAA,QAAA,EAAA,QAAA,EAAA,EAAA,EAAA,IAAA,EAAA,wBAAwB,cADX,MAAM,EAAA,CAAA;;2FACnB,wBAAwB,EAAA,UAAA,EAAA,CAAA;kBADpC,UAAU;mBAAC,EAAE,UAAU,EAAE,MAAM,EAAE;;;MCsCrB,4BAA4B,CAAA;AAClB,IAAA,aAAa,GAAG,MAAM,CAAC,wBAAwB,CAAC;IAChD,IAAI,GAAG,gBAAgB;uGAFjC,4BAA4B,EAAA,IAAA,EAAA,EAAA,EAAA,MAAA,EAAA,EAAA,CAAA,eAAA,CAAA,SAAA,EAAA,CAAA;AAA5B,IAAA,OAAA,IAAA,GAAA,EAAA,CAAA,oBAAA,CAAA,EAAA,UAAA,EAAA,QAAA,EAAA,OAAA,EAAA,QAAA,EAAA,IAAA,EAAA,4BAA4B,EAAA,YAAA,EAAA,IAAA,EAAA,QAAA,EAAA,uBAAA,EAAA,QAAA,EAAA,EAAA,EAAA,QAAA,EAlD3B;;;;;;;;;;;;;;;AAeT,IAAA,CAAA,EAAA,QAAA,EAAA,IAAA,EAAA,MAAA,EAAA,CAAA,mnBAAA,CAAA,EAAA,eAAA,EAAA,EAAA,CAAA,uBAAA,CAAA,MAAA,EAAA,CAAA;;2FAmCQ,4BAA4B,EAAA,UAAA,EAAA,CAAA;kBArDxC,SAAS;+BACI,uBAAuB,EAAA,UAAA,EACrB,IAAI,EAAA,QAAA,EACN;;;;;;;;;;;;;;;KAeT,EAAA,eAAA,EAiCgB,uBAAuB,CAAC,MAAM,EAAA,MAAA,EAAA,CAAA,mnBAAA,CAAA,EAAA;;;ACrDnD;;;;;;;;;;;AAWG;MAEU,wBAAwB,CAAA;IAClB,MAAM,GAAG,MAAM,CAAyB,EAAE;+EAAC;;AAG5D,IAAA,QAAQ,CAAC,OAA2B,EAAA;AAClC,QAAA,IAAI,CAAC,OAAO;AAAE,YAAA,OAAO,CAAC;QACtB,OAAO,IAAI,CAAC,MAAM,EAAE,CAAC,OAAO,CAAC,IAAI,CAAC;IACpC;;AAGA,IAAA,OAAO,CAAC,OAAe,EAAA;AACrB,QAAA,IAAI,CAAC,MAAM,CAAC,MAAM,CAAC,OAAO,KAAK,EAAE,GAAG,OAAO,EAAE,CAAC,OAAO,GAAG,CAAC,OAAO,CAAC,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;IACzF;uGAZW,wBAAwB,EAAA,IAAA,EAAA,EAAA,EAAA,MAAA,EAAA,EAAA,CAAA,eAAA,CAAA,UAAA,EAAA,CAAA;AAAxB,IAAA,OAAA,KAAA,GAAA,EAAA,CAAA,qBAAA,CAAA,EAAA,UAAA,EAAA,QAAA,EAAA,OAAA,EAAA,QAAA,EAAA,QAAA,EAAA,EAAA,EAAA,IAAA,EAAA,wBAAwB,cADX,MAAM,EAAA,CAAA;;2FACnB,wBAAwB,EAAA,UAAA,EAAA,CAAA;kBADpC,UAAU;mBAAC,EAAE,UAAU,EAAE,MAAM,EAAE;;;ACRlC;;;;;;;;;;;AAWG;SACa,4BAA4B,GAAA;AACxC,IAAA,OAAO,wBAAwB,CAAC;AAC5B,QAAA;AACI,YAAA,OAAO,EAAE,+BAA+B;YACxC,UAAU,EAAE,MAAK;AACb,gBAAA,MAAM,aAAa,GAAG,MAAM,CAAC,wBAAwB,CAAC;gBACtD,OAAO;AACH,oBAAA,IAAI,EAAE,QAAQ;AACd,oBAAA,OAAO,EAAE,CAAC,SAA0B,KAAI;wBACpC,MAAM,MAAM,GAAG,SAA4B;AAC3C,wBAAA,aAAa,CAAC,IAAI,CAAC,MAAM,CAAC,OAAO,EAAE,MAAM,CAAC,IAAI,EAAE,MAAM,CAAC,UAAU,CAAC;oBACtE,CAAC;iBACJ;YACL,CAAC;AACD,YAAA,KAAK,EAAE,IAAI;AACd,SAAA;AACD,QAAA;AACI,YAAA,OAAO,EAAE,+BAA+B;YACxC,UAAU,EAAE,MAAK;AACb,gBAAA,MAAM,OAAO,GAAG,MAAM,CAAC,wBAAwB,CAAC;gBAChD,OAAO;AACH,oBAAA,IAAI,EAAE,cAAc;AACpB,oBAAA,OAAO,EAAE,CAAC,SAA0B,KAAI;AACpC,wBAAA,OAAO,CAAC,OAAO,CAAE,SAAmC,CAAC,OAAO,CAAC;oBACjE,CAAC;iBACJ;YACL,CAAC;AACD,YAAA,KAAK,EAAE,IAAI;AACd,SAAA;AACD,QAAA;AACI,YAAA,OAAO,EAAE,+BAA+B;AACxC,YAAA,UAAU,EAAE,OAAO;AACf,gBAAA,IAAI,EAAE,eAAe;AACrB,gBAAA,OAAO,EAAE,CAAC,SAA0B,KAAI;;;;;oBAKpC,MAAM,OAAO,GAAG,SAAmC;oBACnD,OAAO,CAAC,IAAI,CACR,CAAA,uBAAA,EAA0B,OAAO,CAAC,UAAU,CAAA,+DAAA,CAAiE,CAAC;gBACtH,CAAC;aACJ,CAAC;AACF,YAAA,KAAK,EAAE,IAAI;AACd,SAAA;AACJ,KAAA,CAAC;AACN;;AChEA;;AAEG;;;;"}
|
|
1
|
+
{"version":3,"file":"mintplayer-ng-spark-client-operations.mjs","sources":["../../client-operations/src/operations.ts","../../client-operations/src/handlers.token.ts","../../client-operations/src/dispatcher.service.ts","../../client-operations/src/notification.service.ts","../../client-operations/src/toast-container.component.ts","../../client-operations/src/query-refresh.service.ts","../../client-operations/src/provide.ts","../../client-operations/mintplayer-ng-spark-client-operations.ts"],"sourcesContent":["// Wire types matching MintPlayer.Spark.Abstractions.ClientOperations on the server.\n// Discriminator is the `type` field. Unknown operation types are silently dropped\n// by the dispatcher (forward-compat: new types can land server-side without updating\n// older clients).\n\nimport type { PersistentObject } from '@mintplayer/ng-spark/models';\n\nexport enum NotificationKind {\n Info = 0,\n Success = 1,\n Warning = 2,\n Error = 3,\n}\n\nexport interface NavigateOperation {\n type: 'navigate';\n objectTypeId?: string;\n id?: string;\n routeName?: string;\n}\n\nexport interface NotifyOperation {\n type: 'notify';\n message: string;\n kind: NotificationKind;\n durationMs?: number;\n}\n\nexport interface RefreshAttributeOperation {\n type: 'refreshAttribute';\n objectTypeId: string;\n id: string;\n attributeName: string;\n value?: unknown;\n}\n\nexport interface RefreshQueryOperation {\n type: 'refreshQuery';\n queryId: string;\n}\n\nexport type DisableTarget =\n | { kind: 'persistentObject'; objectTypeId: string; id: string }\n | { kind: 'query'; queryId: string }\n | { kind: 'currentResponse' }\n | { kind: 'session' };\n\nexport interface DisableActionOperation {\n type: 'disableAction';\n actionName: string;\n target: DisableTarget;\n}\n\nexport interface RetryOperation {\n type: 'retry';\n step: number;\n title: string;\n options: string[];\n defaultOption?: string | null;\n persistentObject?: PersistentObject | null;\n message?: string | null;\n}\n\n/**\n * Discriminated union of known operation types, plus an open shape for unknown\n * future operations. Handlers should narrow via the `type` discriminator before\n * accessing fields specific to their operation type.\n */\nexport type ClientOperation =\n | NavigateOperation\n | NotifyOperation\n | RefreshAttributeOperation\n | RefreshQueryOperation\n | DisableActionOperation\n | RetryOperation\n | { type: string; [key: string]: unknown };\n\n/**\n * Wire envelope returned by every action endpoint. `result` carries the primary\n * payload (the PersistentObject for a Create, the QueryResult for an Execute,\n * etc.); `operations` carries the side-effects the frontend dispatches.\n */\nexport interface ClientOperationEnvelope<T = unknown> {\n result: T | null;\n operations: ClientOperation[];\n}\n","import { InjectionToken } from '@angular/core';\nimport type { ClientOperation } from './operations';\n\n/**\n * A handler for a specific operation type. Receives the operation and\n * executes the side-effect (e.g. show a toast, navigate, refresh a query).\n * Handlers should `as`-narrow the operation to the type they registered for.\n */\nexport type ClientOperationHandler = (operation: ClientOperation) => void;\n\n/**\n * One entry in the multi-provider registration. Apps can register custom\n * handlers alongside the built-in ones to extend the operation set with\n * app-specific operation types.\n */\nexport interface ClientOperationHandlerRegistration {\n type: string;\n handler: ClientOperationHandler;\n}\n\n/**\n * Multi-provider token. `provideSparkClientOperations()` registers the\n * built-in handlers; apps can add their own with additional `multi: true`\n * providers using this token.\n */\nexport const SPARK_CLIENT_OPERATION_HANDLERS = new InjectionToken<readonly ClientOperationHandlerRegistration[]>(\n 'SPARK_CLIENT_OPERATION_HANDLERS',\n);\n","import { Injectable, inject } from '@angular/core';\nimport type { ClientOperation } from './operations';\nimport { SPARK_CLIENT_OPERATION_HANDLERS, type ClientOperationHandler } from './handlers.token';\n\n/**\n * Routes received operations to registered handlers. Unknown operation types\n * (no matching registration) are silently dropped — this is the forward-compat\n * contract that lets new operation types ship server-side without coordinated\n * client updates.\n *\n * Last-registered-wins on duplicate `type` values, matching standard\n * Angular multi-provider override semantics.\n *\n * R2-H19 — security contract for handler authors:\n * The dispatcher treats handler resolution as allow-list-by-type (unknown\n * types drop). It does NOT validate the *content* of each operation. Handlers\n * that act on URL-shaped fields (navigate, redirect, openWindow) MUST run\n * the value through `sanitizeReturnUrl` from `@mintplayer/ng-spark-auth/models`\n * (or an equivalent same-origin check) before acting on it. Otherwise a\n * single attribute-echo XSS or a single mid-channel byte flip on a non-TLS\n * path lets the server drive client navigation to an attacker host. The\n * built-in `notify` handler renders via Angular interpolation (escaped) so\n * it's safe to pass through, but anything more powerful must validate.\n */\n@Injectable({ providedIn: 'root' })\nexport class SparkClientOperationDispatcher {\n private readonly handlerMap: ReadonlyMap<string, ClientOperationHandler>;\n\n constructor() {\n const registrations = inject(SPARK_CLIENT_OPERATION_HANDLERS, { optional: true }) ?? [];\n const map = new Map<string, ClientOperationHandler>();\n for (const { type, handler } of registrations) {\n map.set(type, handler);\n }\n this.handlerMap = map;\n }\n\n dispatch(operations: readonly ClientOperation[] | null | undefined): void {\n if (!operations || operations.length === 0) return;\n for (const operation of operations) {\n const handler = this.handlerMap.get(operation.type);\n if (handler) {\n handler(operation);\n }\n // Unknown types: silently dropped (forward-compat).\n }\n }\n}\n","import { Injectable, signal } from '@angular/core';\nimport { NotificationKind } from './operations';\n\nexport interface SparkToast {\n id: string;\n message: string;\n kind: NotificationKind;\n durationMs: number;\n}\n\nconst DEFAULT_DURATION_MS = 4000;\n\n/**\n * Holds the active toasts as a signal. The `<spark-toast-container>` component\n * renders them; the built-in `notify` operation handler pushes new toasts here.\n *\n * Auto-dismissal: each toast schedules its own removal after `durationMs`. Pass\n * `0` to make a toast sticky (manual dismissal only).\n */\n@Injectable({ providedIn: 'root' })\nexport class SparkNotificationService {\n private readonly _toasts = signal<readonly SparkToast[]>([]);\n readonly toasts = this._toasts.asReadonly();\n\n show(message: string, kind: NotificationKind = NotificationKind.Info, durationMs?: number): void {\n const id = typeof crypto !== 'undefined' && crypto.randomUUID ? crypto.randomUUID() : `${Date.now()}-${Math.random()}`;\n const effectiveDuration = durationMs ?? DEFAULT_DURATION_MS;\n const toast: SparkToast = { id, message, kind, durationMs: effectiveDuration };\n this._toasts.update(toasts => [...toasts, toast]);\n\n if (effectiveDuration > 0) {\n setTimeout(() => this.dismiss(id), effectiveDuration);\n }\n }\n\n dismiss(id: string): void {\n this._toasts.update(toasts => toasts.filter(t => t.id !== id));\n }\n\n clear(): void {\n this._toasts.set([]);\n }\n}\n","import { ChangeDetectionStrategy, Component, inject } from '@angular/core';\nimport { SparkNotificationService } from './notification.service';\nimport { NotificationKind } from './operations';\n\n@Component({\n selector: 'spark-toast-container',\n standalone: true,\n template: `\n <div class=\"spark-toast-container\">\n @for (toast of notifications.toasts(); track toast.id) {\n <div\n class=\"spark-toast\"\n [class.spark-toast--info]=\"toast.kind === Kind.Info\"\n [class.spark-toast--success]=\"toast.kind === Kind.Success\"\n [class.spark-toast--warning]=\"toast.kind === Kind.Warning\"\n [class.spark-toast--error]=\"toast.kind === Kind.Error\"\n (click)=\"notifications.dismiss(toast.id)\"\n >\n {{ toast.message }}\n </div>\n }\n </div>\n `,\n styles: [`\n .spark-toast-container {\n position: fixed;\n top: 1rem;\n right: 1rem;\n z-index: 9999;\n display: flex;\n flex-direction: column;\n gap: 0.5rem;\n pointer-events: none;\n }\n .spark-toast {\n padding: 0.75rem 1rem;\n border-radius: 4px;\n box-shadow: 0 2px 8px rgba(0, 0, 0, 0.15);\n cursor: pointer;\n min-width: 220px;\n max-width: 400px;\n color: white;\n font-size: 0.95rem;\n pointer-events: auto;\n animation: spark-toast-in 0.18s ease-out;\n }\n .spark-toast--info { background: #0d6efd; }\n .spark-toast--success { background: #198754; }\n .spark-toast--warning { background: #ffc107; color: #000; }\n .spark-toast--error { background: #dc3545; }\n @keyframes spark-toast-in {\n from { opacity: 0; transform: translateX(8px); }\n to { opacity: 1; transform: translateX(0); }\n }\n `],\n changeDetection: ChangeDetectionStrategy.OnPush,\n})\nexport class SparkToastContainerComponent {\n protected readonly notifications = inject(SparkNotificationService);\n protected readonly Kind = NotificationKind;\n}\n","import { Injectable, signal } from '@angular/core';\n\n/**\n * Carries a server-issued `refreshQuery` to whichever grids are showing that query.\n *\n * A broadcast signal rather than a registry of component handles: grids come and go behind\n * `@if` and lazy routes, and nothing else in ng-spark holds a component reference. A grid\n * reads {@link tokenFor} in an effect and re-fetches when it changes, which is the same\n * declarative shape as the `reloadToken` input a host would use.\n *\n * Until this existed the server could emit the operation and the dispatcher dropped it: only\n * `notify` was registered, and unknown types are ignored silently — so `refreshOnCompleted`\n * on the server had no effect on any grid the action did not happen to be hosted in.\n */\n@Injectable({ providedIn: 'root' })\nexport class SparkQueryRefreshService {\n private readonly tokens = signal<Record<string, number>>({});\n\n /** Bumped every time the server asks for this query to refresh. */\n tokenFor(queryId: string | undefined): number {\n if (!queryId) return 0;\n return this.tokens()[queryId] ?? 0;\n }\n\n /**\n * Ask every grid showing `queryId` to re-fetch.\n *\n * Matched on the EXACT string a grid passes to {@link tokenFor} -- whichever of id or alias\n * its `queryId` input holds. A caller that knows only the other form will not reach it.\n *\n * Callers bumping several keys for one user action should do so in one synchronous run: the\n * signal coalesces bumps within a tick into a single effect run, and bumps split across an\n * await become one re-fetch each.\n */\n request(queryId: string): void {\n this.tokens.update(current => ({ ...current, [queryId]: (current[queryId] ?? 0) + 1 }));\n }\n}\n","import { type EnvironmentProviders, inject, makeEnvironmentProviders } from '@angular/core';\nimport type { ClientOperation, DisableActionOperation, NotifyOperation, RefreshQueryOperation } from './operations';\nimport { SPARK_CLIENT_OPERATION_HANDLERS } from './handlers.token';\nimport { SparkNotificationService } from './notification.service';\nimport { SparkQueryRefreshService } from './query-refresh.service';\n\n/**\n * Registers the built-in client-operation handlers: `notify` and `refreshQuery`.\n * Apps add this once in their bootstrap providers.\n *\n * Unregistered operation types are dropped SILENTLY by the dispatcher, which is why\n * `refreshQuery` did nothing at all for as long as it went unhandled — the server emitted\n * it, nothing listened, and no error said so. `disableAction` is in that state today: it is\n * registered below purely to log, so the gap is visible rather than invisible.\n *\n * To register custom operation types alongside the built-ins, add additional\n * `multi: true` providers using <see cref=\"SPARK_CLIENT_OPERATION_HANDLERS\" />.\n */\nexport function provideSparkClientOperations(): EnvironmentProviders {\n return makeEnvironmentProviders([\n {\n provide: SPARK_CLIENT_OPERATION_HANDLERS,\n useFactory: () => {\n const notifications = inject(SparkNotificationService);\n return {\n type: 'notify',\n handler: (operation: ClientOperation) => {\n const notify = operation as NotifyOperation;\n notifications.show(notify.message, notify.kind, notify.durationMs);\n },\n };\n },\n multi: true,\n },\n {\n provide: SPARK_CLIENT_OPERATION_HANDLERS,\n useFactory: () => {\n const refresh = inject(SparkQueryRefreshService);\n return {\n type: 'refreshQuery',\n handler: (operation: ClientOperation) => {\n refresh.request((operation as RefreshQueryOperation).queryId);\n },\n };\n },\n multi: true,\n },\n {\n provide: SPARK_CLIENT_OPERATION_HANDLERS,\n useFactory: () => ({\n type: 'disableAction',\n handler: (operation: ClientOperation) => {\n // Deliberately a no-op with a warning, not silence. The server's\n // IClientAccessor.DisableQueryActions presumes a client that honours it;\n // nothing renders the disabled state yet, and a silently dropped operation\n // reads as \"the server did not send it\" when debugging.\n const disable = operation as DisableActionOperation;\n console.warn(\n `[spark] disableAction('${disable.actionName}') is not implemented by this client; the action stays enabled.`);\n },\n }),\n multi: true,\n },\n ]);\n}\n","/**\n * Generated bundle index. Do not edit.\n */\n\nexport * from './index';\n"],"names":[],"mappings":"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"}
|