@things-factory/integration-ui 10.0.0-zeta.8 → 10.0.1

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.
@@ -5,6 +5,7 @@ import gql from 'graphql-tag';
5
5
  import { css, html, LitElement, nothing } from 'lit';
6
6
  import { customElement, property } from 'lit/decorators.js';
7
7
  import { subscribe } from '@operato/graphql';
8
+ import { i18next } from '@operato/i18n';
8
9
  import { ScrollbarStyles } from '@operato/styles';
9
10
  let ScenarioInstanceLogView = class ScenarioInstanceLogView extends LitElement {
10
11
  constructor() {
@@ -52,6 +53,14 @@ let ScenarioInstanceLogView = class ScenarioInstanceLogView extends LitElement {
52
53
  bottom: 15px;
53
54
  right: 16px;
54
55
  text-decoration: auto;
56
+ display: flex;
57
+ flex-direction: column-reverse;
58
+ gap: 10px;
59
+ align-items: center;
60
+ }
61
+ #start [draft] {
62
+ --md-fab-container-color: var(--md-sys-color-secondary-container);
63
+ --md-fab-icon-color: var(--md-sys-color-on-secondary-container);
55
64
  }
56
65
  `
57
66
  ]; }
@@ -75,9 +84,23 @@ let ScenarioInstanceLogView = class ScenarioInstanceLogView extends LitElement {
75
84
  `)}
76
85
  </div>
77
86
  ${this.startable
78
- ? html `<md-fab id="start" title="start" @click=${() => this.dispatchEvent(new CustomEvent('start'))}>
79
- <md-icon slot="icon">play_arrow</md-icon>
80
- </md-fab>`
87
+ ? html `
88
+ <div id="start">
89
+ <md-fab
90
+ title=${i18next.t('button.run released version')}
91
+ @click=${() => this.dispatchEvent(new CustomEvent('start', { detail: { mode: 'released' } }))}
92
+ >
93
+ <md-icon slot="icon">play_arrow</md-icon>
94
+ </md-fab>
95
+ <md-fab
96
+ draft
97
+ title=${i18next.t('button.run draft for debugging')}
98
+ @click=${() => this.dispatchEvent(new CustomEvent('start', { detail: { mode: 'draft' } }))}
99
+ >
100
+ <md-icon slot="icon">bug_report</md-icon>
101
+ </md-fab>
102
+ </div>
103
+ `
81
104
  : nothing}
