@things-factory/ai-dashboard 10.1.255 → 10.1.257

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.
@@ -6,13 +6,19 @@ import { __decorate, __metadata } from "tslib";
6
6
  */
7
7
  import '@material/web/icon/icon.js';
8
8
  import '@things-factory/ai-assistant/dist-client/index.js';
9
+ import gql from 'graphql-tag';
9
10
  import { LitElement, css, html, nothing } from 'lit';
10
- import { customElement, property, state } from 'lit/decorators.js';
11
+ import { customElement, property } from 'lit/decorators.js';
12
+ import { QueryController } from '@operato/graphql';
11
13
  import { i18next, localize } from '@operato/i18n';
12
- import { cardApi } from '../utils/card-api.js';
13
14
  import { drawsNothing, issueLine, partialLine } from '../utils/card-words.js';
14
15
  const t = (key, options = {}) => String(i18next.t(key, options));
15
16
  let ProposalPreview = class ProposalPreview extends localize(i18next)(LitElement) {
17
+ constructor() {
18
+ super(...arguments);
19
+ /* The proposal run as the viewer, for the proposal shown (ADR-0190). */
20
+ this.preview = new QueryController(this, gql `query ($s: String!, $k: String!) { dashboardCardProposalPreview(sessionId: $s, proposalKey: $k) }`, { variables: () => (this.sessionId && this.proposalKey ? { s: this.sessionId, k: this.proposalKey } : undefined) });
21
+ }
16
22
  static { this.styles = css `
17
23
  :host {
18
24
  display: block;
@@ -49,22 +55,12 @@ let ProposalPreview = class ProposalPreview extends localize(i18next)(LitElement
49
55
  color: var(--ui-warn, #b26a00);
50
56
  }
51
57
  `; }
52
- updated() {
53
- const key = this.sessionId && this.proposalKey ? `${this.sessionId}/${this.proposalKey}` : undefined;
54
- if (key && key !== this.readFor)
55
- this.read(key);
58
+ get run() {
59
+ return this.preview.data?.dashboardCardProposalPreview;
56
60
  }
57
- async read(key) {
58
- this.readFor = key;
59
- try {
60
- const run = await cardApi.preview(this.sessionId, this.proposalKey);
61
- if (this.readFor === key)
62
- this.run = run;
63
- }
64
- catch (error) {
65
- if (this.readFor === key)
66
- this.failed = error?.message ?? String(error);
67
- }
61
+ get failed() {
62
+ const error = this.preview.error;
63
+ return error ? (error.message ?? String(error)) : undefined;
68
64
  }
69
65
  render() {
70
66
  if (this.failed)
@@ -96,14 +92,6 @@ __decorate([
96
92
  property({ attribute: false }),
97
93
  __metadata("design:type", String)
98
94
  ], ProposalPreview.prototype, "proposalKey", void 0);
99
- __decorate([
100
- state(),
101
- __metadata("design:type", Object)
102
- ], ProposalPreview.prototype, "run", void 0);
103
- __decorate([
104
- state(),
105
- __metadata("design:type", String)
106
- ], ProposalPreview.prototype, "failed", void 0);
107
95
  ProposalPreview = __decorate([
108
96
  customElement('ai-dashboard-proposal-preview')
109
97
  ], ProposalPreview);
@@ -1 +1 @@
1
- {"version":3,"file":"proposal-preview.js","sourceRoot":"","sources":["../../client/components/proposal-preview.ts"],"names":[],"mappings":"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","sourcesContent":["/*\n * The preview under a card the conversation offers (ADR-0160 decisions 6, 9). The proposal holds the definition only;\n * the preview asks the server to run it as whoever is looking at the conversation, so a value is never kept in the\n * conversation and nobody sees data their own doors do not open.\n */\nimport '@material/web/icon/icon.js'\nimport '@things-factory/ai-assistant/dist-client/index.js'\n\nimport { LitElement, css, html, nothing } from 'lit'\nimport { customElement, property, state } from 'lit/decorators.js'\n\nimport { i18next, localize } from '@operato/i18n'\n\nimport { cardApi, type CardRun } from '../utils/card-api.js'\nimport { drawsNothing, issueLine, partialLine } from '../utils/card-words.js'\n\nconst t = (key: string, options: Record<string, unknown> = {}) => String(i18next.t(key, options))\n\n@customElement('ai-dashboard-proposal-preview')\nexport class ProposalPreview extends localize(i18next)(LitElement) {\n static styles = css`\n :host {\n display: block;\n margin: 4px 0 8px;\n }\n\n .frame {\n padding: 10px 12px 8px;\n border: 1px solid var(--md-sys-color-outline-variant);\n border-radius: 10px;\n background: var(--md-sys-color-surface-container-lowest);\n }\n\n .waiting,\n .note {\n font-size: 12px;\n color: var(--md-sys-color-on-surface-variant);\n }\n\n .note {\n display: flex;\n align-items: center;\n gap: 4px;\n margin-top: 6px;\n --md-icon-size: 14px;\n }\n\n .issue {\n font-size: 12px;\n color: var(--md-sys-color-error);\n }\n\n .partial {\n color: var(--ui-warn, #b26a00);\n }\n `\n\n @property({ attribute: false }) proposal: any\n @property({ attribute: false }) sessionId?: string\n @property({ attribute: false }) proposalKey?: string\n\n @state() private run?: CardRun\n @state() private failed?: string\n private readFor?: string\n\n updated() {\n const key = this.sessionId && this.proposalKey ? `${this.sessionId}/${this.proposalKey}` : undefined\n if (key && key !== this.readFor) this.read(key)\n }\n\n private async read(key: string) {\n this.readFor = key\n try {\n const run = await cardApi.preview(this.sessionId!, this.proposalKey!)\n if (this.readFor === key) this.run = run\n } catch (error: any) {\n if (this.readFor === key) this.failed = error?.message ?? String(error)\n }\n }\n\n render() {\n if (this.failed) return html`<div class=\"frame issue\">${this.failed}</div>`\n if (!this.run) return html`<div class=\"frame waiting\">${t('ai-dashboard.preview.reading')}</div>`\n const issue = issueLine(this.run, t)\n const partial = partialLine(this.run, t)\n return html`<div class=\"frame\">\n ${issue\n ? html`<div class=\"issue\">${issue.text}</div>`\n : drawsNothing(this.run)\n ? html`<div class=\"waiting\">${t('ai-dashboard.card.nothing')}</div>`\n : html`<ox-assistant-workspace-view compact .workspace=${{ name: this.proposalKey, title: this.proposal?.card?.name ?? '', blocks: [this.run.block] }}></ox-assistant-workspace-view>`}\n ${partial ? html`<div class=\"note partial\"><md-icon>warning</md-icon>${partial}</div>` : nothing}\n <div class=\"note\"><md-icon>bolt</md-icon>${t('ai-dashboard.preview.note', { day: this.run.asOf })}</div>\n </div>`\n }\n}\n"]}
1
+ {"version":3,"file":"proposal-preview.js","sourceRoot":"","sources":["../../client/components/proposal-preview.ts"],"names":[],"mappings":"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","sourcesContent":["/*\n * The preview under a card the conversation offers (ADR-0160 decisions 6, 9). The proposal holds the definition only;\n * the preview asks the server to run it as whoever is looking at the conversation, so a value is never kept in the\n * conversation and nobody sees data their own doors do not open.\n */\nimport '@material/web/icon/icon.js'\nimport '@things-factory/ai-assistant/dist-client/index.js'\n\nimport gql from 'graphql-tag'\nimport { LitElement, css, html, nothing } from 'lit'\nimport { customElement, property } from 'lit/decorators.js'\n\nimport { QueryController } from '@operato/graphql'\nimport { i18next, localize } from '@operato/i18n'\n\nimport { type CardRun } from '../utils/card-api.js'\nimport { drawsNothing, issueLine, partialLine } from '../utils/card-words.js'\n\nconst t = (key: string, options: Record<string, unknown> = {}) => String(i18next.t(key, options))\n\n@customElement('ai-dashboard-proposal-preview')\nexport class ProposalPreview extends localize(i18next)(LitElement) {\n static styles = css`\n :host {\n display: block;\n margin: 4px 0 8px;\n }\n\n .frame {\n padding: 10px 12px 8px;\n border: 1px solid var(--md-sys-color-outline-variant);\n border-radius: 10px;\n background: var(--md-sys-color-surface-container-lowest);\n }\n\n .waiting,\n .note {\n font-size: 12px;\n color: var(--md-sys-color-on-surface-variant);\n }\n\n .note {\n display: flex;\n align-items: center;\n gap: 4px;\n margin-top: 6px;\n --md-icon-size: 14px;\n }\n\n .issue {\n font-size: 12px;\n color: var(--md-sys-color-error);\n }\n\n .partial {\n color: var(--ui-warn, #b26a00);\n }\n `\n\n @property({ attribute: false }) proposal: any\n @property({ attribute: false }) sessionId?: string\n @property({ attribute: false }) proposalKey?: string\n\n /* The proposal run as the viewer, for the proposal shown (ADR-0190). */\n private preview = new QueryController(\n this,\n gql`query ($s: String!, $k: String!) { dashboardCardProposalPreview(sessionId: $s, proposalKey: $k) }`,\n { variables: () => (this.sessionId && this.proposalKey ? { s: this.sessionId, k: this.proposalKey } : undefined) }\n )\n\n private get run(): CardRun | undefined {\n return this.preview.data?.dashboardCardProposalPreview\n }\n\n private get failed(): string | undefined {\n const error = this.preview.error as any\n return error ? (error.message ?? String(error)) : undefined\n }\n\n render() {\n if (this.failed) return html`<div class=\"frame issue\">${this.failed}</div>`\n if (!this.run) return html`<div class=\"frame waiting\">${t('ai-dashboard.preview.reading')}</div>`\n const issue = issueLine(this.run, t)\n const partial = partialLine(this.run, t)\n return html`<div class=\"frame\">\n ${issue\n ? html`<div class=\"issue\">${issue.text}</div>`\n : drawsNothing(this.run)\n ? html`<div class=\"waiting\">${t('ai-dashboard.card.nothing')}</div>`\n : html`<ox-assistant-workspace-view compact .workspace=${{ name: this.proposalKey, title: this.proposal?.card?.name ?? '', blocks: [this.run.block] }}></ox-assistant-workspace-view>`}\n ${partial ? html`<div class=\"note partial\"><md-icon>warning</md-icon>${partial}</div>` : nothing}\n <div class=\"note\"><md-icon>bolt</md-icon>${t('ai-dashboard.preview.note', { day: this.run.asOf })}</div>\n </div>`\n }\n}\n"]}
@@ -5,10 +5,15 @@ import { PageView } from '@operato/shell';
5
5
  declare const MyDashboardPage_base: (new (...args: any[]) => import("lit").LitElement) & typeof PageView;
6
6
  export declare class MyDashboardPage extends MyDashboardPage_base {
7
7
  static styles: import("lit").CSSResult[];
8
- private places;
9
- private loaded;
10
- private error?;
11
8
  private editing;
9
+ /** The places as moved here, shown while the move is being saved. */
10
+ private arranged?;
11
+ private board;
12
+ private arranging;
13
+ private unplacing;
14
+ private get places();
15
+ private get loaded();
16
+ private get error();
12
17
  private onChanged;
13
18
  get context(): {
14
19
  title: string;
@@ -30,8 +35,6 @@ export declare class MyDashboardPage extends MyDashboardPage_base {
30
35
  connectedCallback(): void;
31
36
  disconnectedCallback(): void;
32
37
  updated(changes: Map<string, unknown>): void;
33
- pageUpdated(changes: any): Promise<void>;
34
- private load;
35
38
  render(): import("lit-html").TemplateResult<1>;
36
39
  private renderBoard;
37
40
  private renderEmpty;
@@ -9,14 +9,16 @@ import { __decorate, __metadata } from "tslib";
9
9
  import '@material/web/icon/icon.js';
10
10
  import '../components/dashboard-card.js';
11
11
  import '../components/card-library.js';
12
+ import gql from 'graphql-tag';
12
13
  import { css, html, nothing } from 'lit';
13
14
  import { customElement, state } from 'lit/decorators.js';
15
+ import { MutationController, QueryController } from '@operato/graphql';
14
16
  import { i18next, localize } from '@operato/i18n';
15
17
  import { notify, openPopup } from '@operato/layout';
16
18
  import { PageView } from '@operato/shell';
17
19
  import { DocumentPageStyles, ScrollbarStyles } from '@operato/styles';
18
20
  import { askAssistant } from '@things-factory/ai-assistant/dist-client/index.js';
19
- import { cardApi, DASHBOARD_CHANGED, dashboardChanged } from '../utils/card-api.js';
21
+ import { cardApi, CARD_FIELDS, DASHBOARD_CHANGED, dashboardChanged } from '../utils/card-api.js';
20
22
  import { movedPlaces } from '../utils/card-words.js';
21
23
  import { dashboardExamples } from '../utils/examples.js';
22
24
  import { openCardAiPrompt, openCardRename, openCardShare, openCardVersions } from '../components/card-dialogs.js';
@@ -24,10 +26,16 @@ const t = (key, options = {}) => String(i18next.t(key, options));
24
26
  let MyDashboardPage = class MyDashboardPage extends localize(i18next)(PageView) {
25
27
  constructor() {
26
28
  super(...arguments);
27
- this.places = [];
28
- this.loaded = false;
29
29
  this.editing = false;
30
- this.onChanged = () => this.load();
30
+ /* A page refresh, or a change told from elsewhere, reads the board again. */
31
+ this.board = new QueryController(this, gql `query { myDashboard { id order width height card { ${CARD_FIELDS} } } }`);
32
+ this.arranging = new MutationController(this, gql `mutation ($places: [DashboardPlaceInput!]!) { arrangeDashboard(places: $places) }`, {
33
+ refetch: () => [this.board]
34
+ });
35
+ this.unplacing = new MutationController(this, gql `mutation ($id: String!) { removeDashboardPlace(id: $id) }`, {
36
+ refetch: () => [this.board]
37
+ });
38
+ this.onChanged = () => this.board.refetch();
31
39
  }
32
40
  static { this.styles = [
33
41
  DocumentPageStyles,
@@ -198,6 +206,16 @@ let MyDashboardPage = class MyDashboardPage extends localize(i18next)(PageView)
198
206
  }
199
207
  `
200
208
  ]; }
209
+ get places() {
210
+ return (this.arranging.pending && this.arranged) || this.board.data?.myDashboard || [];
211
+ }
212
+ get loaded() {
213
+ return !!this.board.answeredAt;
214
+ }
215
+ get error() {
216
+ const error = this.board.error;
217
+ return error ? (error.message ?? String(error)) : undefined;
218
+ }
201
219
  get context() {
202
220
  return {
203
221
  title: t('ai-dashboard.title'),
@@ -222,23 +240,6 @@ let MyDashboardPage = class MyDashboardPage extends localize(i18next)(PageView)
222
240
  if (changes.has('editing'))
223
241
  this.updateContext();
224
242
  }
225
- /* Not awaited: the shell sets the tab's title only after this returns. */
226
- async pageUpdated(changes) {
227
- if (this.active && changes.active)
228
- this.load();
229
- }
230
- async load() {
231
- try {
232
- this.places = await cardApi.myDashboard();
233
- this.error = undefined;
234
- }
235
- catch (error) {
236
- this.error = error?.message ?? String(error);
237
- }
238
- finally {
239
- this.loaded = true;
240
- }
241
- }
242
243
  render() {
243
244
  return html `<div class="page">
244
245
  ${this.error
@@ -300,16 +301,10 @@ let MyDashboardPage = class MyDashboardPage extends localize(i18next)(PageView)
300
301
  placeOf(card) {
301
302
  return this.places.find(one => one.card.id === card.id);
302
303
  }
304
+ /* The board shows the move at once; a failed one goes back to the board read. */
303
305
  async arrange(next) {
304
- const before = this.places;
305
- this.places = next;
306
- try {
307
- await cardApi.arrange(next.map(({ id, order, width, height }) => ({ id, order, width, height })));
308
- }
309
- catch (error) {
310
- this.places = before;
311
- notify({ level: 'error', message: error?.message ?? String(error) });
312
- }
306
+ this.arranged = next;
307
+ await this.arranging.run({ places: next.map(({ id, order, width, height }) => ({ id, order, width, height })) });
313
308
  }
314
309
  async onCardAction(event) {
315
310
  const { action, card } = event.detail;
@@ -331,9 +326,9 @@ let MyDashboardPage = class MyDashboardPage extends localize(i18next)(PageView)
331
326
  case 'unplace':
332
327
  if (!place)
333
328
  return;
334
- await cardApi.unplace(place.id);
335
- notify({ level: 'info', message: t('ai-dashboard.text.unplaced', { name: card.name }) });
336
- return this.load();
329
+ if (await this.unplacing.run({ id: place.id }))
330
+ notify({ level: 'info', message: t('ai-dashboard.text.unplaced', { name: card.name }) });
331
+ return;
337
332
  case 'left':
338
333
  case 'right':
339
334
  return place && this.arrange(movedPlaces(this.places, place.id, action === 'left' ? -1 : 1));
@@ -354,22 +349,14 @@ let MyDashboardPage = class MyDashboardPage extends localize(i18next)(PageView)
354
349
  }
355
350
  }
356
351
  };
357
- __decorate([
358
- state(),
359
- __metadata("design:type", Array)
360
- ], MyDashboardPage.prototype, "places", void 0);
361
352
  __decorate([
362
353
  state(),
363
354
  __metadata("design:type", Object)
364
- ], MyDashboardPage.prototype, "loaded", void 0);
365
- __decorate([
366
- state(),
367
- __metadata("design:type", String)
368
- ], MyDashboardPage.prototype, "error", void 0);
355
+ ], MyDashboardPage.prototype, "editing", void 0);
369
356
  __decorate([
370
357
  state(),
371
- __metadata("design:type", Object)
372
- ], MyDashboardPage.prototype, "editing", void 0);
358
+ __metadata("design:type", Array)
359
+ ], MyDashboardPage.prototype, "arranged", void 0);
373
360
  MyDashboardPage = __decorate([
374
361
  customElement('my-dashboard-page')
375
362
  ], MyDashboardPage);
@@ -1 +1 @@
1
- {"version":3,"file":"my-dashboard-page.js","sourceRoot":"","sources":["../../client/pages/my-dashboard-page.ts"],"names":[],"mappings":"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","sourcesContent":["/*\n * 나의 대시보드 - the cards a person placed, drawn from the data as them (ADR-0160 decision 8).\n *\n * Cards are made in the AI conversation beside the page (its card tool is in front here) and saved by pressing the\n * card there; the library holds one's own cards and those shared with one. The page asks no model: each card asks\n * the server to run its definition, each on its own, so a slow card waits in its place.\n */\nimport '@material/web/icon/icon.js'\nimport '../components/dashboard-card.js'\nimport '../components/card-library.js'\n\nimport { css, html, nothing } from 'lit'\nimport { customElement, state } from 'lit/decorators.js'\n\nimport { i18next, localize } from '@operato/i18n'\nimport { notify, openPopup } from '@operato/layout'\nimport { PageView } from '@operato/shell'\nimport { DocumentPageStyles, ScrollbarStyles } from '@operato/styles'\nimport { askAssistant } from '@things-factory/ai-assistant/dist-client/index.js'\n\nimport { cardApi, DASHBOARD_CHANGED, dashboardChanged, type CardItem, type PlaceItem } from '../utils/card-api.js'\nimport { movedPlaces } from '../utils/card-words.js'\nimport { dashboardExamples } from '../utils/examples.js'\nimport { openCardAiPrompt, openCardRename, openCardShare, openCardVersions } from '../components/card-dialogs.js'\nimport type { CardAction } from '../components/dashboard-card.js'\n\nconst t = (key: string, options: Record<string, unknown> = {}) => String(i18next.t(key, options))\n\n\n@customElement('my-dashboard-page')\nexport class MyDashboardPage extends localize(i18next)(PageView) {\n static styles = [\n DocumentPageStyles,\n ScrollbarStyles,\n css`\n .page {\n gap: var(--spacing-large, 16px);\n }\n\n .lead {\n display: flex;\n flex-wrap: wrap;\n align-items: center;\n gap: 8px 16px;\n }\n\n .lead p {\n flex: 1;\n min-width: 240px;\n margin: 0;\n color: var(--ui-muted, var(--md-sys-color-on-surface-variant));\n }\n\n .chip {\n display: inline-flex;\n align-items: center;\n gap: 6px;\n padding: 4px 10px;\n border-radius: 999px;\n background: var(--ui-accent-wash, color-mix(in srgb, var(--md-sys-color-primary) 12%, transparent));\n color: var(--ui-accent, var(--md-sys-color-primary));\n font-size: var(--ui-t-small, 12px);\n font-weight: 600;\n --md-icon-size: 16px;\n }\n\n .board {\n container-type: inline-size;\n }\n\n .grid {\n display: grid;\n grid-template-columns: repeat(4, minmax(0, 1fr));\n grid-auto-rows: minmax(250px, auto);\n grid-auto-flow: dense;\n gap: 16px;\n }\n\n .grid > * {\n grid-column: span var(--w, 2);\n grid-row: span var(--h, 1);\n }\n\n @container (max-width: 1100px) {\n .grid {\n grid-template-columns: repeat(2, minmax(0, 1fr));\n }\n\n .grid > .w3,\n .grid > .w4 {\n --w: 2;\n }\n }\n\n @container (max-width: 640px) {\n .grid {\n grid-template-columns: minmax(0, 1fr);\n }\n\n .grid > * {\n --w: 1 !important;\n }\n }\n\n .empty {\n display: flex;\n flex-direction: column;\n align-items: center;\n gap: 14px;\n max-width: 640px;\n margin: 6vh auto 0;\n padding: 36px 28px;\n border: 1px dashed var(--ui-line, var(--md-sys-color-outline-variant));\n border-radius: 16px;\n background: radial-gradient(120% 100% at 50% 0%, var(--ui-accent-wash, color-mix(in srgb, var(--md-sys-color-primary) 10%, transparent)) 0%, transparent 70%);\n text-align: center;\n }\n\n .empty .mark {\n display: grid;\n place-items: center;\n width: 56px;\n height: 56px;\n border-radius: 16px;\n background: var(--ui-accent, var(--md-sys-color-primary));\n color: var(--ui-on-accent, var(--md-sys-color-on-primary));\n --md-icon-size: 30px;\n box-shadow: 0 10px 24px -12px var(--ui-accent, var(--md-sys-color-primary));\n }\n\n .empty h2 {\n margin: 4px 0 0;\n font-size: var(--ui-t-page, 18px);\n font-weight: 650;\n }\n\n .empty p {\n margin: 0;\n color: var(--ui-muted, var(--md-sys-color-on-surface-variant));\n }\n\n .examples {\n display: flex;\n flex-direction: column;\n gap: 8px;\n width: 100%;\n margin-top: 6px;\n }\n\n .examples button,\n .empty .library {\n display: flex;\n align-items: center;\n gap: 10px;\n padding: 10px 14px;\n border: 1px solid var(--ui-line, var(--md-sys-color-outline-variant));\n border-radius: 10px;\n background: var(--ui-panel, var(--md-sys-color-surface-container-lowest));\n color: var(--ui-ink, var(--md-sys-color-on-surface));\n font: inherit;\n text-align: start;\n cursor: pointer;\n transition:\n border-color 0.15s ease,\n transform 0.15s ease;\n --md-icon-size: 18px;\n }\n\n .examples button md-icon {\n color: var(--ui-accent, var(--md-sys-color-primary));\n }\n\n .examples button:hover,\n .examples button:focus-visible,\n .empty .library:hover {\n border-color: var(--ui-accent, var(--md-sys-color-primary));\n transform: translateY(-1px);\n outline: none;\n }\n\n .empty .library {\n justify-content: center;\n border-style: dashed;\n background: transparent;\n }\n\n .notice {\n margin: 0;\n padding: 12px 14px;\n border-radius: 10px;\n background: color-mix(in srgb, var(--ui-crit, #c62828) 8%, transparent);\n }\n\n .note {\n margin: 0;\n font-size: var(--ui-t-small, 12px);\n color: var(--ui-faint, var(--md-sys-color-on-surface-variant));\n }\n `\n ]\n\n @state() private places: PlaceItem[] = []\n @state() private loaded = false\n @state() private error?: string\n @state() private editing = false\n\n private onChanged = () => this.load()\n\n get context() {\n return {\n title: t('ai-dashboard.title'),\n frame: 'document',\n actions: [\n { title: t(this.editing ? 'ai-dashboard.button.done' : 'ai-dashboard.button.arrange'), action: () => (this.editing = !this.editing), icon: this.editing ? 'check' : 'dashboard_customize' },\n { title: t('ai-dashboard.button.library'), action: () => this.openLibrary(), icon: 'collections_bookmark' },\n { title: t('ai-dashboard.button.make'), action: () => this.make(), icon: 'auto_awesome', emphasis: { raised: true } }\n ]\n }\n }\n\n connectedCallback() {\n super.connectedCallback()\n window.addEventListener(DASHBOARD_CHANGED, this.onChanged)\n }\n\n disconnectedCallback() {\n window.removeEventListener(DASHBOARD_CHANGED, this.onChanged)\n super.disconnectedCallback()\n }\n\n updated(changes: Map<string, unknown>) {\n /* The action bar follows the mode - its words say what pressing it does now. */\n if (changes.has('editing')) this.updateContext()\n }\n\n /* Not awaited: the shell sets the tab's title only after this returns. */\n async pageUpdated(changes: any) {\n if ((this as any).active && changes.active) this.load()\n }\n\n private async load() {\n try {\n this.places = await cardApi.myDashboard()\n this.error = undefined\n } catch (error: any) {\n this.error = error?.message ?? String(error)\n } finally {\n this.loaded = true\n }\n }\n\n render() {\n return html`<div class=\"page\">\n ${this.error\n ? html`<p class=\"notice\">${this.error}</p>`\n : this.loaded && !this.places.length\n ? this.renderEmpty()\n : this.places.length\n ? this.renderBoard()\n : nothing}\n </div>`\n }\n\n private renderBoard() {\n const sorted = [...this.places].sort((a, b) => a.order - b.order)\n return html`<div class=\"lead\">\n <p>${t('ai-dashboard.page.lead')}</p>\n ${this.editing ? html`<span class=\"chip\"><md-icon>dashboard_customize</md-icon>${t('ai-dashboard.page.arranging')}</span>` : nothing}\n </div>\n <div class=\"board\">\n <div class=\"grid\" @card-action=${(event: CustomEvent) => this.onCardAction(event)}>\n ${sorted.map(\n (place, i) => html`<ai-dashboard-card\n class=\"w${place.width} h${place.height}\"\n style=\"--w: ${place.width}; --h: ${place.height}\"\n data-place=${place.id}\n .card=${place.card}\n .width=${place.width}\n .height=${place.height}\n ?editing=${this.editing}\n ?first=${i === 0}\n ?last=${i === sorted.length - 1}\n ></ai-dashboard-card>`\n )}\n </div>\n </div>\n <p class=\"note\">${t('ai-dashboard.page.no-tokens')}</p>`\n }\n\n private renderEmpty() {\n return html`<div class=\"empty\">\n <span class=\"mark\"><md-icon>auto_awesome</md-icon></span>\n <h2>${t('ai-dashboard.page.empty-title')}</h2>\n <p>${t('ai-dashboard.page.empty-text')}</p>\n ${dashboardExamples().length\n ? html`<div class=\"examples\">\n ${dashboardExamples().map(key => html`<button @click=${() => this.askFor(t(key))}><md-icon>chat_bubble</md-icon><span>${t(key)}</span></button>`)}\n </div>`\n : nothing}\n <button class=\"library\" @click=${() => this.openLibrary()}><md-icon>collections_bookmark</md-icon>${t('ai-dashboard.page.from-library')}</button>\n <p class=\"note\">${t('ai-dashboard.page.no-tokens')}</p>\n </div>`\n }\n\n /** Sends a request to the conversation beside the page - this screen's, where the card tool is in front. */\n private async askFor(ask: string) {\n await askAssistant({ ask, continueCurrent: true })\n }\n\n private make() {\n askAssistant({ draft: t('ai-dashboard.page.make-draft'), continueCurrent: true })\n }\n\n private openLibrary() {\n openPopup(html`<ai-dashboard-card-library></ai-dashboard-card-library>`, { backdrop: true, size: 'large', title: t('ai-dashboard.library.title') })\n }\n\n private placeOf(card: CardItem) {\n return this.places.find(one => one.card.id === card.id)\n }\n\n private async arrange(next: PlaceItem[]) {\n const before = this.places\n this.places = next\n try {\n await cardApi.arrange(next.map(({ id, order, width, height }) => ({ id, order, width, height })))\n } catch (error: any) {\n this.places = before\n notify({ level: 'error', message: error?.message ?? String(error) })\n }\n }\n\n private async onCardAction(event: CustomEvent) {\n const { action, card } = event.detail as { action: CardAction; card: CardItem }\n const place = this.placeOf(card)\n try {\n switch (action) {\n case 'ai':\n return openCardAiPrompt(card)\n case 'rename':\n return openCardRename(card)\n case 'share':\n return openCardShare(card)\n case 'versions':\n return openCardVersions(card)\n case 'copy':\n await cardApi.copy(card.id)\n notify({ level: 'info', message: t('ai-dashboard.text.copied', { name: card.name }) })\n return dashboardChanged()\n case 'unplace':\n if (!place) return\n await cardApi.unplace(place.id)\n notify({ level: 'info', message: t('ai-dashboard.text.unplaced', { name: card.name }) })\n return this.load()\n case 'left':\n case 'right':\n return place && this.arrange(movedPlaces(this.places, place.id, action === 'left' ? -1 : 1))\n case 'wider':\n case 'narrower':\n case 'taller':\n case 'shorter': {\n if (!place) return\n const width = Math.min(4, Math.max(1, place.width + (action === 'wider' ? 1 : action === 'narrower' ? -1 : 0)))\n const height = Math.min(2, Math.max(1, place.height + (action === 'taller' ? 1 : action === 'shorter' ? -1 : 0)))\n return this.arrange(this.places.map(one => (one.id === place.id ? { ...one, width, height } : one)))\n }\n }\n } catch (error: any) {\n notify({ level: 'error', message: error?.message ?? String(error) })\n }\n }\n}\n"]}
1
+ {"version":3,"file":"my-dashboard-page.js","sourceRoot":"","sources":["../../client/pages/my-dashboard-page.ts"],"names":[],"mappings":"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","sourcesContent":["/*\n * 나의 대시보드 - the cards a person placed, drawn from the data as them (ADR-0160 decision 8).\n *\n * Cards are made in the AI conversation beside the page (its card tool is in front here) and saved by pressing the\n * card there; the library holds one's own cards and those shared with one. The page asks no model: each card asks\n * the server to run its definition, each on its own, so a slow card waits in its place.\n */\nimport '@material/web/icon/icon.js'\nimport '../components/dashboard-card.js'\nimport '../components/card-library.js'\n\nimport gql from 'graphql-tag'\nimport { css, html, nothing } from 'lit'\nimport { customElement, state } from 'lit/decorators.js'\n\nimport { MutationController, QueryController } from '@operato/graphql'\nimport { i18next, localize } from '@operato/i18n'\nimport { notify, openPopup } from '@operato/layout'\nimport { PageView } from '@operato/shell'\nimport { DocumentPageStyles, ScrollbarStyles } from '@operato/styles'\nimport { askAssistant } from '@things-factory/ai-assistant/dist-client/index.js'\n\nimport { cardApi, CARD_FIELDS, DASHBOARD_CHANGED, dashboardChanged, type CardItem, type PlaceItem } from '../utils/card-api.js'\nimport { movedPlaces } from '../utils/card-words.js'\nimport { dashboardExamples } from '../utils/examples.js'\nimport { openCardAiPrompt, openCardRename, openCardShare, openCardVersions } from '../components/card-dialogs.js'\nimport type { CardAction } from '../components/dashboard-card.js'\n\nconst t = (key: string, options: Record<string, unknown> = {}) => String(i18next.t(key, options))\n\n\n@customElement('my-dashboard-page')\nexport class MyDashboardPage extends localize(i18next)(PageView) {\n static styles = [\n DocumentPageStyles,\n ScrollbarStyles,\n css`\n .page {\n gap: var(--spacing-large, 16px);\n }\n\n .lead {\n display: flex;\n flex-wrap: wrap;\n align-items: center;\n gap: 8px 16px;\n }\n\n .lead p {\n flex: 1;\n min-width: 240px;\n margin: 0;\n color: var(--ui-muted, var(--md-sys-color-on-surface-variant));\n }\n\n .chip {\n display: inline-flex;\n align-items: center;\n gap: 6px;\n padding: 4px 10px;\n border-radius: 999px;\n background: var(--ui-accent-wash, color-mix(in srgb, var(--md-sys-color-primary) 12%, transparent));\n color: var(--ui-accent, var(--md-sys-color-primary));\n font-size: var(--ui-t-small, 12px);\n font-weight: 600;\n --md-icon-size: 16px;\n }\n\n .board {\n container-type: inline-size;\n }\n\n .grid {\n display: grid;\n grid-template-columns: repeat(4, minmax(0, 1fr));\n grid-auto-rows: minmax(250px, auto);\n grid-auto-flow: dense;\n gap: 16px;\n }\n\n .grid > * {\n grid-column: span var(--w, 2);\n grid-row: span var(--h, 1);\n }\n\n @container (max-width: 1100px) {\n .grid {\n grid-template-columns: repeat(2, minmax(0, 1fr));\n }\n\n .grid > .w3,\n .grid > .w4 {\n --w: 2;\n }\n }\n\n @container (max-width: 640px) {\n .grid {\n grid-template-columns: minmax(0, 1fr);\n }\n\n .grid > * {\n --w: 1 !important;\n }\n }\n\n .empty {\n display: flex;\n flex-direction: column;\n align-items: center;\n gap: 14px;\n max-width: 640px;\n margin: 6vh auto 0;\n padding: 36px 28px;\n border: 1px dashed var(--ui-line, var(--md-sys-color-outline-variant));\n border-radius: 16px;\n background: radial-gradient(120% 100% at 50% 0%, var(--ui-accent-wash, color-mix(in srgb, var(--md-sys-color-primary) 10%, transparent)) 0%, transparent 70%);\n text-align: center;\n }\n\n .empty .mark {\n display: grid;\n place-items: center;\n width: 56px;\n height: 56px;\n border-radius: 16px;\n background: var(--ui-accent, var(--md-sys-color-primary));\n color: var(--ui-on-accent, var(--md-sys-color-on-primary));\n --md-icon-size: 30px;\n box-shadow: 0 10px 24px -12px var(--ui-accent, var(--md-sys-color-primary));\n }\n\n .empty h2 {\n margin: 4px 0 0;\n font-size: var(--ui-t-page, 18px);\n font-weight: 650;\n }\n\n .empty p {\n margin: 0;\n color: var(--ui-muted, var(--md-sys-color-on-surface-variant));\n }\n\n .examples {\n display: flex;\n flex-direction: column;\n gap: 8px;\n width: 100%;\n margin-top: 6px;\n }\n\n .examples button,\n .empty .library {\n display: flex;\n align-items: center;\n gap: 10px;\n padding: 10px 14px;\n border: 1px solid var(--ui-line, var(--md-sys-color-outline-variant));\n border-radius: 10px;\n background: var(--ui-panel, var(--md-sys-color-surface-container-lowest));\n color: var(--ui-ink, var(--md-sys-color-on-surface));\n font: inherit;\n text-align: start;\n cursor: pointer;\n transition:\n border-color 0.15s ease,\n transform 0.15s ease;\n --md-icon-size: 18px;\n }\n\n .examples button md-icon {\n color: var(--ui-accent, var(--md-sys-color-primary));\n }\n\n .examples button:hover,\n .examples button:focus-visible,\n .empty .library:hover {\n border-color: var(--ui-accent, var(--md-sys-color-primary));\n transform: translateY(-1px);\n outline: none;\n }\n\n .empty .library {\n justify-content: center;\n border-style: dashed;\n background: transparent;\n }\n\n .notice {\n margin: 0;\n padding: 12px 14px;\n border-radius: 10px;\n background: color-mix(in srgb, var(--ui-crit, #c62828) 8%, transparent);\n }\n\n .note {\n margin: 0;\n font-size: var(--ui-t-small, 12px);\n color: var(--ui-faint, var(--md-sys-color-on-surface-variant));\n }\n `\n ]\n\n @state() private editing = false\n /** The places as moved here, shown while the move is being saved. */\n @state() private arranged?: PlaceItem[]\n\n /* A page refresh, or a change told from elsewhere, reads the board again. */\n private board = new QueryController(this, gql`query { myDashboard { id order width height card { ${CARD_FIELDS} } } }`)\n private arranging = new MutationController(this, gql`mutation ($places: [DashboardPlaceInput!]!) { arrangeDashboard(places: $places) }`, {\n refetch: () => [this.board]\n })\n private unplacing = new MutationController(this, gql`mutation ($id: String!) { removeDashboardPlace(id: $id) }`, {\n refetch: () => [this.board]\n })\n\n private get places(): PlaceItem[] {\n return (this.arranging.pending && this.arranged) || this.board.data?.myDashboard || []\n }\n\n private get loaded() {\n return !!this.board.answeredAt\n }\n\n private get error(): string | undefined {\n const error = this.board.error as any\n return error ? (error.message ?? String(error)) : undefined\n }\n\n private onChanged = () => this.board.refetch()\n\n get context() {\n return {\n title: t('ai-dashboard.title'),\n frame: 'document',\n actions: [\n { title: t(this.editing ? 'ai-dashboard.button.done' : 'ai-dashboard.button.arrange'), action: () => (this.editing = !this.editing), icon: this.editing ? 'check' : 'dashboard_customize' },\n { title: t('ai-dashboard.button.library'), action: () => this.openLibrary(), icon: 'collections_bookmark' },\n { title: t('ai-dashboard.button.make'), action: () => this.make(), icon: 'auto_awesome', emphasis: { raised: true } }\n ]\n }\n }\n\n connectedCallback() {\n super.connectedCallback()\n window.addEventListener(DASHBOARD_CHANGED, this.onChanged)\n }\n\n disconnectedCallback() {\n window.removeEventListener(DASHBOARD_CHANGED, this.onChanged)\n super.disconnectedCallback()\n }\n\n updated(changes: Map<string, unknown>) {\n /* The action bar follows the mode - its words say what pressing it does now. */\n if (changes.has('editing')) this.updateContext()\n }\n\n render() {\n return html`<div class=\"page\">\n ${this.error\n ? html`<p class=\"notice\">${this.error}</p>`\n : this.loaded && !this.places.length\n ? this.renderEmpty()\n : this.places.length\n ? this.renderBoard()\n : nothing}\n </div>`\n }\n\n private renderBoard() {\n const sorted = [...this.places].sort((a, b) => a.order - b.order)\n return html`<div class=\"lead\">\n <p>${t('ai-dashboard.page.lead')}</p>\n ${this.editing ? html`<span class=\"chip\"><md-icon>dashboard_customize</md-icon>${t('ai-dashboard.page.arranging')}</span>` : nothing}\n </div>\n <div class=\"board\">\n <div class=\"grid\" @card-action=${(event: CustomEvent) => this.onCardAction(event)}>\n ${sorted.map(\n (place, i) => html`<ai-dashboard-card\n class=\"w${place.width} h${place.height}\"\n style=\"--w: ${place.width}; --h: ${place.height}\"\n data-place=${place.id}\n .card=${place.card}\n .width=${place.width}\n .height=${place.height}\n ?editing=${this.editing}\n ?first=${i === 0}\n ?last=${i === sorted.length - 1}\n ></ai-dashboard-card>`\n )}\n </div>\n </div>\n <p class=\"note\">${t('ai-dashboard.page.no-tokens')}</p>`\n }\n\n private renderEmpty() {\n return html`<div class=\"empty\">\n <span class=\"mark\"><md-icon>auto_awesome</md-icon></span>\n <h2>${t('ai-dashboard.page.empty-title')}</h2>\n <p>${t('ai-dashboard.page.empty-text')}</p>\n ${dashboardExamples().length\n ? html`<div class=\"examples\">\n ${dashboardExamples().map(key => html`<button @click=${() => this.askFor(t(key))}><md-icon>chat_bubble</md-icon><span>${t(key)}</span></button>`)}\n </div>`\n : nothing}\n <button class=\"library\" @click=${() => this.openLibrary()}><md-icon>collections_bookmark</md-icon>${t('ai-dashboard.page.from-library')}</button>\n <p class=\"note\">${t('ai-dashboard.page.no-tokens')}</p>\n </div>`\n }\n\n /** Sends a request to the conversation beside the page - this screen's, where the card tool is in front. */\n private async askFor(ask: string) {\n await askAssistant({ ask, continueCurrent: true })\n }\n\n private make() {\n askAssistant({ draft: t('ai-dashboard.page.make-draft'), continueCurrent: true })\n }\n\n private openLibrary() {\n openPopup(html`<ai-dashboard-card-library></ai-dashboard-card-library>`, { backdrop: true, size: 'large', title: t('ai-dashboard.library.title') })\n }\n\n private placeOf(card: CardItem) {\n return this.places.find(one => one.card.id === card.id)\n }\n\n /* The board shows the move at once; a failed one goes back to the board read. */\n private async arrange(next: PlaceItem[]) {\n this.arranged = next\n await this.arranging.run({ places: next.map(({ id, order, width, height }) => ({ id, order, width, height })) })\n }\n\n private async onCardAction(event: CustomEvent) {\n const { action, card } = event.detail as { action: CardAction; card: CardItem }\n const place = this.placeOf(card)\n try {\n switch (action) {\n case 'ai':\n return openCardAiPrompt(card)\n case 'rename':\n return openCardRename(card)\n case 'share':\n return openCardShare(card)\n case 'versions':\n return openCardVersions(card)\n case 'copy':\n await cardApi.copy(card.id)\n notify({ level: 'info', message: t('ai-dashboard.text.copied', { name: card.name }) })\n return dashboardChanged()\n case 'unplace':\n if (!place) return\n if (await this.unplacing.run({ id: place.id })) notify({ level: 'info', message: t('ai-dashboard.text.unplaced', { name: card.name }) })\n return\n case 'left':\n case 'right':\n return place && this.arrange(movedPlaces(this.places, place.id, action === 'left' ? -1 : 1))\n case 'wider':\n case 'narrower':\n case 'taller':\n case 'shorter': {\n if (!place) return\n const width = Math.min(4, Math.max(1, place.width + (action === 'wider' ? 1 : action === 'narrower' ? -1 : 0)))\n const height = Math.min(2, Math.max(1, place.height + (action === 'taller' ? 1 : action === 'shorter' ? -1 : 0)))\n return this.arrange(this.places.map(one => (one.id === place.id ? { ...one, width, height } : one)))\n }\n }\n } catch (error: any) {\n notify({ level: 'error', message: error?.message ?? String(error) })\n }\n }\n}\n"]}