82
105
  `;
83
106
  }
@@ -1 +1 @@
1
- {"version":3,"file":"scenario-instance-log-view.js","sourceRoot":"","sources":["../../client/viewparts/scenario-instance-log-view.ts"],"names":[],"mappings":";AAAA,OAAO,4BAA4B,CAAA;AACnC,OAAO,0BAA0B,CAAA;AAEjC,OAAO,GAAG,MAAM,aAAa,CAAA;AAE7B,OAAO,EAAE,GAAG,EAAE,IAAI,EAAE,UAAU,EAAE,OAAO,EAAE,MAAM,KAAK,CAAA;AACpD,OAAO,EAAE,aAAa,EAAE,QAAQ,EAAS,MAAM,mBAAmB,CAAA;AAClE,OAAO,EAAE,SAAS,EAAE,MAAM,kBAAkB,CAAA;AAC5C,OAAO,EAAE,eAAe,EAAE,MAAM,iBAAiB,CAAA;AAG1C,IAAM,uBAAuB,GAA7B,MAAM,uBAAwB,SAAQ,UAAU;IAAhD;;QAiDwB,cAAS,GAAY,KAAK,CAAA;IA2EzD,CAAC;aA3HQ,WAAM,GAAG;QACd,eAAe;QACf,GAAG,CAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;KAwCF;KACF,AA3CY,CA2CZ;IASD,YAAY;QACV,IAAI,CAAC,IAAI,GAAG,EAAE,CAAA;QACd,IAAI,CAAC,cAAc,EAAE,CAAA;IACvB,CAAC;IAED,oBAAoB;QAClB,KAAK,CAAC,oBAAoB,EAAE,CAAA;QAC5B,IAAI,CAAC,aAAa,EAAE,CAAA;IACtB,CAAC;IAED,MAAM;QACJ,MAAM,IAAI,GAAG,IAAI,CAAC,IAAI,IAAI,EAAE,CAAA;QAE5B,OAAO,IAAI,CAAA;;;UAGL,IAAI,CAAC,GAAG,CACR,CAAC,EAAE,SAAS,EAAE,OAAO,EAAE,KAAK,EAAE,EAAE,EAAE,CAAC,IAAI,CAAA;0BACvB,KAAK;sBACT,IAAI,IAAI,CAAC,SAAS,CAAC,CAAC,cAAc,EAAE,mBAAmB,KAAK,aAAa,OAAO;;WAE3F,CACF;;QAED,IAAI,CAAC,SAAS;YACd,CAAC,CAAC,IAAI,CAAA,2CAA2C,GAAG,EAAE,CAAC,IAAI,CAAC,aAAa,CAAC,IAAI,WAAW,CAAC,OAAO,CAAC,CAAC;;oBAEvF;YACZ,CAAC,CAAC,OAAO;KACZ,CAAA;IACH,CAAC;IAED,KAAK,CAAC,cAAc;QAClB,IAAI,CAAC,YAAY,GAAG,MAAM,SAAS,CACjC;YACE,KAAK,EAAE,GAAG,CAAA;;;;;;;;SAQT;YACD,SAAS,EAAE;gBACT,YAAY,EAAE,IAAI,CAAC,YAAY;gBAC/B,YAAY,EAAE,IAAI,CAAC,YAAY;aAChC;SACF,EACD;YACE,IAAI,EAAE,KAAK,EAAE,EAAE,IAAI,EAAE,EAAE,EAAE;gBACvB,IAAI,SAAS,GAAG,IAAI,CAAC,YAAY,GAAG,IAAI,CAAC,SAAS,KAAK,IAAI,CAAC,YAAY,CAAA;gBAExE,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,CAAA;gBACxB,IAAI,CAAC,IAAI,CAAC,MAAM,GAAG,GAAG,IAAI,IAAI,CAAC,IAAI,CAAC,KAAK,EAAE,CAAA;gBAC3C,IAAI,CAAC,aAAa,EAAE,CAAA;gBAEpB,IAAI,SAAS,EAAE,CAAC;oBACd,6DAA6D;oBAC7D,MAAM,IAAI,CAAC,cAAc,CAAA;oBACzB,IAAI,CAAC,SAAS,GAAG,IAAI,CAAC,YAAY,GAAG,IAAI,CAAC,YAAY,CAAA;gBACxD,CAAC;YACH,CAAC;SACF,CACF,CAAA;IACH,CAAC;IAED,KAAK,CAAC,aAAa;QACjB,MAAM,IAAI,CAAC,YAAY,EAAE,WAAW,EAAE,CAAA;QACtC,OAAO,IAAI,CAAC,YAAY,CAAA;IAC1B,CAAC;;AA7E2B;IAA3B,QAAQ,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,CAAC;;6DAAsB;AACrB;IAA3B,QAAQ,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,CAAC;;6DAAsB;AACtB;IAA1B,QAAQ,CAAC,EAAE,IAAI,EAAE,KAAK,EAAE,CAAC;;qDAAU;AACP;IAA5B,QAAQ,CAAC,EAAE,IAAI,EAAE,OAAO,EAAE,CAAC;;0DAA2B;AAjD5C,uBAAuB;IADnC,aAAa,CAAC,4BAA4B,CAAC;GAC/B,uBAAuB,CA4HnC","sourcesContent":["import '@material/web/icon/icon.js'\nimport '@material/web/fab/fab.js'\n\nimport gql from 'graphql-tag'\n\nimport { css, html, LitElement, nothing } from 'lit'\nimport { customElement, property, query } from 'lit/decorators.js'\nimport { subscribe } from '@operato/graphql'\nimport { ScrollbarStyles } from '@operato/styles'\n\n@customElement('scenario-instance-log-view')\nexport class ScenarioInstanceLogView extends LitElement {\n static styles = [\n ScrollbarStyles,\n css`\n :host {\n display: flex;\n flex-direction: column;\n background-color: var(--md-sys-color-surface);\n padding: var(--spacing-large);\n }\n\n :host([active]) {\n padding: 0;\n }\n\n [content] {\n flex: 1;\n\n display: flex;\n flex-direction: column;\n overflow: auto;\n\n font-size: var(--fontsize-small);\n }\n\n div.error {\n color: #8b0000;\n }\n\n div.warn {\n color: #ff6b6b;\n }\n\n span {\n color: var(--md-sys-color-primary);\n }\n\n #start {\n position: absolute;\n bottom: 15px;\n right: 16px;\n text-decoration: auto;\n }\n `\n ]\n\n @property({ type: String }) scenarioName?: string\n @property({ type: String }) instanceName?: string\n @property({ type: Array }) logs: any\n @property({ type: Boolean }) startable: boolean = false\n\n subscription: any\n\n firstUpdated() {\n this.logs = []\n this.startSubscribe()\n }\n\n disconnectedCallback() {\n super.disconnectedCallback()\n this.stopSubscribe()\n }\n\n render() {\n const logs = this.logs || []\n\n return html`\n <div options></div>\n <div content>\n ${logs.map(\n ({ timestamp, message, level }) => html`\n <div class=\"${level}\">\n <span>${new Date(timestamp).toLocaleString()}</span> <strong>${level}</strong> ${message}\n </div>\n `\n )}\n </div>\n ${this.startable\n ? html`<md-fab id=\"start\" title=\"start\" @click=${() => this.dispatchEvent(new CustomEvent('start'))}>\n <md-icon slot=\"icon\">play_arrow</md-icon>\n </md-fab>`\n : nothing}\n `\n }\n\n async startSubscribe() {\n this.subscription = await subscribe(\n {\n query: gql`\n subscription ($instanceName: String, $scenarioName: String, $level: String) {\n log: scenarioInstanceLog(instanceName: $instanceName, scenarioName: $scenarioName, level: $level) {\n level\n message\n timestamp\n }\n }\n `,\n variables: {\n instanceName: this.instanceName,\n scenarioName: this.scenarioName\n }\n },\n {\n next: async ({ data }) => {\n var wasBottom = this.scrollHeight - this.scrollTop === this.clientHeight\n\n this.logs.push(data.log)\n this.logs.length > 100 && this.logs.shift()\n this.requestUpdate()\n\n if (wasBottom) {\n /* this is not proved yet - to keep bottom scroll position */\n await this.updateComplete\n this.scrollTop = this.scrollHeight - this.clientHeight\n }\n }\n }\n )\n }\n\n async stopSubscribe() {\n await this.subscription?.unsubscribe()\n delete this.subscription\n }\n}\n"]}
1
+ {"version":3,"file":"scenario-instance-log-view.js","sourceRoot":"","sources":["../../client/viewparts/scenario-instance-log-view.ts"],"names":[],"mappings":"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","sourcesContent":["import '@material/web/icon/icon.js'\nimport '@material/web/fab/fab.js'\n\nimport gql from 'graphql-tag'\n\nimport { css, html, LitElement, nothing } from 'lit'\nimport { customElement, property, query } from 'lit/decorators.js'\nimport { subscribe } from '@operato/graphql'\nimport { i18next } from '@operato/i18n'\nimport { ScrollbarStyles } from '@operato/styles'\n\n@customElement('scenario-instance-log-view')\nexport class ScenarioInstanceLogView extends LitElement {\n static styles = [\n ScrollbarStyles,\n css`\n :host {\n display: flex;\n flex-direction: column;\n background-color: var(--md-sys-color-surface);\n padding: var(--spacing-large);\n }\n\n :host([active]) {\n padding: 0;\n }\n\n [content] {\n flex: 1;\n\n display: flex;\n flex-direction: column;\n overflow: auto;\n\n font-size: var(--fontsize-small);\n }\n\n div.error {\n color: #8b0000;\n }\n\n div.warn {\n color: #ff6b6b;\n }\n\n span {\n color: var(--md-sys-color-primary);\n }\n\n #start {\n position: absolute;\n bottom: 15px;\n right: 16px;\n text-decoration: auto;\n display: flex;\n flex-direction: column-reverse;\n gap: 10px;\n align-items: center;\n }\n #start [draft] {\n --md-fab-container-color: var(--md-sys-color-secondary-container);\n --md-fab-icon-color: var(--md-sys-color-on-secondary-container);\n }\n `\n ]\n\n @property({ type: String }) scenarioName?: string\n @property({ type: String }) instanceName?: string\n @property({ type: Array }) logs: any\n @property({ type: Boolean }) startable: boolean = false\n\n subscription: any\n\n firstUpdated() {\n this.logs = []\n this.startSubscribe()\n }\n\n disconnectedCallback() {\n super.disconnectedCallback()\n this.stopSubscribe()\n }\n\n render() {\n const logs = this.logs || []\n\n return html`\n <div options></div>\n <div content>\n ${logs.map(\n ({ timestamp, message, level }) => html`\n <div class=\"${level}\">\n <span>${new Date(timestamp).toLocaleString()}</span> <strong>${level}</strong> ${message}\n </div>\n `\n )}\n </div>\n ${this.startable\n ? html`\n <div id=\"start\">\n <md-fab\n title=${i18next.t('button.run released version')}\n @click=${() => this.dispatchEvent(new CustomEvent('start', { detail: { mode: 'released' } }))}\n >\n <md-icon slot=\"icon\">play_arrow</md-icon>\n </md-fab>\n <md-fab\n draft\n title=${i18next.t('button.run draft for debugging')}\n @click=${() => this.dispatchEvent(new CustomEvent('start', { detail: { mode: 'draft' } }))}\n >\n <md-icon slot=\"icon\">bug_report</md-icon>\n </md-fab>\n </div>\n `\n : nothing}\n `\n }\n\n async startSubscribe() {\n this.subscription = await subscribe(\n {\n query: gql`\n subscription ($instanceName: String, $scenarioName: String, $level: String) {\n log: scenarioInstanceLog(instanceName: $instanceName, scenarioName: $scenarioName, level: $level) {\n level\n message\n timestamp\n }\n }\n `,\n variables: {\n instanceName: this.instanceName,\n scenarioName: this.scenarioName\n }\n },\n {\n next: async ({ data }) => {\n var wasBottom = this.scrollHeight - this.scrollTop === this.clientHeight\n\n this.logs.push(data.log)\n this.logs.length > 100 && this.logs.shift()\n this.requestUpdate()\n\n if (wasBottom) {\n /* this is not proved yet - to keep bottom scroll position */\n await this.updateComplete\n this.scrollTop = this.scrollHeight - this.clientHeight\n }\n }\n }\n )\n }\n\n async stopSubscribe() {\n await this.subscription?.unsubscribe()\n delete this.subscription\n }\n}\n"]}
@@ -11,7 +11,7 @@ export declare class ScenarioMonitor extends ScenarioMonitor_base {
11
11
  render(): import("lit-html").TemplateResult<1>;
12
12
  renderButtons(scenario: any): import("lit-html").TemplateResult<1>;
13
13
  popupLogView(scenario: any): Promise<void>;
14
- startScenario(scenario: any): Promise<void>;
14
+ startScenario(scenario: any, mode?: string): Promise<void>;
15
15
  stopScenario(scenario: any): Promise<void>;
16
16
  }
17
17
  export {};
@@ -227,7 +227,19 @@ let ScenarioMonitor = class ScenarioMonitor extends localize(i18next)(LitElement
227
227
  <div buttons ?detail=${this.mode == 'detail'}>
228
228
  <md-icon @click=${e => this.popupLogView(scenario)}>text_snippet</md-icon>
229
229
  ${!scenarioInstance
230
- ? html ` <md-icon @click=${e => this.startScenario(scenario)}>play_circle</md-icon>`
230
+ ? html `
231
+ <md-icon
232
+ title=${i18next.t('button.run released version')}
233
+ @click=${e => this.startScenario(scenario, 'released')}
234
+ >play_circle</md-icon
235
+ >
236
+ <md-icon
237
+ title=${i18next.t('button.run draft for debugging')}
238
+ @click=${e => this.startScenario(scenario, 'draft')}
239
+ debug
240
+ >bug_report</md-icon
241
+ >
242
+ `
231
243
  : html ` <md-icon @click=${e => this.stopScenario(scenario)} stop>pause_circle</md-icon> `}
232
244
  </div>
233
245
  `;
@@ -236,7 +248,7 @@ let ScenarioMonitor = class ScenarioMonitor extends localize(i18next)(LitElement
236
248
  const popup = openPopup(html `
237
249
  <scenario-instance-log-view
238
250
  .scenarioName=${scenario.name}
239
- @start=${() => this.startScenario(scenario)}
251
+ @start=${(e) => this.startScenario(scenario, e.detail?.mode || 'released')}
240
252
  startable
241
253
  ></scenario-instance-log-view>
242
254
  `, {
@@ -244,22 +256,23 @@ let ScenarioMonitor = class ScenarioMonitor extends localize(i18next)(LitElement
244
256
  title: `${i18next.t('title.scenario-log')} (${scenario.name})`
245
257
  });
246
258
  }
247
- async startScenario(scenario) {
259
+ async startScenario(scenario, mode = 'released') {
248
260
  var response = await client.mutate({
249
261
  mutation: gql `
250
- mutation ($scenarioName: String!) {
251
- startScenario(scenarioName: $scenarioName) {
262
+ mutation ($scenarioName: String!, $mode: String) {
263
+ startScenario(scenarioName: $scenarioName, mode: $mode) {
252
264
  state
253
265
  }
254
266
  }
255
267
  `,
256
268
  variables: {
257
- scenarioName: scenario.name
269
+ scenarioName: scenario.name,
270
+ mode
258
271
  }
259
272
  });
260
273
  notify({
261
274
  level: 'info',
262
- message: `${!IS_SCENARIO_RUNNING(response.data.startScenario.state) ? 'fail' : 'success'} to start instance : ${scenario.name}`
275
+ message: `${!IS_SCENARIO_RUNNING(response.data.startScenario.state) ? 'fail' : 'success'} to start instance : ${scenario.name} (${mode})`
263
276
  });
264
277
  }
265
278
  async stopScenario(scenario) {
@@ -1 +1 @@
1
- {"version":3,"file":"scenario-monitor.js","sourceRoot":"","sources":["../../client/viewparts/scenario-monitor.ts"],"names":[],"mappings":"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","sourcesContent":["import '@material/web/icon/icon.js'\n\nimport '@operato/data-grist'\nimport './scenario-instance-monitor.js'\n\nimport gql from 'graphql-tag'\nimport { css, html, LitElement, nothing } from 'lit'\nimport { customElement, property } from 'lit/decorators.js'\n\nimport { client } from '@operato/graphql'\nimport { i18next, localize } from '@operato/i18n'\nimport { notify, openPopup } from '@operato/layout'\nimport { ScrollbarStyles } from '@operato/styles'\n\nfunction IS_SCENARIO_RUNNING(state) {\n return state && state !== 'UNLOADED'\n}\n\n@customElement('scenario-monitor')\nexport class ScenarioMonitor extends localize(i18next)(LitElement) {\n static styles = [\n ScrollbarStyles,\n css`\n :host {\n display: flex;\n flex-direction: row;\n\n border: var(--border-dim-color);\n background-color: var(--md-sys-color-surface);\n box-shadow: var(--box-shadow);\n border-radius: var(--border-radius);\n position: relative;\n overflow: hidden;\n }\n\n [desc] {\n position: relative;\n display: flex;\n flex-direction: column;\n padding: var(--spacing-medium);\n color: var(--md-sys-color-secondary);\n font-size: var(--fontsize-small);\n width: 100%;\n box-sizing: border-box;\n }\n\n [desc] [detail-info] {\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n width: calc(100% - 25px);\n height: 45px;\n }\n\n [desc] strong {\n display: flex;\n align-items: center;\n gap: var(--spacing-small);\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n font-size: var(--fontsize-large);\n }\n\n [desc] span {\n display: block;\n position: absolute;\n top: 0px;\n right: var(--spacing-medium);\n font-size: 40px;\n font-weight: bold;\n text-align: right;\n }\n\n [desc] [schedule] * {\n vertical-align: middle;\n display: inline-block;\n }\n\n [desc] [schedule] {\n background-color: #f1f1f1;\n border-radius: 20px;\n margin: var(--spacing-medium) 0;\n padding: var(--spacing-small);\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n font-size: 12px;\n line-height: 8px;\n }\n\n [desc] md-icon {\n --md-icon-size: 18px;\n border-radius: 50%;\n color: var(--md-sys-color-on-primary);\n }\n\n [desc] strong md-icon {\n --md-icon-size: 16px;\n color: var(--md-sys-color-primary);\n }\n\n [buttons] {\n display: flex;\n flex-direction: row-reverse;\n border-top: var(--border-dim-color);\n padding: var(--spacing-small) 0 0 0;\n }\n\n [buttons] md-icon {\n --md-icon-size: 22px;\n color: var(--md-sys-color-primary);\n }\n\n [buttons][detail] {\n display: flex;\n flex-direction: column-reverse;\n margin-bottom: auto;\n }\n\n :host([mode='detail']) [schedule] {\n margin: var(--spacing-medium) 0 0 0;\n }\n\n :host([mode='detail']) [desc] {\n flex: unset;\n width: 200px;\n }\n\n :host([mode='detail']) [desc] [buttons] {\n display: none;\n }\n\n :host([mode='detail']) [buttons] {\n border-top: none;\n padding: var(--spacing-medium);\n }\n\n ul {\n flex: 1;\n\n display: flex;\n flex-direction: row;\n flex-wrap: wrap;\n list-style: none;\n margin: 0;\n padding: 0;\n }\n\n ul > li {\n position: relative;\n margin: var(--spacing-medium);\n min-width: 140px;\n border: 1px solid black;\n border-radius: var(--border-radius);\n font-size: 12px;\n box-sizing: border-box;\n overflow: hidden;\n }\n\n li span {\n display: block;\n position: absolute;\n width: 100%;\n height: 100%;\n background-color: rgba(255, 255, 255, 0.8);\n }\n\n pre {\n margin: var(--spacing-medium);\n }\n\n @media screen and (max-width: 480px) {\n :host {\n margin: var(--spacing-small);\n }\n\n [desc] {\n padding: var(--spacing-small);\n }\n\n [desc] [detail-info] {\n height: 38px;\n }\n\n [desc] span {\n font-size: 36px;\n }\n }\n `\n ]\n\n @property({ type: Object }) scenario: any\n @property({ type: String }) mode?: string\n @property({ type: Boolean, attribute: 'is-parent' }) isParent?: boolean\n\n render() {\n const scenario = this.scenario || {}\n const mode = this.mode\n\n const { id, name, description, schedule, color } = scenario\n const instances = scenario.instances || []\n\n return html`\n <div desc>\n <div detail-info title=${name}>\n <strong\n >${name} ${this.isParent ? html`<md-icon title=\"inherited\">arrow_downward</md-icon>` : nothing}</strong\n >\n ${description}&nbsp;\n <span>${instances.length}</span>\n </div>\n <div schedule>\n <md-icon style=\"background-color: ${color};\">schedule</md-icon>\n <pre>${schedule}&nbsp;</pre>\n </div>\n ${this.renderButtons(scenario)}\n </div>\n\n ${mode === 'detail'\n ? html`\n <ul>\n ${instances.map(\n instance => html`\n <li style=\"border-color:${color};background-color:${color}\">\n <span></span>\n <scenario-instance-monitor .instance=${instance} .color=${color}></scenario-instance-monitor>\n </li>\n `\n )}\n </ul>\n ${this.renderButtons(scenario)}\n `\n : html``}\n `\n }\n\n renderButtons(scenario) {\n const instances = scenario.instances || []\n const scenarioInstance = instances.find(instance => instance.instanceName == scenario.name) || null\n\n return html`\n <div buttons ?detail=${this.mode == 'detail'}>\n <md-icon @click=${e => this.popupLogView(scenario)}>text_snippet</md-icon>\n ${!scenarioInstance\n ? html` <md-icon @click=${e => this.startScenario(scenario)}>play_circle</md-icon>`\n : html` <md-icon @click=${e => this.stopScenario(scenario)} stop>pause_circle</md-icon> `}\n </div>\n `\n }\n\n async popupLogView(scenario) {\n const popup = openPopup(\n html`\n <scenario-instance-log-view\n .scenarioName=${scenario.name}\n @start=${() => this.startScenario(scenario)}\n startable\n ></scenario-instance-log-view>\n `,\n {\n size: 'large',\n title: `${i18next.t('title.scenario-log')} (${scenario.name})`\n }\n )\n }\n\n async startScenario(scenario) {\n var response = await client.mutate({\n mutation: gql`\n mutation ($scenarioName: String!) {\n startScenario(scenarioName: $scenarioName) {\n state\n }\n }\n `,\n variables: {\n scenarioName: scenario.name\n }\n })\n\n notify({\n level: 'info',\n message: `${!IS_SCENARIO_RUNNING(response.data.startScenario.state) ? 'fail' : 'success'} to start instance : ${scenario.name}`\n })\n }\n\n async stopScenario(scenario) {\n var response = await client.mutate({\n mutation: gql`\n mutation ($instanceName: String!) {\n stopScenario(instanceName: $instanceName) {\n state\n }\n }\n `,\n variables: {\n instanceName: scenario.name\n }\n })\n\n notify({\n level: 'info',\n message: `${IS_SCENARIO_RUNNING(response.data.stopScenario.state) ? 'fail' : 'success'} to stop instance : ${scenario.name}`\n })\n }\n}\n"]}
1
+ {"version":3,"file":"scenario-monitor.js","sourceRoot":"","sources":["../../client/viewparts/scenario-monitor.ts"],"names":[],"mappings":"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","sourcesContent":["import '@material/web/icon/icon.js'\n\nimport '@operato/data-grist'\nimport './scenario-instance-monitor.js'\n\nimport gql from 'graphql-tag'\nimport { css, html, LitElement, nothing } from 'lit'\nimport { customElement, property } from 'lit/decorators.js'\n\nimport { client } from '@operato/graphql'\nimport { i18next, localize } from '@operato/i18n'\nimport { notify, openPopup } from '@operato/layout'\nimport { ScrollbarStyles } from '@operato/styles'\n\nfunction IS_SCENARIO_RUNNING(state) {\n return state && state !== 'UNLOADED'\n}\n\n@customElement('scenario-monitor')\nexport class ScenarioMonitor extends localize(i18next)(LitElement) {\n static styles = [\n ScrollbarStyles,\n css`\n :host {\n display: flex;\n flex-direction: row;\n\n border: var(--border-dim-color);\n background-color: var(--md-sys-color-surface);\n box-shadow: var(--box-shadow);\n border-radius: var(--border-radius);\n position: relative;\n overflow: hidden;\n }\n\n [desc] {\n position: relative;\n display: flex;\n flex-direction: column;\n padding: var(--spacing-medium);\n color: var(--md-sys-color-secondary);\n font-size: var(--fontsize-small);\n width: 100%;\n box-sizing: border-box;\n }\n\n [desc] [detail-info] {\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n width: calc(100% - 25px);\n height: 45px;\n }\n\n [desc] strong {\n display: flex;\n align-items: center;\n gap: var(--spacing-small);\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n font-size: var(--fontsize-large);\n }\n\n [desc] span {\n display: block;\n position: absolute;\n top: 0px;\n right: var(--spacing-medium);\n font-size: 40px;\n font-weight: bold;\n text-align: right;\n }\n\n [desc] [schedule] * {\n vertical-align: middle;\n display: inline-block;\n }\n\n [desc] [schedule] {\n background-color: #f1f1f1;\n border-radius: 20px;\n margin: var(--spacing-medium) 0;\n padding: var(--spacing-small);\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n font-size: 12px;\n line-height: 8px;\n }\n\n [desc] md-icon {\n --md-icon-size: 18px;\n border-radius: 50%;\n color: var(--md-sys-color-on-primary);\n }\n\n [desc] strong md-icon {\n --md-icon-size: 16px;\n color: var(--md-sys-color-primary);\n }\n\n [buttons] {\n display: flex;\n flex-direction: row-reverse;\n border-top: var(--border-dim-color);\n padding: var(--spacing-small) 0 0 0;\n }\n\n [buttons] md-icon {\n --md-icon-size: 22px;\n color: var(--md-sys-color-primary);\n }\n\n [buttons][detail] {\n display: flex;\n flex-direction: column-reverse;\n margin-bottom: auto;\n }\n\n :host([mode='detail']) [schedule] {\n margin: var(--spacing-medium) 0 0 0;\n }\n\n :host([mode='detail']) [desc] {\n flex: unset;\n width: 200px;\n }\n\n :host([mode='detail']) [desc] [buttons] {\n display: none;\n }\n\n :host([mode='detail']) [buttons] {\n border-top: none;\n padding: var(--spacing-medium);\n }\n\n ul {\n flex: 1;\n\n display: flex;\n flex-direction: row;\n flex-wrap: wrap;\n list-style: none;\n margin: 0;\n padding: 0;\n }\n\n ul > li {\n position: relative;\n margin: var(--spacing-medium);\n min-width: 140px;\n border: 1px solid black;\n border-radius: var(--border-radius);\n font-size: 12px;\n box-sizing: border-box;\n overflow: hidden;\n }\n\n li span {\n display: block;\n position: absolute;\n width: 100%;\n height: 100%;\n background-color: rgba(255, 255, 255, 0.8);\n }\n\n pre {\n margin: var(--spacing-medium);\n }\n\n @media screen and (max-width: 480px) {\n :host {\n margin: var(--spacing-small);\n }\n\n [desc] {\n padding: var(--spacing-small);\n }\n\n [desc] [detail-info] {\n height: 38px;\n }\n\n [desc] span {\n font-size: 36px;\n }\n }\n `\n ]\n\n @property({ type: Object }) scenario: any\n @property({ type: String }) mode?: string\n @property({ type: Boolean, attribute: 'is-parent' }) isParent?: boolean\n\n render() {\n const scenario = this.scenario || {}\n const mode = this.mode\n\n const { id, name, description, schedule, color } = scenario\n const instances = scenario.instances || []\n\n return html`\n <div desc>\n <div detail-info title=${name}>\n <strong\n >${name} ${this.isParent ? html`<md-icon title=\"inherited\">arrow_downward</md-icon>` : nothing}</strong\n >\n ${description}&nbsp;\n <span>${instances.length}</span>\n </div>\n <div schedule>\n <md-icon style=\"background-color: ${color};\">schedule</md-icon>\n <pre>${schedule}&nbsp;</pre>\n </div>\n ${this.renderButtons(scenario)}\n </div>\n\n ${mode === 'detail'\n ? html`\n <ul>\n ${instances.map(\n instance => html`\n <li style=\"border-color:${color};background-color:${color}\">\n <span></span>\n <scenario-instance-monitor .instance=${instance} .color=${color}></scenario-instance-monitor>\n </li>\n `\n )}\n </ul>\n ${this.renderButtons(scenario)}\n `\n : html``}\n `\n }\n\n renderButtons(scenario) {\n const instances = scenario.instances || []\n const scenarioInstance = instances.find(instance => instance.instanceName == scenario.name) || null\n\n return html`\n <div buttons ?detail=${this.mode == 'detail'}>\n <md-icon @click=${e => this.popupLogView(scenario)}>text_snippet</md-icon>\n ${!scenarioInstance\n ? html`\n <md-icon\n title=${i18next.t('button.run released version')}\n @click=${e => this.startScenario(scenario, 'released')}\n >play_circle</md-icon\n >\n <md-icon\n title=${i18next.t('button.run draft for debugging')}\n @click=${e => this.startScenario(scenario, 'draft')}\n debug\n >bug_report</md-icon\n >\n `\n : html` <md-icon @click=${e => this.stopScenario(scenario)} stop>pause_circle</md-icon> `}\n </div>\n `\n }\n\n async popupLogView(scenario) {\n const popup = openPopup(\n html`\n <scenario-instance-log-view\n .scenarioName=${scenario.name}\n @start=${(e: CustomEvent) => this.startScenario(scenario, e.detail?.mode || 'released')}\n startable\n ></scenario-instance-log-view>\n `,\n {\n size: 'large',\n title: `${i18next.t('title.scenario-log')} (${scenario.name})`\n }\n )\n }\n\n async startScenario(scenario, mode: string = 'released') {\n var response = await client.mutate({\n mutation: gql`\n mutation ($scenarioName: String!, $mode: String) {\n startScenario(scenarioName: $scenarioName, mode: $mode) {\n state\n }\n }\n `,\n variables: {\n scenarioName: scenario.name,\n mode\n }\n })\n\n notify({\n level: 'info',\n message: `${!IS_SCENARIO_RUNNING(response.data.startScenario.state) ? 'fail' : 'success'} to start instance : ${scenario.name} (${mode})`\n })\n }\n\n async stopScenario(scenario) {\n var response = await client.mutate({\n mutation: gql`\n mutation ($instanceName: String!) {\n stopScenario(instanceName: $instanceName) {\n state\n }\n }\n `,\n variables: {\n instanceName: scenario.name\n }\n })\n\n notify({\n level: 'info',\n message: `${IS_SCENARIO_RUNNING(response.data.stopScenario.state) ? 'fail' : 'success'} to stop instance : ${scenario.name}`\n })\n }\n}\n"]}
@@ -0,0 +1,31 @@
1
+ import '@material/web/icon/icon.js';
2
+ import '@material/web/chips/assist-chip.js';
3
+ import '@operato/data-grist/ox-empty-note.js';
4
+ import { LitElement } from 'lit';
5
+ /**
6
+ * 시나리오 버전 히스토리 패널.
7
+ *
8
+ * - 릴리즈된 버전 목록(버전번호·코멘트·작성자·시각)
9
+ * - 각 버전을 현재 draft 와 비교하는 diff 뷰
10
+ * - 과거 버전을 현재 draft 로 복사(revert)
11
+ *
12
+ * board-ui 의 board-versions 를 시나리오(스텝 배열 diff)에 맞춰 확장한 형태.
13
+ */
14
+ export declare class ScenarioVersions extends LitElement {
15
+ static styles: import("lit").CSSResult[];
16
+ scenarioId?: string;
17
+ scenarioName?: string;
18
+ /** revert(과거→draft 복사) 성공 시 호출 — 목록 자동 갱신용 콜백(속성 바인딩이라 팝업 경계에서도 확실히 동작). */
19
+ onReverted?: () => void;
20
+ versions: any[];
21
+ /** version → diff 결과(펼쳐진 경우만 존재) */
22
+ diffs: {
23
+ [version: number]: any;
24
+ };
25
+ render(): import("lit-html").TemplateResult<1>;
26
+ private renderDiff;
27
+ firstUpdated(): void;
28
+ refresh(): Promise<void>;
29
+ toggleDiff(version: number, prevVersion?: number): Promise<void>;
30
+ revert(version: number): Promise<void>;
31
+ }
@@ -0,0 +1,331 @@
1
+ import { __decorate, __metadata } from "tslib";
2
+ import '@material/web/icon/icon.js';
3
+ import '@material/web/chips/assist-chip.js';
4
+ import '@operato/data-grist/ox-empty-note.js';
5
+ import gql from 'graphql-tag';
6
+ import { css, html, LitElement } from 'lit';
7
+ import { customElement, property, state } from 'lit/decorators.js';
8
+ import { i18next } from '@operato/i18n';
9
+ import { client } from '@operato/graphql';
10
+ import { notify } from '@operato/layout';
11
+ import { OxPrompt } from '@operato/popup/ox-prompt.js';
12
+ import { ScrollbarStyles } from '@operato/styles';
13
+ /**
14
+ * 시나리오 버전 히스토리 패널.
15
+ *
16
+ * - 릴리즈된 버전 목록(버전번호·코멘트·작성자·시각)
17
+ * - 각 버전을 현재 draft 와 비교하는 diff 뷰
18
+ * - 과거 버전을 현재 draft 로 복사(revert)
19
+ *
20
+ * board-ui 의 board-versions 를 시나리오(스텝 배열 diff)에 맞춰 확장한 형태.
21
+ */
22
+ let ScenarioVersions = class ScenarioVersions extends LitElement {
23
+ constructor() {
24
+ super(...arguments);
25
+ this.versions = [];
26
+ /** version → diff 결과(펼쳐진 경우만 존재) */
27
+ this.diffs = {};
28
+ }
29
+ static { this.styles = [
30
+ ScrollbarStyles,
31
+ css `
32
+ :host {
33
+ display: flex;
34
+ flex-direction: column;
35
+ overflow: auto;
36
+ background-color: var(--md-sys-color-surface);
37
+ color: var(--md-sys-color-on-surface);
38
+ font: var(--label-font);
39
+ padding: var(--spacing-medium, 12px);
40
+ gap: var(--spacing-medium, 12px);
41
+ }
42
+
43
+ div[card] {
44
+ position: relative;
45
+ border: 1px solid var(--md-sys-color-outline-variant, rgba(0, 0, 0, 0.12));
46
+ border-radius: var(--border-radius, 6px);
47
+ padding: var(--spacing-medium, 12px);
48
+ text-align: start;
49
+ }
50
+
51
+ div[head] {
52
+ display: flex;
53
+ align-items: center;
54
+ gap: var(--spacing-small, 6px);
55
+ }
56
+
57
+ div[head] [ver] {
58
+ font: var(--subtitle-font, bold 14px sans-serif);
59
+ color: var(--md-sys-color-primary);
60
+ display: inline-flex;
61
+ align-items: center;
62
+ gap: 3px;
63
+ }
64
+
65
+ div[head] [meta] {
66
+ margin-left: auto;
67
+ display: inline-flex;
68
+ align-items: center;
69
+ gap: 5px;
70
+ opacity: 0.75;
71
+ font-size: var(--fontsize-small, 12px);
72
+ }
73
+
74
+ div[comment] {
75
+ margin-top: 6px;
76
+ white-space: pre-wrap;
77
+ color: var(--md-sys-color-on-surface-variant, inherit);
78
+ }
79
+
80
+ div[actions] {
81
+ display: flex;
82
+ gap: var(--spacing-small, 6px);
83
+ margin-top: 8px;
84
+ }
85
+
86
+ md-icon {
87
+ font-size: var(--fontsize-large, 18px);
88
+ vertical-align: middle;
89
+ }
90
+
91
+ button {
92
+ cursor: pointer;
93
+ border: 1px solid var(--md-sys-color-outline, rgba(0, 0, 0, 0.2));
94
+ background: var(--md-sys-color-surface);
95
+ color: inherit;
96
+ border-radius: var(--border-radius, 6px);
97
+ padding: 4px 10px;
98
+ display: inline-flex;
99
+ align-items: center;
100
+ gap: 4px;
101
+ font: inherit;
102
+ }
103
+ button[primary] {
104
+ background: var(--md-sys-color-primary);
105
+ color: var(--md-sys-color-on-primary);
106
+ border-color: transparent;
107
+ }
108
+
109
+ div[diff] {
110
+ margin-top: 8px;
111
+ border-top: 1px dashed var(--md-sys-color-outline-variant, rgba(0, 0, 0, 0.12));
112
+ padding-top: 8px;
113
+ font-size: var(--fontsize-small, 12px);
114
+ }
115
+ div[diff] [group] {
116
+ font-weight: bold;
117
+ margin: 4px 0 2px;
118
+ }
119
+ [change] {
120
+ display: block;
121
+ padding: 1px 0;
122
+ }
123
+ [change][added] {
124
+ color: var(--md-sys-color-primary, green);
125
+ }
126
+ [change][removed] {
127
+ color: var(--md-sys-color-error, #b00020);
128
+ text-decoration: line-through;
129
+ opacity: 0.8;
130
+ }
131
+ [change][modified] {
132
+ color: var(--status-warning-color, #b26a00);
133
+ }
134
+ [change] small {
135
+ opacity: 0.7;
136
+ }
137
+
138
+ ox-empty-note {
139
+ padding: 24px;
140
+ opacity: 0.7;
141
+ }
142
+ `
143
+ ]; }
144
+ render() {
145
+ return html `
146
+ ${this.versions.length == 0
147
+ ? /* 빈 상태는 프레임워크 공통 부품(ox-empty-note) 사용 */
148
+ html `<ox-empty-note icon="history" title=${i18next.t('text.no released version information available')}></ox-empty-note>`
149
+ : this.versions.map((version, index) => html `
150
+ <div card>
151
+ <div head>
152
+ <span ver><md-icon>sell</md-icon> v${version.version}</span>
153
+ <span meta>
154
+ <md-icon>person</md-icon> ${version.updater?.name || 'anonymous'}
155
+ <md-icon>schedule</md-icon> ${new Date(version.updatedAt).toLocaleString()}
156
+ </span>
157
+ </div>
158
+
159
+ ${version.comment ? html `<div comment>${version.comment}</div>` : ''}
160
+
161
+ <div actions>
162
+ <button @click=${() => this.toggleDiff(version.version, this.versions[index + 1]?.version)}>
163
+ <md-icon>difference</md-icon>${i18next.t('button.diff with previous')}
164
+ </button>
165
+ <button primary @click=${() => this.revert(version.version)}>
166
+ <md-icon>settings_backup_restore</md-icon>${i18next.t('button.copy to draft')}
167
+ </button>
168
+ </div>
169
+
170
+ ${this.diffs[version.version] ? this.renderDiff(this.diffs[version.version]) : ''}
171
+ </div>
172
+ `)}
173
+ `;
174
+ }
175
+ renderDiff(diff) {
176
+ if (diff.earliest) {
177
+ return html `<div diff>${i18next.t('text.initial version all new')}</div>`;
178
+ }
179
+ const fieldDiffs = diff.fieldDiffs || [];
180
+ const stepDiffs = diff.stepDiffs || [];
181
+ if (fieldDiffs.length == 0 && stepDiffs.length == 0) {
182
+ return html `<div diff>${i18next.t('text.no difference from previous')}</div>`;
183
+ }
184
+ const fmt = (v) => (v === null || v === undefined ? '∅' : typeof v === 'object' ? JSON.stringify(v) : String(v));
185
+ return html `
186
+ <div diff>
187
+ ${fieldDiffs.length
188
+ ? html `
189
+ <div group>${i18next.t('label.scenario fields')}</div>
190
+ ${fieldDiffs.map((f) => html `<span change modified>${f.field}: <small>${fmt(f.before)} → ${fmt(f.after)}</small></span>`)}
191
+ `
192
+ : ''}
193
+ ${stepDiffs.length
194
+ ? html `
195
+ <div group>${i18next.t('label.steps')}</div>
196
+ ${stepDiffs.map((s) => {
197
+ if (s.changeType == 'added') {
198
+ return html `<span change added>+ ${s.name || '(unnamed)'}</span>`;
199
+ }
200
+ if (s.changeType == 'removed') {
201
+ return html `<span change removed>− ${s.name || '(unnamed)'}</span>`;
202
+ }
203
+ const changed = (s.fieldDiffs || []).map((fd) => fd.field).join(', ');
204
+ return html `<span change modified>~ ${s.name || '(unnamed)'} <small>(${changed})</small></span>`;
205
+ })}
206
+ `
207
+ : ''}
208
+ </div>
209
+ `;
210
+ }
211
+ firstUpdated() {
212
+ this.refresh();
213
+ }
214
+ async refresh() {
215
+ if (!this.scenarioId) {
216
+ return;
217
+ }
218
+ const response = (await client.query({
219
+ query: gql `
220
+ query FetchScenarioVersions($id: String!) {
221
+ scenarioVersions(id: $id) {
222
+ id
223
+ version
224
+ comment
225
+ updater {
226
+ name
227
+ }
228
+ updatedAt
229
+ }
230
+ }
231
+ `,
232
+ variables: { id: this.scenarioId },
233
+ fetchPolicy: 'no-cache'
234
+ })).data;
235
+ this.versions = response.scenarioVersions || [];
236
+ }
237
+ async toggleDiff(version, prevVersion) {
238
+ if (this.diffs[version]) {
239
+ const { [version]: _removed, ...rest } = this.diffs;
240
+ this.diffs = rest;
241
+ return;
242
+ }
243
+ // 앞 버전과 비교 = "이 버전이 무엇을 바꿨나"(체인지로그). 최초 버전은 앞 버전이 없어 전체 신규.
244
+ if (prevVersion === undefined || prevVersion === null) {
245
+ this.diffs = { ...this.diffs, [version]: { earliest: true } };
246
+ return;
247
+ }
248
+ const response = await client.query({
249
+ query: gql `
250
+ query ScenarioVersionDiff($id: String!, $base: Int!, $to: Int!) {
251
+ scenarioVersionDiff(id: $id, version: $base, toVersion: $to) {
252
+ fromVersion
253
+ toVersion
254
+ fieldDiffs {
255
+ field
256
+ before
257
+ after
258
+ }
259
+ stepDiffs {
260
+ name
261
+ changeType
262
+ fieldDiffs {
263
+ field
264
+ }
265
+ }
266
+ }
267
+ }
268
+ `,
269
+ variables: { id: this.scenarioId, base: prevVersion, to: version },
270
+ fetchPolicy: 'no-cache'
271
+ });
272
+ this.diffs = { ...this.diffs, [version]: response.data.scenarioVersionDiff };
273
+ }
274
+ async revert(version) {
275
+ const ok = await OxPrompt.open({
276
+ type: 'question',
277
+ title: String(i18next.t('button.copy to draft')),
278
+ text: String(i18next.t('text.sure to copy version to draft', { version })),
279
+ confirmButton: { text: String(i18next.t('button.confirm')) },
280
+ cancelButton: { text: String(i18next.t('button.cancel')) }
281
+ });
282
+ if (!ok) {
283
+ return;
284
+ }
285
+ const response = await client.mutate({
286
+ mutation: gql `
287
+ mutation RevertScenarioVersion($id: String!, $version: Int!) {
288
+ revertScenarioVersion(id: $id, version: $version) {
289
+ id
290
+ version
291
+ publishState
292
+ }
293
+ }
294
+ `,
295
+ variables: { id: this.scenarioId, version }
296
+ });
297
+ if (!response.errors) {
298
+ notify({ message: i18next.t('text.info_x_successfully', { x: i18next.t('text.copy') }) });
299
+ this.onReverted?.();
300
+ this.dispatchEvent(new CustomEvent('reverted', { bubbles: true, composed: true }));
301
+ }
302
+ else {
303
+ notify({ level: 'error', message: response.errors.map(e => e.message).join('\n') });
304
+ }
305
+ }
306
+ };
307
+ __decorate([
308
+ property({ type: String }),
309
+ __metadata("design:type", String)
310
+ ], ScenarioVersions.prototype, "scenarioId", void 0);
311
+ __decorate([
312
+ property({ type: String }),
313
+ __metadata("design:type", String)
314
+ ], ScenarioVersions.prototype, "scenarioName", void 0);
315
+ __decorate([
316
+ property({ attribute: false }),
317
+ __metadata("design:type", Function)
318
+ ], ScenarioVersions.prototype, "onReverted", void 0);
319
+ __decorate([
320
+ state(),
321
+ __metadata("design:type", Array)
322
+ ], ScenarioVersions.prototype, "versions", void 0);
323
+ __decorate([
324
+ state(),
325
+ __metadata("design:type", Object)
326
+ ], ScenarioVersions.prototype, "diffs", void 0);
327
+ ScenarioVersions = __decorate([
328
+ customElement('scenario-versions')
329
+ ], ScenarioVersions);
330
+ export { ScenarioVersions };
331
+ //# sourceMappingURL=scenario-versions.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"scenario-versions.js","sourceRoot":"","sources":["../../client/viewparts/scenario-versions.ts"],"names":[],"mappings":"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","sourcesContent":["import '@material/web/icon/icon.js'\nimport '@material/web/chips/assist-chip.js'\nimport '@operato/data-grist/ox-empty-note.js'\n\nimport gql from 'graphql-tag'\nimport { css, html, LitElement } from 'lit'\nimport { customElement, property, state } from 'lit/decorators.js'\n\nimport { i18next } from '@operato/i18n'\nimport { client } from '@operato/graphql'\nimport { notify } from '@operato/layout'\nimport { OxPrompt } from '@operato/popup/ox-prompt.js'\nimport { ScrollbarStyles } from '@operato/styles'\n\n/**\n * 시나리오 버전 히스토리 패널.\n *\n * - 릴리즈된 버전 목록(버전번호·코멘트·작성자·시각)\n * - 각 버전을 현재 draft 와 비교하는 diff 뷰\n * - 과거 버전을 현재 draft 로 복사(revert)\n *\n * board-ui 의 board-versions 를 시나리오(스텝 배열 diff)에 맞춰 확장한 형태.\n */\n@customElement('scenario-versions')\nexport class ScenarioVersions extends LitElement {\n static styles = [\n ScrollbarStyles,\n css`\n :host {\n display: flex;\n flex-direction: column;\n overflow: auto;\n background-color: var(--md-sys-color-surface);\n color: var(--md-sys-color-on-surface);\n font: var(--label-font);\n padding: var(--spacing-medium, 12px);\n gap: var(--spacing-medium, 12px);\n }\n\n div[card] {\n position: relative;\n border: 1px solid var(--md-sys-color-outline-variant, rgba(0, 0, 0, 0.12));\n border-radius: var(--border-radius, 6px);\n padding: var(--spacing-medium, 12px);\n text-align: start;\n }\n\n div[head] {\n display: flex;\n align-items: center;\n gap: var(--spacing-small, 6px);\n }\n\n div[head] [ver] {\n font: var(--subtitle-font, bold 14px sans-serif);\n color: var(--md-sys-color-primary);\n display: inline-flex;\n align-items: center;\n gap: 3px;\n }\n\n div[head] [meta] {\n margin-left: auto;\n display: inline-flex;\n align-items: center;\n gap: 5px;\n opacity: 0.75;\n font-size: var(--fontsize-small, 12px);\n }\n\n div[comment] {\n margin-top: 6px;\n white-space: pre-wrap;\n color: var(--md-sys-color-on-surface-variant, inherit);\n }\n\n div[actions] {\n display: flex;\n gap: var(--spacing-small, 6px);\n margin-top: 8px;\n }\n\n md-icon {\n font-size: var(--fontsize-large, 18px);\n vertical-align: middle;\n }\n\n button {\n cursor: pointer;\n border: 1px solid var(--md-sys-color-outline, rgba(0, 0, 0, 0.2));\n background: var(--md-sys-color-surface);\n color: inherit;\n border-radius: var(--border-radius, 6px);\n padding: 4px 10px;\n display: inline-flex;\n align-items: center;\n gap: 4px;\n font: inherit;\n }\n button[primary] {\n background: var(--md-sys-color-primary);\n color: var(--md-sys-color-on-primary);\n border-color: transparent;\n }\n\n div[diff] {\n margin-top: 8px;\n border-top: 1px dashed var(--md-sys-color-outline-variant, rgba(0, 0, 0, 0.12));\n padding-top: 8px;\n font-size: var(--fontsize-small, 12px);\n }\n div[diff] [group] {\n font-weight: bold;\n margin: 4px 0 2px;\n }\n [change] {\n display: block;\n padding: 1px 0;\n }\n [change][added] {\n color: var(--md-sys-color-primary, green);\n }\n [change][removed] {\n color: var(--md-sys-color-error, #b00020);\n text-decoration: line-through;\n opacity: 0.8;\n }\n [change][modified] {\n color: var(--status-warning-color, #b26a00);\n }\n [change] small {\n opacity: 0.7;\n }\n\n ox-empty-note {\n padding: 24px;\n opacity: 0.7;\n }\n `\n ]\n\n @property({ type: String }) scenarioId?: string\n @property({ type: String }) scenarioName?: string\n /** revert(과거→draft 복사) 성공 시 호출 — 목록 자동 갱신용 콜백(속성 바인딩이라 팝업 경계에서도 확실히 동작). */\n @property({ attribute: false }) onReverted?: () => void\n\n @state() versions: any[] = []\n /** version → diff 결과(펼쳐진 경우만 존재) */\n @state() diffs: { [version: number]: any } = {}\n\n render() {\n return html`\n ${this.versions.length == 0\n ? /* 빈 상태는 프레임워크 공통 부품(ox-empty-note) 사용 */\n html`<ox-empty-note icon=\"history\" title=${i18next.t('text.no released version information available')}></ox-empty-note>`\n : this.versions.map(\n (version, index) => html`\n <div card>\n <div head>\n <span ver><md-icon>sell</md-icon> v${version.version}</span>\n <span meta>\n <md-icon>person</md-icon> ${version.updater?.name || 'anonymous'}\n <md-icon>schedule</md-icon> ${new Date(version.updatedAt).toLocaleString()}\n </span>\n </div>\n\n ${version.comment ? html`<div comment>${version.comment}</div>` : ''}\n\n <div actions>\n <button @click=${() => this.toggleDiff(version.version, this.versions[index + 1]?.version)}>\n <md-icon>difference</md-icon>${i18next.t('button.diff with previous')}\n </button>\n <button primary @click=${() => this.revert(version.version)}>\n <md-icon>settings_backup_restore</md-icon>${i18next.t('button.copy to draft')}\n </button>\n </div>\n\n ${this.diffs[version.version] ? this.renderDiff(this.diffs[version.version]) : ''}\n </div>\n `\n )}\n `\n }\n\n private renderDiff(diff: any) {\n if (diff.earliest) {\n return html`<div diff>${i18next.t('text.initial version all new')}</div>`\n }\n\n const fieldDiffs = diff.fieldDiffs || []\n const stepDiffs = diff.stepDiffs || []\n\n if (fieldDiffs.length == 0 && stepDiffs.length == 0) {\n return html`<div diff>${i18next.t('text.no difference from previous')}</div>`\n }\n\n const fmt = (v: any) => (v === null || v === undefined ? '∅' : typeof v === 'object' ? JSON.stringify(v) : String(v))\n\n return html`\n <div diff>\n ${fieldDiffs.length\n ? html`\n <div group>${i18next.t('label.scenario fields')}</div>\n ${fieldDiffs.map(\n (f: any) => html`<span change modified>${f.field}: <small>${fmt(f.before)} → ${fmt(f.after)}</small></span>`\n )}\n `\n : ''}\n ${stepDiffs.length\n ? html`\n <div group>${i18next.t('label.steps')}</div>\n ${stepDiffs.map((s: any) => {\n if (s.changeType == 'added') {\n return html`<span change added>+ ${s.name || '(unnamed)'}</span>`\n }\n if (s.changeType == 'removed') {\n return html`<span change removed>− ${s.name || '(unnamed)'}</span>`\n }\n const changed = (s.fieldDiffs || []).map((fd: any) => fd.field).join(', ')\n return html`<span change modified>~ ${s.name || '(unnamed)'} <small>(${changed})</small></span>`\n })}\n `\n : ''}\n </div>\n `\n }\n\n firstUpdated() {\n this.refresh()\n }\n\n async refresh() {\n if (!this.scenarioId) {\n return\n }\n\n const response = (\n await client.query({\n query: gql`\n query FetchScenarioVersions($id: String!) {\n scenarioVersions(id: $id) {\n id\n version\n comment\n updater {\n name\n }\n updatedAt\n }\n }\n `,\n variables: { id: this.scenarioId },\n fetchPolicy: 'no-cache'\n })\n ).data\n\n this.versions = response.scenarioVersions || []\n }\n\n async toggleDiff(version: number, prevVersion?: number) {\n if (this.diffs[version]) {\n const { [version]: _removed, ...rest } = this.diffs\n this.diffs = rest\n return\n }\n\n // 앞 버전과 비교 = \"이 버전이 무엇을 바꿨나\"(체인지로그). 최초 버전은 앞 버전이 없어 전체 신규.\n if (prevVersion === undefined || prevVersion === null) {\n this.diffs = { ...this.diffs, [version]: { earliest: true } }\n return\n }\n\n const response = await client.query({\n query: gql`\n query ScenarioVersionDiff($id: String!, $base: Int!, $to: Int!) {\n scenarioVersionDiff(id: $id, version: $base, toVersion: $to) {\n fromVersion\n toVersion\n fieldDiffs {\n field\n before\n after\n }\n stepDiffs {\n name\n changeType\n fieldDiffs {\n field\n }\n }\n }\n }\n `,\n variables: { id: this.scenarioId, base: prevVersion, to: version },\n fetchPolicy: 'no-cache'\n })\n\n this.diffs = { ...this.diffs, [version]: response.data.scenarioVersionDiff }\n }\n\n async revert(version: number) {\n const ok = await OxPrompt.open({\n type: 'question',\n title: String(i18next.t('button.copy to draft')),\n text: String(i18next.t('text.sure to copy version to draft', { version })),\n confirmButton: { text: String(i18next.t('button.confirm')) },\n cancelButton: { text: String(i18next.t('button.cancel')) }\n })\n if (!ok) {\n return\n }\n\n const response = await client.mutate({\n mutation: gql`\n mutation RevertScenarioVersion($id: String!, $version: Int!) {\n revertScenarioVersion(id: $id, version: $version) {\n id\n version\n publishState\n }\n }\n `,\n variables: { id: this.scenarioId, version }\n })\n\n if (!response.errors) {\n notify({ message: i18next.t('text.info_x_successfully', { x: i18next.t('text.copy') }) })\n this.onReverted?.()\n this.dispatchEvent(new CustomEvent('reverted', { bubbles: true, composed: true }))\n } else {\n notify({ level: 'error', message: response.errors.map(e => e.message).join('\\n') })\n }\n }\n}\n"]}