@things-factory/worklist 10.1.169 → 10.1.173
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/dist-client/components/decision-content.d.ts +1 -1
- package/dist-client/components/decision-content.js +25 -4
- package/dist-client/components/decision-content.js.map +1 -1
- package/dist-client/pages/activity-instance/activity-instance-view.d.ts +10 -2
- package/dist-client/pages/activity-instance/activity-instance-view.js +18 -22
- package/dist-client/pages/activity-instance/activity-instance-view.js.map +1 -1
- package/dist-client/pages/activity-thread/activity-thread-view-page.js +2 -0
- package/dist-client/pages/activity-thread/activity-thread-view-page.js.map +1 -1
- package/dist-client/pages/activity-thread/activity-thread-view.js +18 -2
- package/dist-client/pages/activity-thread/activity-thread-view.js.map +1 -1
- package/dist-client/pages/todo/draft-list-page.d.ts +11 -3
- package/dist-client/pages/todo/draft-list-page.js +23 -7
- package/dist-client/pages/todo/draft-list-page.js.map +1 -1
- package/dist-client/pages/todo/work-box.d.ts +16 -0
- package/dist-client/pages/todo/work-box.js +10 -0
- package/dist-client/pages/todo/work-box.js.map +1 -1
- package/dist-client/route.d.ts +1 -1
- package/dist-client/tsconfig.tsbuildinfo +1 -1
- package/dist-server/service/activity-summary/index.d.ts +1 -1
- package/dist-server/service/activity-thread/index.d.ts +1 -1
- package/dist-server/service/index.d.ts +3 -3
- package/dist-server/tsconfig.tsbuildinfo +1 -1
- package/package.json +5 -5
- package/dist-client/pages/todo/done-list-page.d.ts +0 -38
- package/dist-client/pages/todo/done-list-page.js +0 -382
- package/dist-client/pages/todo/done-list-page.js.map +0 -1
|
@@ -11,7 +11,7 @@ import { nothing, TemplateResult } from 'lit';
|
|
|
11
11
|
/**
|
|
12
12
|
* The fields a page asks for to draw the decision - every field renderDecision reads.
|
|
13
13
|
*
|
|
14
|
-
* `name` is the label when
|
|
14
|
+
* `name` is the label when the translation `tKey` names is missing (decisionLabel), and `valueTKey` with `params`
|
|
15
15
|
* builds the value sentence at reading time (slotText). Leaving them out drew the sentence frozen
|
|
16
16
|
* at issue, in the language of whoever raised it, with nothing to say a field was missing.
|
|
17
17
|
*/
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import '@material/web/icon/icon.js';
|
|
2
2
|
import { css, html, nothing } from 'lit';
|
|
3
3
|
import { i18next } from '@operato/i18n';
|
|
4
|
+
import { entity360KindOf, entity360Name } from '@operato/layout';
|
|
4
5
|
import { declaredLabel, fieldValue } from './activity-fields.js';
|
|
5
6
|
import { COMPENSABLE, decisionDrawable, decisionSlots, reversibilityIsMalformed, reversibilityOf, slotOfRole, slotsOfRole } from './decision-slots.js';
|
|
6
7
|
/**
|
|
@@ -14,7 +15,7 @@ import { COMPENSABLE, decisionDrawable, decisionSlots, reversibilityIsMalformed,
|
|
|
14
15
|
/**
|
|
15
16
|
* The fields a page asks for to draw the decision - every field renderDecision reads.
|
|
16
17
|
*
|
|
17
|
-
* `name` is the label when
|
|
18
|
+
* `name` is the label when the translation `tKey` names is missing (decisionLabel), and `valueTKey` with `params`
|
|
18
19
|
* builds the value sentence at reading time (slotText). Leaving them out drew the sentence frozen
|
|
19
20
|
* at issue, in the language of whoever raised it, with nothing to say a field was missing.
|
|
20
21
|
*/
|
|
@@ -75,7 +76,7 @@ export function renderDecision(decisionKeys, input) {
|
|
|
75
76
|
<div class="label">${i18next.t('label.what-it-was-judged-from')}</div>
|
|
76
77
|
${evidence.map(slot => html `
|
|
77
78
|
<div class="evidence">
|
|
78
|
-
${
|
|
79
|
+
${decisionLabel(slot) ? html `<div class="label">${decisionLabel(slot)}</div>` : ''}
|
|
79
80
|
<div>${slotText(slot)}</div>
|
|
80
81
|
</div>
|
|
81
82
|
`)}
|
|
@@ -85,7 +86,7 @@ export function renderDecision(decisionKeys, input) {
|
|
|
85
86
|
${currentState?.found
|
|
86
87
|
? html `
|
|
87
88
|
<div class="current-state">
|
|
88
|
-
<div class="label">${
|
|
89
|
+
<div class="label">${decisionLabel(currentState) || i18next.t('label.current-state')}</div>
|
|
89
90
|
<div>${slotText(currentState)}</div>
|
|
90
91
|
</div>
|
|
91
92
|
`
|
|
@@ -96,7 +97,7 @@ export function renderDecision(decisionKeys, input) {
|
|
|
96
97
|
<div class="label">${i18next.t('label.what-changes')}</div>
|
|
97
98
|
${consequences.map(slot => html `
|
|
98
99
|
<div class="consequence">
|
|
99
|
-
${
|
|
100
|
+
${decisionLabel(slot) ? html `<div class="label">${decisionLabel(slot)}</div>` : ''}
|
|
100
101
|
<div>${slotText(slot)}</div>
|
|
101
102
|
</div>
|
|
102
103
|
`)}
|
|
@@ -106,6 +107,18 @@ export function renderDecision(decisionKeys, input) {
|
|
|
106
107
|
</section>
|
|
107
108
|
`;
|
|
108
109
|
}
|
|
110
|
+
/**
|
|
111
|
+
* A slot's own label - only where the declaration names one with `tKey`.
|
|
112
|
+
*
|
|
113
|
+
* A decision key's `name` is the developer's note ("Never shown on a screen", ActivityDecisionKeyItem),
|
|
114
|
+
* and without `tKey` the screen shows no label. declaredLabel falls back to `name` whenever `tKey` is
|
|
115
|
+
* absent - right for a search key, whose name is its column, and wrong here: asking for `name` put
|
|
116
|
+
* "what approving does" under 「승인하면 달라지는 것」 on a Korean screen (2026-10-16). The fallback
|
|
117
|
+
* stays for a declared key whose translation is missing.
|
|
118
|
+
*/
|
|
119
|
+
function decisionLabel(slot) {
|
|
120
|
+
return slot.tKey ? declaredLabel(slot) : '';
|
|
121
|
+
}
|
|
109
122
|
/**
|
|
110
123
|
* Whether approving can be undone, drawn as the frame around the decision.
|
|
111
124
|
*
|
|
@@ -169,6 +182,14 @@ function slotText(slot) {
|
|
|
169
182
|
if (said) {
|
|
170
183
|
return said;
|
|
171
184
|
}
|
|
185
|
+
/*
|
|
186
|
+
* A value that names what it is - `{ __typename, id, name }` - is drawn as its name, a link to its
|
|
187
|
+
* 360 (ADR-0067 decision 1: an entity's name opens its 360). The counterparty an expenditure pays
|
|
188
|
+
* opens the counterparty 360; a person opens the person 360. A kind nobody registered stays text.
|
|
189
|
+
*/
|
|
190
|
+
if (slot.value && typeof slot.value === 'object' && !Array.isArray(slot.value) && entity360KindOf(slot.value)) {
|
|
191
|
+
return entity360Name(slot.value);
|
|
192
|
+
}
|
|
172
193
|
const scalar = slot.value !== null && slot.value !== undefined && typeof slot.value !== 'object';
|
|
173
194
|
if (scalar && slot.unit) {
|
|
174
195
|
return `${slot.value} ${slot.unit}`;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"decision-content.js","sourceRoot":"","sources":["../../client/components/decision-content.ts"],"names":[],"mappings":"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","sourcesContent":["import '@material/web/icon/icon.js'\n\nimport { css, html, nothing, TemplateResult } from 'lit'\nimport { i18next } from '@operato/i18n'\n\nimport { declaredLabel, fieldValue } from './activity-fields.js'\nimport {\n COMPENSABLE,\n DecisionSlot,\n decisionDrawable,\n decisionSlots,\n reversibilityIsMalformed,\n reversibilityOf,\n slotOfRole,\n slotsOfRole\n} from './decision-slots.js'\n\n/**\n * The decision an activity declared, drawn the one way every screen draws it.\n *\n * The approval screen drew it and the task screen did not. An activity whose model is all hidden -\n * the expenditure request carries its payee and lines only for its decisionKeys - then showed the\n * approver what was asked and showed the person who asked an empty box. Both read the same\n * declaration and the same input, so one drawing serves both.\n */\n\n/**\n * The fields a page asks for to draw the decision - every field renderDecision reads.\n *\n * `name` is the label when no translation has `tKey` (declaredLabel), and `valueTKey` with `params`\n * builds the value sentence at reading time (slotText). Leaving them out drew the sentence frozen\n * at issue, in the language of whoever raised it, with nothing to say a field was missing.\n */\nexport const DecisionKeysFields = `decisionKeys {\n role\n inputPath\n name\n tKey\n valueTKey\n params\n unit\n}`\n\n/**\n * The decision, or `nothing` when the activity declared none or none of it is in this input.\n *\n * Returning nothing is how a page knows to fall back to the model. An activity with no\n * decisionKeys draws exactly what it drew before.\n *\n * A slot whose path led nowhere is skipped rather than drawn empty. Older instances of an activity\n * predate a field the declaration names and an empty bar on the screen would read as \"there is no\n * reason\" when the truth is that this record has no such value. What cannot be shown is left out;\n * what is shown is only what the payload actually carries.\n *\n * `reason` is the exception. Missing and blank mean the same thing to whoever is reading - nobody\n * wrote one - so both draw the grey line rather than disappearing. A reason that silently vanishes\n * would let an approver assume it was never asked for.\n */\nexport function renderDecision(decisionKeys: any, input: any): TemplateResult | typeof nothing {\n const slots = decisionSlots(decisionKeys, input)\n\n if (!decisionDrawable(slots)) {\n return nothing\n }\n\n const headline = slotOfRole(slots, 'headline')\n const subject = slotOfRole(slots, 'subject')\n const reason = slotOfRole(slots, 'reason')\n const consequences = slotsOfRole(slots, 'consequence').filter(slot => slot.found)\n const evidence = slotsOfRole(slots, 'evidence').filter(slot => slot.found)\n const currentState = slotOfRole(slots, 'currentState')\n const reversibility = slotOfRole(slots, 'reversibility')\n\n return html`\n <section decision>\n ${headline?.found ? html`<div class=\"headline\">${slotText(headline)}</div>` : ''}\n ${subject?.found ? html`<div class=\"subject\">${slotText(subject)}</div>` : ''}\n ${\n reason\n ? html`\n <div class=\"block\">\n <div class=\"label\">${i18next.t('field.reason')}</div>\n <div class=\"said ${hasWords(reason) ? '' : 'none'}\">\n ${hasWords(reason) ? slotText(reason) : i18next.t('text.no-reason-given')}\n </div>\n </div>\n `\n : ''\n }\n ${renderReversibility(reversibility)}\n ${\n evidence.length\n ? html`\n <div class=\"block\">\n <div class=\"label\">${i18next.t('label.what-it-was-judged-from')}</div>\n ${evidence.map(\n slot => html`\n <div class=\"evidence\">\n ${declaredLabel(slot) ? html`<div class=\"label\">${declaredLabel(slot)}</div>` : ''}\n <div>${slotText(slot)}</div>\n </div>\n `\n )}\n </div>\n `\n : ''\n }\n ${\n currentState?.found\n ? html`\n <div class=\"current-state\">\n <div class=\"label\">${declaredLabel(currentState) || i18next.t('label.current-state')}</div>\n <div>${slotText(currentState)}</div>\n </div>\n `\n : ''\n }\n ${\n consequences.length\n ? html`\n <div class=\"block\">\n <div class=\"label\">${i18next.t('label.what-changes')}</div>\n ${consequences.map(\n slot => html`\n <div class=\"consequence\">\n ${declaredLabel(slot) ? html`<div class=\"label\">${declaredLabel(slot)}</div>` : ''}\n <div>${slotText(slot)}</div>\n </div>\n `\n )}\n </div>\n `\n : ''\n }\n </section>\n `\n}\n\n/**\n * Whether approving can be undone, drawn as the frame around the decision.\n *\n * Only an explicit true or false draws. Anything else - the path led nowhere, or the value is not\n * a boolean - draws nothing, because saying \"this can be undone\" on a screen that does not know is\n * the one mistake this line must never make.\n *\n * This is not rejectionIsFinal. That one says whether **rejecting** ends the case for good; this\n * says whether **approving** can be taken back. The twin actuation carries both, which is exactly\n * why they must not share a sentence.\n */\nfunction renderReversibility(slot?: DecisionSlot) {\n const said = reversibilityOf(slot)\n\n if (!said) {\n if (reversibilityIsMalformed(slot)) {\n /*\n * Declared, and the value is there, but not the shape this role takes - a bare sentence\n * where { reversible, caveat } belongs. Nothing is drawn, because this side cannot tell\n * which way it goes; the log is so a developer does not have to find it by hand, which is\n * how it was found the first time.\n */\n console.error(`[worklist] reversibility at \"${slot?.inputPath}\" is not { reversible, caveat } — nothing drawn`)\n }\n\n return ''\n }\n\n /*\n * The module's own sentence when it wrote one. 「버린 자재는 돌아오지 않습니다」 says why, which\n * the plain wording cannot; the boolean beside it is what decides how heavily this is drawn.\n */\n return html`\n <div class=\"reversibility\" ?irreversible=${!said.reversible}>\n <md-icon>${said.kind === COMPENSABLE ? 'history' : said.reversible ? 'undo' : 'lock'}</md-icon>\n <span\n >${\n said.caveat || (said.kind === COMPENSABLE\n ? i18next.t('text.approval-is-compensable', { defaultValue: 'The original decision remains. A subsequent corrective action is required.' })\n : i18next.t(said.reversible ? 'text.approval-is-reversible' : 'text.approval-is-irreversible'))\n }</span\n >\n </div>\n `\n}\n\n/**\n * One slot's value as something to read.\n *\n * A scalar prints with its unit when one was declared. Anything shaped - an object, a list - goes\n * through fieldValue, the same laying-out the model sections use, so a payload reads the same way\n * wherever it appears and a four-level object does not become one long line.\n *\n * ── The sentence is built here, not frozen when the request was raised ──\n * Eighteen doors write a Korean sentence at issue and the issue snapshots it, so it stands in the\n * language of whoever raised it and an approver reading another language never catches up. Where\n * a door declares `valueTKey`, the sentence is made at reading time instead, out of the values\n * the request did freeze.\n *\n * **A door that has not moved yet draws exactly what it drew before.** That is what lets plant\n * move them one at a time instead of eighteen at once, and it covers a door that moved into a\n * locale nobody has written yet: an empty `defaultValue` means a missing key falls through to the\n * frozen sentence rather than printing `approval.…` on the card.\n */\nfunction slotText(slot: DecisionSlot): unknown {\n const said = sentenceOf(slot)\n\n if (said) {\n return said\n }\n\n const scalar = slot.value !== null && slot.value !== undefined && typeof slot.value !== 'object'\n\n if (scalar && slot.unit) {\n return `${slot.value} ${slot.unit}`\n }\n\n return scalar ? String(slot.value) : fieldValue(slot.value)\n}\n\n/** The sentence this slot declares, when it declares one and the locale has it. */\nfunction sentenceOf(slot: DecisionSlot): string {\n if (!slot.valueTKey) {\n return ''\n }\n\n return String(i18next.t(slot.valueTKey, { ...(slot.params || {}), defaultValue: '' }) || '')\n}\n\n/** Did a person actually write something here. Whitespace is not words. */\nfunction hasWords(slot: DecisionSlot): boolean {\n return typeof slot.value === 'string' ? slot.value.trim().length > 0 : slot.found && slot.value != null\n}\n\n/*\n * The decision, drawn from the activity's declaration.\n *\n * The order is the declaration's and the weight descends with it: what is being asked reads\n * first at title size, then what it is about, then the words a person wrote, then what changes\n * on approval, and last why it came up at all.\n */\nexport const DecisionContentStyles = css`\n section[decision] .headline {\n font-size: var(--ui-t-headline, 19px);\n font-weight: 600;\n line-height: 1.35;\n color: var(--ui-ink, #17242c);\n word-break: keep-all;\n }\n\n section[decision] .subject {\n margin-top: 3px;\n font-family: var(--ui-mono, ui-monospace, Menlo, monospace);\n font-size: var(--ui-t-body, 13px);\n color: var(--ui-muted, #57676f);\n }\n\n section[decision] .block {\n margin-top: 14px;\n }\n\n section[decision] .block > .label {\n margin-bottom: 4px;\n font-size: var(--ui-t-small, 11.5px);\n color: var(--ui-muted, #57676f);\n }\n\n /* What a person wrote is set apart, because it is the only part nobody computed. */\n section[decision] .said {\n padding: 9px 11px;\n border-left: 3px solid var(--ui-line, #d5dce0);\n background: var(--ui-line-soft, #f2f5f7);\n color: var(--ui-ink, #17242c);\n word-break: break-word;\n }\n\n section[decision] .none {\n color: var(--ui-faint, #8a959c);\n }\n\n section[decision] .consequence {\n margin-top: 8px;\n padding: 9px 11px;\n border: 1px solid var(--ui-line, #d5dce0);\n border-radius: var(--ui-r-small, 6px);\n }\n\n section[decision] .consequence > .label {\n margin-bottom: 3px;\n font-size: var(--ui-t-small, 11.5px);\n color: var(--ui-muted, #57676f);\n }\n\n /*\n * Whether approving can be undone reads as the frame around the decision, not as one of its\n * consequences. Among them it carries the same weight as \"four orders get pushed back\", and\n * on an approval that moves equipment it is the heaviest line on the screen.\n */\n section[decision] .reversibility {\n display: flex;\n align-items: center;\n gap: 6px;\n\n margin-top: 12px;\n padding: 8px 11px;\n border-radius: var(--ui-r-small, 6px);\n\n background: var(--ui-line-soft, #f2f5f7);\n color: var(--ui-muted, #57676f);\n font-size: var(--ui-t-small, 11.5px);\n }\n\n section[decision] .reversibility[irreversible] {\n background: var(--md-sys-color-error-container, #ffdad6);\n color: var(--md-sys-color-on-error-container, #410002);\n font-weight: 600;\n }\n\n section[decision] .reversibility md-icon {\n font-size: 1.15em;\n }\n\n /*\n * What the decision was made from. Set flatter than the consequences - it is the record the\n * approver checks, not something the approval brings about.\n */\n section[decision] .evidence {\n margin-top: 8px;\n padding: 7px 0 7px 11px;\n border-left: 2px solid var(--ui-line, #d5dce0);\n }\n\n section[decision] .evidence > .label {\n margin-bottom: 2px;\n font-size: var(--ui-t-small, 11.5px);\n color: var(--ui-muted, #57676f);\n }\n\n /*\n * What is true right now sits apart from what the approval would change. Sharing the box the\n * consequences use would say the approval causes these readings.\n */\n section[decision] .current-state {\n margin-top: 14px;\n padding: 9px 11px;\n border: 1px dashed var(--ui-line, #d5dce0);\n border-radius: var(--ui-r-small, 6px);\n }\n\n section[decision] .current-state > .label {\n margin-bottom: 3px;\n font-size: var(--ui-t-small, 11.5px);\n color: var(--ui-muted, #57676f);\n }\n`\n"]}
|
|
1
|
+
{"version":3,"file":"decision-content.js","sourceRoot":"","sources":["../../client/components/decision-content.ts"],"names":[],"mappings":"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","sourcesContent":["import '@material/web/icon/icon.js'\n\nimport { css, html, nothing, TemplateResult } from 'lit'\nimport { i18next } from '@operato/i18n'\nimport { entity360KindOf, entity360Name } from '@operato/layout'\n\nimport { declaredLabel, fieldValue } from './activity-fields.js'\nimport {\n COMPENSABLE,\n DecisionSlot,\n decisionDrawable,\n decisionSlots,\n reversibilityIsMalformed,\n reversibilityOf,\n slotOfRole,\n slotsOfRole\n} from './decision-slots.js'\n\n/**\n * The decision an activity declared, drawn the one way every screen draws it.\n *\n * The approval screen drew it and the task screen did not. An activity whose model is all hidden -\n * the expenditure request carries its payee and lines only for its decisionKeys - then showed the\n * approver what was asked and showed the person who asked an empty box. Both read the same\n * declaration and the same input, so one drawing serves both.\n */\n\n/**\n * The fields a page asks for to draw the decision - every field renderDecision reads.\n *\n * `name` is the label when the translation `tKey` names is missing (decisionLabel), and `valueTKey` with `params`\n * builds the value sentence at reading time (slotText). Leaving them out drew the sentence frozen\n * at issue, in the language of whoever raised it, with nothing to say a field was missing.\n */\nexport const DecisionKeysFields = `decisionKeys {\n role\n inputPath\n name\n tKey\n valueTKey\n params\n unit\n}`\n\n/**\n * The decision, or `nothing` when the activity declared none or none of it is in this input.\n *\n * Returning nothing is how a page knows to fall back to the model. An activity with no\n * decisionKeys draws exactly what it drew before.\n *\n * A slot whose path led nowhere is skipped rather than drawn empty. Older instances of an activity\n * predate a field the declaration names and an empty bar on the screen would read as \"there is no\n * reason\" when the truth is that this record has no such value. What cannot be shown is left out;\n * what is shown is only what the payload actually carries.\n *\n * `reason` is the exception. Missing and blank mean the same thing to whoever is reading - nobody\n * wrote one - so both draw the grey line rather than disappearing. A reason that silently vanishes\n * would let an approver assume it was never asked for.\n */\nexport function renderDecision(decisionKeys: any, input: any): TemplateResult | typeof nothing {\n const slots = decisionSlots(decisionKeys, input)\n\n if (!decisionDrawable(slots)) {\n return nothing\n }\n\n const headline = slotOfRole(slots, 'headline')\n const subject = slotOfRole(slots, 'subject')\n const reason = slotOfRole(slots, 'reason')\n const consequences = slotsOfRole(slots, 'consequence').filter(slot => slot.found)\n const evidence = slotsOfRole(slots, 'evidence').filter(slot => slot.found)\n const currentState = slotOfRole(slots, 'currentState')\n const reversibility = slotOfRole(slots, 'reversibility')\n\n return html`\n <section decision>\n ${headline?.found ? html`<div class=\"headline\">${slotText(headline)}</div>` : ''}\n ${subject?.found ? html`<div class=\"subject\">${slotText(subject)}</div>` : ''}\n ${\n reason\n ? html`\n <div class=\"block\">\n <div class=\"label\">${i18next.t('field.reason')}</div>\n <div class=\"said ${hasWords(reason) ? '' : 'none'}\">\n ${hasWords(reason) ? slotText(reason) : i18next.t('text.no-reason-given')}\n </div>\n </div>\n `\n : ''\n }\n ${renderReversibility(reversibility)}\n ${\n evidence.length\n ? html`\n <div class=\"block\">\n <div class=\"label\">${i18next.t('label.what-it-was-judged-from')}</div>\n ${evidence.map(\n slot => html`\n <div class=\"evidence\">\n ${decisionLabel(slot) ? html`<div class=\"label\">${decisionLabel(slot)}</div>` : ''}\n <div>${slotText(slot)}</div>\n </div>\n `\n )}\n </div>\n `\n : ''\n }\n ${\n currentState?.found\n ? html`\n <div class=\"current-state\">\n <div class=\"label\">${decisionLabel(currentState) || i18next.t('label.current-state')}</div>\n <div>${slotText(currentState)}</div>\n </div>\n `\n : ''\n }\n ${\n consequences.length\n ? html`\n <div class=\"block\">\n <div class=\"label\">${i18next.t('label.what-changes')}</div>\n ${consequences.map(\n slot => html`\n <div class=\"consequence\">\n ${decisionLabel(slot) ? html`<div class=\"label\">${decisionLabel(slot)}</div>` : ''}\n <div>${slotText(slot)}</div>\n </div>\n `\n )}\n </div>\n `\n : ''\n }\n </section>\n `\n}\n\n/**\n * A slot's own label - only where the declaration names one with `tKey`.\n *\n * A decision key's `name` is the developer's note (\"Never shown on a screen\", ActivityDecisionKeyItem),\n * and without `tKey` the screen shows no label. declaredLabel falls back to `name` whenever `tKey` is\n * absent - right for a search key, whose name is its column, and wrong here: asking for `name` put\n * \"what approving does\" under 「승인하면 달라지는 것」 on a Korean screen (2026-10-16). The fallback\n * stays for a declared key whose translation is missing.\n */\nfunction decisionLabel(slot: DecisionSlot): string {\n return slot.tKey ? declaredLabel(slot) : ''\n}\n\n/**\n * Whether approving can be undone, drawn as the frame around the decision.\n *\n * Only an explicit true or false draws. Anything else - the path led nowhere, or the value is not\n * a boolean - draws nothing, because saying \"this can be undone\" on a screen that does not know is\n * the one mistake this line must never make.\n *\n * This is not rejectionIsFinal. That one says whether **rejecting** ends the case for good; this\n * says whether **approving** can be taken back. The twin actuation carries both, which is exactly\n * why they must not share a sentence.\n */\nfunction renderReversibility(slot?: DecisionSlot) {\n const said = reversibilityOf(slot)\n\n if (!said) {\n if (reversibilityIsMalformed(slot)) {\n /*\n * Declared, and the value is there, but not the shape this role takes - a bare sentence\n * where { reversible, caveat } belongs. Nothing is drawn, because this side cannot tell\n * which way it goes; the log is so a developer does not have to find it by hand, which is\n * how it was found the first time.\n */\n console.error(`[worklist] reversibility at \"${slot?.inputPath}\" is not { reversible, caveat } — nothing drawn`)\n }\n\n return ''\n }\n\n /*\n * The module's own sentence when it wrote one. 「버린 자재는 돌아오지 않습니다」 says why, which\n * the plain wording cannot; the boolean beside it is what decides how heavily this is drawn.\n */\n return html`\n <div class=\"reversibility\" ?irreversible=${!said.reversible}>\n <md-icon>${said.kind === COMPENSABLE ? 'history' : said.reversible ? 'undo' : 'lock'}</md-icon>\n <span\n >${\n said.caveat || (said.kind === COMPENSABLE\n ? i18next.t('text.approval-is-compensable', { defaultValue: 'The original decision remains. A subsequent corrective action is required.' })\n : i18next.t(said.reversible ? 'text.approval-is-reversible' : 'text.approval-is-irreversible'))\n }</span\n >\n </div>\n `\n}\n\n/**\n * One slot's value as something to read.\n *\n * A scalar prints with its unit when one was declared. Anything shaped - an object, a list - goes\n * through fieldValue, the same laying-out the model sections use, so a payload reads the same way\n * wherever it appears and a four-level object does not become one long line.\n *\n * ── The sentence is built here, not frozen when the request was raised ──\n * Eighteen doors write a Korean sentence at issue and the issue snapshots it, so it stands in the\n * language of whoever raised it and an approver reading another language never catches up. Where\n * a door declares `valueTKey`, the sentence is made at reading time instead, out of the values\n * the request did freeze.\n *\n * **A door that has not moved yet draws exactly what it drew before.** That is what lets plant\n * move them one at a time instead of eighteen at once, and it covers a door that moved into a\n * locale nobody has written yet: an empty `defaultValue` means a missing key falls through to the\n * frozen sentence rather than printing `approval.…` on the card.\n */\nfunction slotText(slot: DecisionSlot): unknown {\n const said = sentenceOf(slot)\n\n if (said) {\n return said\n }\n\n /*\n * A value that names what it is - `{ __typename, id, name }` - is drawn as its name, a link to its\n * 360 (ADR-0067 decision 1: an entity's name opens its 360). The counterparty an expenditure pays\n * opens the counterparty 360; a person opens the person 360. A kind nobody registered stays text.\n */\n if (slot.value && typeof slot.value === 'object' && !Array.isArray(slot.value) && entity360KindOf(slot.value)) {\n return entity360Name(slot.value)\n }\n\n const scalar = slot.value !== null && slot.value !== undefined && typeof slot.value !== 'object'\n\n if (scalar && slot.unit) {\n return `${slot.value} ${slot.unit}`\n }\n\n return scalar ? String(slot.value) : fieldValue(slot.value)\n}\n\n/** The sentence this slot declares, when it declares one and the locale has it. */\nfunction sentenceOf(slot: DecisionSlot): string {\n if (!slot.valueTKey) {\n return ''\n }\n\n return String(i18next.t(slot.valueTKey, { ...(slot.params || {}), defaultValue: '' }) || '')\n}\n\n/** Did a person actually write something here. Whitespace is not words. */\nfunction hasWords(slot: DecisionSlot): boolean {\n return typeof slot.value === 'string' ? slot.value.trim().length > 0 : slot.found && slot.value != null\n}\n\n/*\n * The decision, drawn from the activity's declaration.\n *\n * The order is the declaration's and the weight descends with it: what is being asked reads\n * first at title size, then what it is about, then the words a person wrote, then what changes\n * on approval, and last why it came up at all.\n */\nexport const DecisionContentStyles = css`\n section[decision] .headline {\n font-size: var(--ui-t-headline, 19px);\n font-weight: 600;\n line-height: 1.35;\n color: var(--ui-ink, #17242c);\n word-break: keep-all;\n }\n\n section[decision] .subject {\n margin-top: 3px;\n font-family: var(--ui-mono, ui-monospace, Menlo, monospace);\n font-size: var(--ui-t-body, 13px);\n color: var(--ui-muted, #57676f);\n }\n\n section[decision] .block {\n margin-top: 14px;\n }\n\n section[decision] .block > .label {\n margin-bottom: 4px;\n font-size: var(--ui-t-small, 11.5px);\n color: var(--ui-muted, #57676f);\n }\n\n /* What a person wrote is set apart, because it is the only part nobody computed. */\n section[decision] .said {\n padding: 9px 11px;\n border-left: 3px solid var(--ui-line, #d5dce0);\n background: var(--ui-line-soft, #f2f5f7);\n color: var(--ui-ink, #17242c);\n word-break: break-word;\n }\n\n section[decision] .none {\n color: var(--ui-faint, #8a959c);\n }\n\n section[decision] .consequence {\n margin-top: 8px;\n padding: 9px 11px;\n border: 1px solid var(--ui-line, #d5dce0);\n border-radius: var(--ui-r-small, 6px);\n }\n\n section[decision] .consequence > .label {\n margin-bottom: 3px;\n font-size: var(--ui-t-small, 11.5px);\n color: var(--ui-muted, #57676f);\n }\n\n /*\n * Whether approving can be undone reads as the frame around the decision, not as one of its\n * consequences. Among them it carries the same weight as \"four orders get pushed back\", and\n * on an approval that moves equipment it is the heaviest line on the screen.\n */\n section[decision] .reversibility {\n display: flex;\n align-items: center;\n gap: 6px;\n\n margin-top: 12px;\n padding: 8px 11px;\n border-radius: var(--ui-r-small, 6px);\n\n background: var(--ui-line-soft, #f2f5f7);\n color: var(--ui-muted, #57676f);\n font-size: var(--ui-t-small, 11.5px);\n }\n\n section[decision] .reversibility[irreversible] {\n background: var(--md-sys-color-error-container, #ffdad6);\n color: var(--md-sys-color-on-error-container, #410002);\n font-weight: 600;\n }\n\n section[decision] .reversibility md-icon {\n font-size: 1.15em;\n }\n\n /*\n * What the decision was made from. Set flatter than the consequences - it is the record the\n * approver checks, not something the approval brings about.\n */\n section[decision] .evidence {\n margin-top: 8px;\n padding: 7px 0 7px 11px;\n border-left: 2px solid var(--ui-line, #d5dce0);\n }\n\n section[decision] .evidence > .label {\n margin-bottom: 2px;\n font-size: var(--ui-t-small, 11.5px);\n color: var(--ui-muted, #57676f);\n }\n\n /*\n * What is true right now sits apart from what the approval would change. Sharing the box the\n * consequences use would say the approval causes these readings.\n */\n section[decision] .current-state {\n margin-top: 14px;\n padding: 9px 11px;\n border: 1px dashed var(--ui-line, #d5dce0);\n border-radius: var(--ui-r-small, 6px);\n }\n\n section[decision] .current-state > .label {\n margin-bottom: 3px;\n font-size: var(--ui-t-small, 11.5px);\n color: var(--ui-muted, #57676f);\n }\n`\n"]}
|
|
@@ -17,11 +17,19 @@ export declare class ActivityInstanceView extends ActivityInstanceView_base {
|
|
|
17
17
|
* decision, every model field being hidden. The declaration goes first and the given values are
|
|
18
18
|
* the fallback, as on the task screen (thread-sections).
|
|
19
19
|
*/
|
|
20
|
-
renderRequest(): import("lit-html").TemplateResult
|
|
20
|
+
renderRequest(): typeof nothing | import("lit-html").TemplateResult;
|
|
21
21
|
renderActivityThread(activityInstance: ActivityInstance, activityThread: ActivityThread): import("lit-html").TemplateResult<1>;
|
|
22
22
|
renderActivityApproval(activityApproval: ActivityApproval): import("lit-html").TemplateResult<1>;
|
|
23
23
|
renderSearchKeys(): import("lit-html").TemplateResult<1>;
|
|
24
|
-
|
|
24
|
+
/**
|
|
25
|
+
* What the assignee wrote - the fields the model declares as output and does not hide.
|
|
26
|
+
*
|
|
27
|
+
* This listed every model field by its developer name, hidden ones too, with the value read from the
|
|
28
|
+
* output: an expenditure request showed requestId · month · requester · payee · lines, all empty,
|
|
29
|
+
* under 「산출물」. 상신함 opens this view for anyone who put something up, so it draws what the task
|
|
30
|
+
* screen draws, and nothing when the activity has nothing to write.
|
|
31
|
+
*/
|
|
32
|
+
renderWritten(output: any): import("lit-html").TemplateResult<1> | typeof nothing;
|
|
25
33
|
updated(changes: any): void;
|
|
26
34
|
fetchActivityInstance(): Promise<void>;
|
|
27
35
|
}
|
|
@@ -6,7 +6,7 @@ import { customElement, property, state } from 'lit/decorators.js';
|
|
|
6
6
|
import { client } from '@operato/graphql';
|
|
7
7
|
import { i18next, localize } from '@operato/i18n';
|
|
8
8
|
import { ScrollbarStyles } from '@operato/styles';
|
|
9
|
-
import { ActivityFieldsStyles, declaredLabel, inputSpecOf, renderGiven } from '../../components/activity-fields.js';
|
|
9
|
+
import { ActivityFieldsStyles, declaredLabel, inputSpecOf, outputSpecOf, renderGiven } from '../../components/activity-fields.js';
|
|
10
10
|
import { DecisionContentStyles, DecisionKeysFields, renderDecision } from '../../components/decision-content.js';
|
|
11
11
|
import { WorklistStateColors } from '../../components/state-ribon.js';
|
|
12
12
|
import { ActivityInstance } from '../../types/activity-instance.js';
|
|
@@ -295,10 +295,7 @@ let ActivityInstanceView = class ActivityInstanceView extends localize(i18next)(
|
|
|
295
295
|
<div><label>${i18next.t('field.round')}</label> ${round}</div>
|
|
296
296
|
</div>
|
|
297
297
|
|
|
298
|
-
|
|
299
|
-
<span subtitle>${i18next.t('field.artifact')}</span>
|
|
300
|
-
${this.renderInOut(output || {})}
|
|
301
|
-
</div>
|
|
298
|
+
${this.renderWritten(output || {})}
|
|
302
299
|
<div timeline>
|
|
303
300
|
<span subtitle>${i18next.t('label.timeline')}</span>
|
|
304
301
|
|
|
@@ -348,23 +345,22 @@ let ActivityInstanceView = class ActivityInstanceView extends localize(i18next)(
|
|
|
348
345
|
</table>
|
|
349
346
|
`;
|
|
350
347
|
}
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
`;
|
|
348
|
+
/**
|
|
349
|
+
* What the assignee wrote - the fields the model declares as output and does not hide.
|
|
350
|
+
*
|
|
351
|
+
* This listed every model field by its developer name, hidden ones too, with the value read from the
|
|
352
|
+
* output: an expenditure request showed requestId · month · requester · payee · lines, all empty,
|
|
353
|
+
* under 「산출물」. 상신함 opens this view for anyone who put something up, so it draws what the task
|
|
354
|
+
* screen draws, and nothing when the activity has nothing to write.
|
|
355
|
+
*/
|
|
356
|
+
renderWritten(output) {
|
|
357
|
+
const written = outputSpecOf(this.activityInstance.activity?.model);
|
|
358
|
+
return written.length
|
|
359
|
+
? html `<div>
|
|
360
|
+
<span subtitle>${i18next.t('field.artifact')}</span>
|
|
361
|
+
${renderGiven(written, output)}
|
|
362
|
+
</div>`
|
|
363
|
+
: nothing;
|
|
368
364
|
}
|
|
369
365
|
updated(changes) {
|
|
370
366
|
if (changes.has('activityInstanceId')) {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"activity-instance-view.js","sourceRoot":"","sources":["../../../client/pages/activity-instance/activity-instance-view.ts"],"names":[],"mappings":"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","sourcesContent":["import '@things-factory/organization/dist-client/component/approval-line-view.js'\n\nimport gql from 'graphql-tag'\nimport { css, html, LitElement, nothing } from 'lit'\nimport { customElement, property, query, state } from 'lit/decorators.js'\n\nimport { client } from '@operato/graphql'\nimport { i18next, localize } from '@operato/i18n'\nimport { ScrollbarStyles } from '@operato/styles'\n\nimport { ActivityFieldsStyles, declaredLabel, inputSpecOf, renderGiven } from '../../components/activity-fields.js'\nimport { DecisionContentStyles, DecisionKeysFields, renderDecision } from '../../components/decision-content.js'\nimport { WorklistStateColors } from '../../components/state-ribon.js'\nimport { ActivityInstance } from '../../types/activity-instance.js'\nimport { ActivityThread } from '../../types/activity-thread.js'\nimport { ActivityApproval } from '../../types/activity-approval.js'\nimport { entity360Name } from '@operato/layout'\n\nfunction getSafeFormatter(locale: string, options: Intl.DateTimeFormatOptions): Intl.DateTimeFormat {\n try {\n const safeLocale = locale || 'en-US'\n return new Intl.DateTimeFormat(safeLocale, options)\n } catch (e) {\n console.warn(`Invalid locale or options provided: ${locale}, falling back to default en-US.`, e)\n return new Intl.DateTimeFormat('en-US', options)\n }\n}\n\nconst formatter = getSafeFormatter(navigator.language, { dateStyle: 'full', timeStyle: 'short' })\n@customElement('activity-instance-view')\nexport class ActivityInstanceView extends localize(i18next)(LitElement) {\n static styles = [\n ScrollbarStyles,\n WorklistStateColors,\n ActivityFieldsStyles,\n DecisionContentStyles,\n css`\n :host {\n display: flex;\n overflow: auto;\n font-size: var(--fontsize-default);\n }\n [instance-container] {\n flex: 1;\n background-color: var(--md-sys-color-background);\n border-right: var(--border-dim-color);\n padding: var(--spacing-large);\n color: var(--md-sys-color-secondary);\n }\n [thread-container] {\n flex: 2;\n padding: var(--spacing-large);\n }\n [instance-container] div {\n margin-bottom: var(--spacing-medium);\n padding-bottom: var(--spacing-medium);\n border-bottom: var(--border-dim-color);\n }\n /* The state speaks through the icon's colour on a quiet disc, as in the ribbons - a filled disc\n under an on-primary icon read under 3:1 for three states. */\n [header] md-icon {\n background-color: var(--md-sys-color-surface-container-high);\n float: left;\n margin-right: var(--spacing-medium);\n padding: var(--spacing-medium);\n border-radius: 50%;\n float: left;\n font-size: 1.8em;\n color: var(--worklist-state-color, var(--ui-muted, #57676f));\n }\n [header] strong {\n display: block;\n font: bold 22px / 1.1 var(--theme-font);\n }\n [header] {\n overflow: hidden;\n font-size: var(--fontsize-small);\n }\n [instance-container] div label {\n display: inline-block;\n margin-right: var(--spacing-medium);\n min-width: 50px;\n }\n [issuer] md-icon {\n opacity: 0.5;\n position: relative;\n top: 4px;\n font-size: 20px;\n }\n span[status] {\n width: 15px;\n height: 15px;\n position: relative;\n top: 2px;\n background-color: var(--worklist-state-color, var(--ui-muted, #57676f));\n display: inline-block;\n margin-right: var(--spacing-small);\n border-radius: 50%;\n }\n [thread-container] table {\n width: 100%;\n border-collapse: collapse;\n }\n [thread-container] th {\n color: var(--md-sys-color-on-primary-container);\n background-color: var(--md-sys-color-primary-container);\n border-top: var(--grid-header-top-border);\n border-bottom: var(--grid-header-bottom-border);\n padding: var(--grid-header-padding);\n text-overflow: ellipsis;\n font: var(--grid-header-font);\n }\n [thread-container] td {\n padding: var(--spacing-small);\n border-bottom: var(--grid-record-border-bottom);\n }\n [assignee] * {\n vertical-align: middle;\n }\n [assignee] md-icon {\n opacity: 0.5;\n }\n [subtitle] {\n display: block;\n margin: var(--spacing-large) 0 var(--spacing-small) 0;\n padding: var(--spacing-small) var(--spacing-medium);\n color: var(--md-sys-color-on-surface);\n background-color: var(--md-sys-color-surface-variant);\n font: bold 16px var(--theme-font);\n border: 2px solid var(--md-sys-color-outline);\n border-radius: 999px;\n }\n [timeline] ol {\n list-style: none;\n margin: 0;\n padding: 0;\n }\n [timeline] li {\n display: flex;\n }\n [timeline] [info] {\n color: var(--md-sys-color-on-surface);\n background: var(--md-sys-color-surface-variant);\n\n flex: 1;\n }\n [timeline] [date] {\n opacity: 0.7;\n width: 130px;\n font-size: var(--fontsize-small);\n }\n [timeline] [info] strong {\n float: right;\n }\n [timeline] [status] {\n margin: 0 var(--spacing-small);\n display: block;\n border-radius: 50%;\n width: 12px;\n height: 12px;\n position: relative;\n top: 3px;\n /* The ring separates the dot from the line behind it, so it is the page's own colour. */\n border: 2px solid var(--md-sys-color-surface);\n background-color: var(--worklist-state-color, var(--ui-muted, #57676f));\n }\n [timeline] [status]::before {\n content: '';\n height: 60px;\n width: 2px;\n display: block;\n position: relative;\n margin-left: 5px;\n background-color: var(--worklist-state-color, var(--ui-muted, #57676f));\n opacity: 0.2;\n }\n [timeline] [info] md-icon {\n position: relative;\n top: 3px;\n font-size: var(--fontsize-large);\n }\n [timeline] [info] p {\n /* A fixed light grey under text that follows the theme was light-on-light in the dark theme. */\n background-color: var(--md-sys-color-surface-container);\n color: var(--md-sys-color-on-surface);\n margin: var(--spacing-small) 0 var(--spacing-medium) 0;\n padding: var(--spacing-small) var(--spacing-medium);\n border-radius: var(--border-radius);\n font-size: var(--fontsize-small);\n text-align: justify;\n }\n [timeline] [info] p::before {\n content: '';\n float: right;\n margin-top: -10px;\n margin-right: 20px;\n border: 7px solid transparent;\n border-bottom-color: var(--md-sys-color-surface-container);\n border-top: 0;\n }\n [thread] div {\n border-bottom: var(--border-dim-color);\n padding: var(--spacing-small);\n text-align: right;\n overflow: hidden;\n }\n [thread] div label {\n float: left;\n width: 25%;\n text-align: left;\n }\n `\n ]\n\n @property({\n type: String,\n attribute: 'activity-instance-id'\n })\n activityInstanceId?: string\n\n @state() activityInstance?: ActivityInstance\n\n render() {\n if (!this.activityInstance) {\n return html`<div>no activity instance info.</div>`\n }\n\n const { id, name, description, state, issuer, assignedAt, startedAt, activityThreads, terminatedAt, updatedAt } =\n this.activityInstance\n\n return html`\n <div instance-container>\n <div header>\n <md-icon>description</md-icon>\n <strong>${name}</strong>\n ${description}\n </div>\n\n <div>\n <label>${i18next.t('label.status')}</label>\n <span status></span>\n <strong>${i18next.t('label.activity-state-' + state)}</strong>\n </div>\n\n <div issuer>\n <label>${i18next.t('field.issuer')}</label>\n <md-icon>account_circle</md-icon>\n <strong>${entity360Name(issuer)}</strong>\n </div>\n <div>\n <label>${i18next.t('field.assigned-at')}</label>${assignedAt && formatter.format(new Date(assignedAt))}\n </div>\n <div><label>${i18next.t('field.started-at')}</label>${startedAt && formatter.format(new Date(startedAt))}</div>\n <div><label>${i18next.t('field.updated-at')}</label>${updatedAt && formatter.format(new Date(updatedAt))}</div>\n <div>\n <label>${i18next.t('field.terminated-at')}</label>${terminatedAt && formatter.format(new Date(terminatedAt))}\n </div>\n </div>\n <div thread-container>\n ${this.renderRequest()}\n ${activityThreads?.map(activityThread => this.renderActivityThread(this.activityInstance!, activityThread))}\n </div>\n `\n }\n\n /**\n * What was asked - the same drawing the task and approval screens use.\n *\n * 상신함 opens what I put up here. Without this the view showed the name, the state and the\n * history, and not the request itself: an expenditure request's payee and lines live only in its\n * decision, every model field being hidden. The declaration goes first and the given values are\n * the fallback, as on the task screen (thread-sections).\n */\n renderRequest() {\n const { activity, input } = this.activityInstance!\n const decision = renderDecision(activity?.decisionKeys, input)\n\n if (decision !== nothing) {\n return decision\n }\n\n const given = inputSpecOf(activity?.model)\n\n return given.length\n ? html`<section readonly>\n <h2>${i18next.t('label.activity-input')}</h2>\n ${renderGiven(given, input)}\n </section>`\n : nothing\n }\n\n renderActivityThread(activityInstance: ActivityInstance, activityThread: ActivityThread) {\n const {\n state,\n assignee,\n output,\n round,\n activityApprovals = [],\n assignedAt,\n startedAt,\n terminatedAt\n } = activityThread\n const { approvalLine } = activityInstance!\n const { name, email } = assignee || {}\n const approvals = activityApprovals.sort((a, b) =>\n a.round < b.round ? 1 : a.round > b.round ? -1 : a.order! < b.order! ? 1 : -1\n )\n const current = approvals[0]?.round == round ? approvals[0].order : -1\n\n return html`\n <div assignee>\n <md-icon>account_circle</md-icon>\n <strong>${name}</strong>\n </div>\n\n <div thread>\n <span subtitle>${i18next.t('label.thread-basics')}</span>\n <div>\n <label>${i18next.t('label.status')}</label>\n <span status></span>\n <strong>${i18next.t('label.activity-state-' + state)}</strong>\n </div>\n <div>\n <label>${i18next.t('field.assigned-at')}</label> ${assignedAt && formatter.format(new Date(assignedAt))}\n </div>\n <div><label>${i18next.t('field.started-at')}</label> ${startedAt && formatter.format(new Date(startedAt))}</div>\n <div>\n <label>${i18next.t('field.terminated-at')}</label> ${terminatedAt && formatter.format(new Date(terminatedAt))}\n </div>\n <div><label>${i18next.t('field.round')}</label> ${round}</div>\n </div>\n\n <div>\n <span subtitle>${i18next.t('field.artifact')}</span>\n ${this.renderInOut(output || {})}\n </div>\n <div timeline>\n <span subtitle>${i18next.t('label.timeline')}</span>\n\n <div>\n ${approvalLine\n ? html`<approval-line-view .model=${approvalLine} .current=${current}></approval-line-view>`\n : html``}\n </div>\n\n <ol>\n ${approvals.map(approval => this.renderActivityApproval(approval))}\n </ol>\n </div>\n `\n }\n\n renderActivityApproval(activityApproval: ActivityApproval) {\n const { judgment, approver, comment, round, order, createdAt, terminatedAt } = activityApproval\n const { name, email } = approver || {}\n\n return html`\n <li>\n <span date>${formatter.format(new Date(terminatedAt || createdAt!))}</span>\n <span status></span>\n <span info>\n ${i18next.t('label.activity-state-' + (judgment || 'started'))}\n <strong><md-icon>account_circle</md-icon>${name}</strong>\n <p>${comment}</p>\n </span>\n </li>\n `\n }\n\n renderSearchKeys() {\n const { activity } = this.activityInstance!\n const { searchKeys = [] } = activity! || {}\n\n return html`\n <table>\n <tr>\n <th>${i18next.t('label.name')}</th>\n <th>${i18next.t('label.value')}</th>\n </tr>\n\n ${searchKeys?.map(\n (item, index) => html`\n <tr>\n <td>${declaredLabel(item)}</td>\n <td>${this.activityInstance![`key0${index + 1}`]}</td>\n </tr>\n `\n )}\n </table>\n `\n }\n\n renderInOut(data) {\n const { activity } = this.activityInstance!\n const { model } = activity || {}\n\n return html`\n <table>\n <tr>\n <th>${i18next.t('label.name')}</th>\n <th>${i18next.t('label.value')}</th>\n </tr>\n ${model?.map(\n item => html`\n <tr>\n <td>${item.name}</td>\n <td>${item.tag ? data[item.tag] : ''}</td>\n </tr>\n `\n )}\n </table>\n `\n }\n\n updated(changes) {\n if (changes.has('activityInstanceId')) {\n this.fetchActivityInstance()\n }\n }\n\n async fetchActivityInstance() {\n const id = this.activityInstanceId\n\n const response = await client.query({\n query: gql`\n query ($id: String!) {\n activityInstance(id: $id) {\n id\n name\n description\n state\n key01\n key02\n key03\n key04\n key05\n input\n output\n issuer {\n id\n name\n email\n }\n starter {\n name\n email\n }\n activity {\n id\n name\n description\n searchKeys {\n name\n description\n inputKey\n tKey\n }\n ${DecisionKeysFields}\n model {\n name\n description\n active\n tag\n inout\n type\n unit\n options\n quantifier\n spec\n hidden\n }\n }\n approvalLine {\n type\n participation\n notifyAfter\n value\n approver {\n id\n name\n description\n controlNo\n }\n }\n activityThreads {\n state\n transaction\n output\n assignee {\n id\n name\n email\n }\n round\n activityApprovals {\n round\n order\n approver {\n id\n name\n email\n }\n judgment\n comment\n createdAt\n terminatedAt\n }\n assignedAt\n startedAt\n terminatedAt\n }\n updater {\n id\n name\n }\n assignedAt\n startedAt\n terminatedAt\n updatedAt\n }\n }\n `,\n variables: {\n id\n }\n })\n\n this.activityInstance = response.data.activityInstance\n this.setAttribute('state', this.activityInstance?.state || '')\n }\n}\n"]}
|
|
1
|
+
{"version":3,"file":"activity-instance-view.js","sourceRoot":"","sources":["../../../client/pages/activity-instance/activity-instance-view.ts"],"names":[],"mappings":"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","sourcesContent":["import '@things-factory/organization/dist-client/component/approval-line-view.js'\n\nimport gql from 'graphql-tag'\nimport { css, html, LitElement, nothing } from 'lit'\nimport { customElement, property, query, state } from 'lit/decorators.js'\n\nimport { client } from '@operato/graphql'\nimport { i18next, localize } from '@operato/i18n'\nimport { ScrollbarStyles } from '@operato/styles'\n\nimport { ActivityFieldsStyles, declaredLabel, inputSpecOf, outputSpecOf, renderGiven } from '../../components/activity-fields.js'\nimport { DecisionContentStyles, DecisionKeysFields, renderDecision } from '../../components/decision-content.js'\nimport { WorklistStateColors } from '../../components/state-ribon.js'\nimport { ActivityInstance } from '../../types/activity-instance.js'\nimport { ActivityThread } from '../../types/activity-thread.js'\nimport { ActivityApproval } from '../../types/activity-approval.js'\nimport { entity360Name } from '@operato/layout'\n\nfunction getSafeFormatter(locale: string, options: Intl.DateTimeFormatOptions): Intl.DateTimeFormat {\n try {\n const safeLocale = locale || 'en-US'\n return new Intl.DateTimeFormat(safeLocale, options)\n } catch (e) {\n console.warn(`Invalid locale or options provided: ${locale}, falling back to default en-US.`, e)\n return new Intl.DateTimeFormat('en-US', options)\n }\n}\n\nconst formatter = getSafeFormatter(navigator.language, { dateStyle: 'full', timeStyle: 'short' })\n@customElement('activity-instance-view')\nexport class ActivityInstanceView extends localize(i18next)(LitElement) {\n static styles = [\n ScrollbarStyles,\n WorklistStateColors,\n ActivityFieldsStyles,\n DecisionContentStyles,\n css`\n :host {\n display: flex;\n overflow: auto;\n font-size: var(--fontsize-default);\n }\n [instance-container] {\n flex: 1;\n background-color: var(--md-sys-color-background);\n border-right: var(--border-dim-color);\n padding: var(--spacing-large);\n color: var(--md-sys-color-secondary);\n }\n [thread-container] {\n flex: 2;\n padding: var(--spacing-large);\n }\n [instance-container] div {\n margin-bottom: var(--spacing-medium);\n padding-bottom: var(--spacing-medium);\n border-bottom: var(--border-dim-color);\n }\n /* The state speaks through the icon's colour on a quiet disc, as in the ribbons - a filled disc\n under an on-primary icon read under 3:1 for three states. */\n [header] md-icon {\n background-color: var(--md-sys-color-surface-container-high);\n float: left;\n margin-right: var(--spacing-medium);\n padding: var(--spacing-medium);\n border-radius: 50%;\n float: left;\n font-size: 1.8em;\n color: var(--worklist-state-color, var(--ui-muted, #57676f));\n }\n [header] strong {\n display: block;\n font: bold 22px / 1.1 var(--theme-font);\n }\n [header] {\n overflow: hidden;\n font-size: var(--fontsize-small);\n }\n [instance-container] div label {\n display: inline-block;\n margin-right: var(--spacing-medium);\n min-width: 50px;\n }\n [issuer] md-icon {\n opacity: 0.5;\n position: relative;\n top: 4px;\n font-size: 20px;\n }\n span[status] {\n width: 15px;\n height: 15px;\n position: relative;\n top: 2px;\n background-color: var(--worklist-state-color, var(--ui-muted, #57676f));\n display: inline-block;\n margin-right: var(--spacing-small);\n border-radius: 50%;\n }\n [thread-container] table {\n width: 100%;\n border-collapse: collapse;\n }\n [thread-container] th {\n color: var(--md-sys-color-on-primary-container);\n background-color: var(--md-sys-color-primary-container);\n border-top: var(--grid-header-top-border);\n border-bottom: var(--grid-header-bottom-border);\n padding: var(--grid-header-padding);\n text-overflow: ellipsis;\n font: var(--grid-header-font);\n }\n [thread-container] td {\n padding: var(--spacing-small);\n border-bottom: var(--grid-record-border-bottom);\n }\n [assignee] * {\n vertical-align: middle;\n }\n [assignee] md-icon {\n opacity: 0.5;\n }\n [subtitle] {\n display: block;\n margin: var(--spacing-large) 0 var(--spacing-small) 0;\n padding: var(--spacing-small) var(--spacing-medium);\n color: var(--md-sys-color-on-surface);\n background-color: var(--md-sys-color-surface-variant);\n font: bold 16px var(--theme-font);\n border: 2px solid var(--md-sys-color-outline);\n border-radius: 999px;\n }\n [timeline] ol {\n list-style: none;\n margin: 0;\n padding: 0;\n }\n [timeline] li {\n display: flex;\n }\n [timeline] [info] {\n color: var(--md-sys-color-on-surface);\n background: var(--md-sys-color-surface-variant);\n\n flex: 1;\n }\n [timeline] [date] {\n opacity: 0.7;\n width: 130px;\n font-size: var(--fontsize-small);\n }\n [timeline] [info] strong {\n float: right;\n }\n [timeline] [status] {\n margin: 0 var(--spacing-small);\n display: block;\n border-radius: 50%;\n width: 12px;\n height: 12px;\n position: relative;\n top: 3px;\n /* The ring separates the dot from the line behind it, so it is the page's own colour. */\n border: 2px solid var(--md-sys-color-surface);\n background-color: var(--worklist-state-color, var(--ui-muted, #57676f));\n }\n [timeline] [status]::before {\n content: '';\n height: 60px;\n width: 2px;\n display: block;\n position: relative;\n margin-left: 5px;\n background-color: var(--worklist-state-color, var(--ui-muted, #57676f));\n opacity: 0.2;\n }\n [timeline] [info] md-icon {\n position: relative;\n top: 3px;\n font-size: var(--fontsize-large);\n }\n [timeline] [info] p {\n /* A fixed light grey under text that follows the theme was light-on-light in the dark theme. */\n background-color: var(--md-sys-color-surface-container);\n color: var(--md-sys-color-on-surface);\n margin: var(--spacing-small) 0 var(--spacing-medium) 0;\n padding: var(--spacing-small) var(--spacing-medium);\n border-radius: var(--border-radius);\n font-size: var(--fontsize-small);\n text-align: justify;\n }\n [timeline] [info] p::before {\n content: '';\n float: right;\n margin-top: -10px;\n margin-right: 20px;\n border: 7px solid transparent;\n border-bottom-color: var(--md-sys-color-surface-container);\n border-top: 0;\n }\n [thread] div {\n border-bottom: var(--border-dim-color);\n padding: var(--spacing-small);\n text-align: right;\n overflow: hidden;\n }\n [thread] div label {\n float: left;\n width: 25%;\n text-align: left;\n }\n `\n ]\n\n @property({\n type: String,\n attribute: 'activity-instance-id'\n })\n activityInstanceId?: string\n\n @state() activityInstance?: ActivityInstance\n\n render() {\n if (!this.activityInstance) {\n return html`<div>no activity instance info.</div>`\n }\n\n const { id, name, description, state, issuer, assignedAt, startedAt, activityThreads, terminatedAt, updatedAt } =\n this.activityInstance\n\n return html`\n <div instance-container>\n <div header>\n <md-icon>description</md-icon>\n <strong>${name}</strong>\n ${description}\n </div>\n\n <div>\n <label>${i18next.t('label.status')}</label>\n <span status></span>\n <strong>${i18next.t('label.activity-state-' + state)}</strong>\n </div>\n\n <div issuer>\n <label>${i18next.t('field.issuer')}</label>\n <md-icon>account_circle</md-icon>\n <strong>${entity360Name(issuer)}</strong>\n </div>\n <div>\n <label>${i18next.t('field.assigned-at')}</label>${assignedAt && formatter.format(new Date(assignedAt))}\n </div>\n <div><label>${i18next.t('field.started-at')}</label>${startedAt && formatter.format(new Date(startedAt))}</div>\n <div><label>${i18next.t('field.updated-at')}</label>${updatedAt && formatter.format(new Date(updatedAt))}</div>\n <div>\n <label>${i18next.t('field.terminated-at')}</label>${terminatedAt && formatter.format(new Date(terminatedAt))}\n </div>\n </div>\n <div thread-container>\n ${this.renderRequest()}\n ${activityThreads?.map(activityThread => this.renderActivityThread(this.activityInstance!, activityThread))}\n </div>\n `\n }\n\n /**\n * What was asked - the same drawing the task and approval screens use.\n *\n * 상신함 opens what I put up here. Without this the view showed the name, the state and the\n * history, and not the request itself: an expenditure request's payee and lines live only in its\n * decision, every model field being hidden. The declaration goes first and the given values are\n * the fallback, as on the task screen (thread-sections).\n */\n renderRequest() {\n const { activity, input } = this.activityInstance!\n const decision = renderDecision(activity?.decisionKeys, input)\n\n if (decision !== nothing) {\n return decision\n }\n\n const given = inputSpecOf(activity?.model)\n\n return given.length\n ? html`<section readonly>\n <h2>${i18next.t('label.activity-input')}</h2>\n ${renderGiven(given, input)}\n </section>`\n : nothing\n }\n\n renderActivityThread(activityInstance: ActivityInstance, activityThread: ActivityThread) {\n const {\n state,\n assignee,\n output,\n round,\n activityApprovals = [],\n assignedAt,\n startedAt,\n terminatedAt\n } = activityThread\n const { approvalLine } = activityInstance!\n const { name, email } = assignee || {}\n const approvals = activityApprovals.sort((a, b) =>\n a.round < b.round ? 1 : a.round > b.round ? -1 : a.order! < b.order! ? 1 : -1\n )\n const current = approvals[0]?.round == round ? approvals[0].order : -1\n\n return html`\n <div assignee>\n <md-icon>account_circle</md-icon>\n <strong>${name}</strong>\n </div>\n\n <div thread>\n <span subtitle>${i18next.t('label.thread-basics')}</span>\n <div>\n <label>${i18next.t('label.status')}</label>\n <span status></span>\n <strong>${i18next.t('label.activity-state-' + state)}</strong>\n </div>\n <div>\n <label>${i18next.t('field.assigned-at')}</label> ${assignedAt && formatter.format(new Date(assignedAt))}\n </div>\n <div><label>${i18next.t('field.started-at')}</label> ${startedAt && formatter.format(new Date(startedAt))}</div>\n <div>\n <label>${i18next.t('field.terminated-at')}</label> ${terminatedAt && formatter.format(new Date(terminatedAt))}\n </div>\n <div><label>${i18next.t('field.round')}</label> ${round}</div>\n </div>\n\n ${this.renderWritten(output || {})}\n <div timeline>\n <span subtitle>${i18next.t('label.timeline')}</span>\n\n <div>\n ${approvalLine\n ? html`<approval-line-view .model=${approvalLine} .current=${current}></approval-line-view>`\n : html``}\n </div>\n\n <ol>\n ${approvals.map(approval => this.renderActivityApproval(approval))}\n </ol>\n </div>\n `\n }\n\n renderActivityApproval(activityApproval: ActivityApproval) {\n const { judgment, approver, comment, round, order, createdAt, terminatedAt } = activityApproval\n const { name, email } = approver || {}\n\n return html`\n <li>\n <span date>${formatter.format(new Date(terminatedAt || createdAt!))}</span>\n <span status></span>\n <span info>\n ${i18next.t('label.activity-state-' + (judgment || 'started'))}\n <strong><md-icon>account_circle</md-icon>${name}</strong>\n <p>${comment}</p>\n </span>\n </li>\n `\n }\n\n renderSearchKeys() {\n const { activity } = this.activityInstance!\n const { searchKeys = [] } = activity! || {}\n\n return html`\n <table>\n <tr>\n <th>${i18next.t('label.name')}</th>\n <th>${i18next.t('label.value')}</th>\n </tr>\n\n ${searchKeys?.map(\n (item, index) => html`\n <tr>\n <td>${declaredLabel(item)}</td>\n <td>${this.activityInstance![`key0${index + 1}`]}</td>\n </tr>\n `\n )}\n </table>\n `\n }\n\n /**\n * What the assignee wrote - the fields the model declares as output and does not hide.\n *\n * This listed every model field by its developer name, hidden ones too, with the value read from the\n * output: an expenditure request showed requestId · month · requester · payee · lines, all empty,\n * under 「산출물」. 상신함 opens this view for anyone who put something up, so it draws what the task\n * screen draws, and nothing when the activity has nothing to write.\n */\n renderWritten(output: any) {\n const written = outputSpecOf(this.activityInstance!.activity?.model)\n\n return written.length\n ? html`<div>\n <span subtitle>${i18next.t('field.artifact')}</span>\n ${renderGiven(written, output)}\n </div>`\n : nothing\n }\n\n updated(changes) {\n if (changes.has('activityInstanceId')) {\n this.fetchActivityInstance()\n }\n }\n\n async fetchActivityInstance() {\n const id = this.activityInstanceId\n\n const response = await client.query({\n query: gql`\n query ($id: String!) {\n activityInstance(id: $id) {\n id\n name\n description\n state\n key01\n key02\n key03\n key04\n key05\n input\n output\n issuer {\n id\n name\n email\n }\n starter {\n name\n email\n }\n activity {\n id\n name\n description\n searchKeys {\n name\n description\n inputKey\n tKey\n }\n ${DecisionKeysFields}\n model {\n name\n description\n active\n tag\n inout\n type\n unit\n options\n quantifier\n spec\n hidden\n }\n }\n approvalLine {\n type\n participation\n notifyAfter\n value\n approver {\n id\n name\n description\n controlNo\n }\n }\n activityThreads {\n state\n transaction\n output\n assignee {\n id\n name\n email\n }\n round\n activityApprovals {\n round\n order\n approver {\n id\n name\n email\n }\n judgment\n comment\n createdAt\n terminatedAt\n }\n assignedAt\n startedAt\n terminatedAt\n }\n updater {\n id\n name\n }\n assignedAt\n startedAt\n terminatedAt\n updatedAt\n }\n }\n `,\n variables: {\n id\n }\n })\n\n this.activityInstance = response.data.activityInstance\n this.setAttribute('state', this.activityInstance?.state || '')\n }\n}\n"]}
|
|
@@ -15,6 +15,7 @@ import { PageView } from '@operato/shell';
|
|
|
15
15
|
import { DocumentPageStyles, ScrollbarStyles } from '@operato/styles';
|
|
16
16
|
import { provider } from '@operato/board/board-provider.js';
|
|
17
17
|
import { ActivityFieldsStyles } from '../../components/activity-fields.js';
|
|
18
|
+
import { DecisionKeysFields } from '../../components/decision-content.js';
|
|
18
19
|
const ActivityThreadFetchResult = `\
|
|
19
20
|
{ id
|
|
20
21
|
state
|
|
@@ -50,6 +51,7 @@ const ActivityThreadFetchResult = `\
|
|
|
50
51
|
description
|
|
51
52
|
state
|
|
52
53
|
activity { id
|
|
54
|
+
${DecisionKeysFields}
|
|
53
55
|
model { name
|
|
54
56
|
description
|
|
55
57
|
active
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"activity-thread-view-page.js","sourceRoot":"","sources":["../../../client/pages/activity-thread/activity-thread-view-page.ts"],"names":[],"mappings":"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","sourcesContent":["import '@operato/board/ox-board-viewer.js'\nimport '@operato/list-state/ox-page-state.js'\nimport '../../components/activity-thread-ribon.js'\nimport '../../components/activity-thread-timeline.js'\nimport './activity-thread-view.js'\n\nimport gql from 'graphql-tag'\nimport { css, html, nothing } from 'lit'\nimport { DirectiveResult } from 'lit-html/directive.js'\nimport { unsafeHTML } from 'lit-html/directives/unsafe-html.js'\nimport { customElement, property, query, state } from 'lit/decorators.js'\nimport { keyed } from 'lit/directives/keyed.js'\nimport { client } from '@operato/graphql'\nimport { i18next, localize } from '@operato/i18n'\nimport { PageView } from '@operato/shell'\nimport { DocumentPageStyles, ScrollbarStyles } from '@operato/styles'\nimport { provider } from '@operato/board/board-provider.js'\n\nimport { ActivityFieldsStyles } from '../../components/activity-fields.js'\n\nconst ActivityThreadFetchResult = `\\\n{ id\n state\n dueAt\n assignedAt\n startedAt\n terminatedAt\n assignee { id\n name\n }\n output\n round\n activityApprovals { round\n order\n approver { id name\n }\n judgment\n comment\n createdAt\n updatedAt\n terminatedAt\n }\n activityThreadHistories { transaction\n reason\n updater { id name\n }\n updatedAt\n state\n output\n }\n activityInstance { id\n name\n description\n state\n activity { id\n model { name\n description\n active\n tag\n inout\n type\n unit\n options\n quantifier\n spec\n hidden\n }\n }\n approvalLine { type\n value\n participation\n notifyAfter\n approver { id\n name\n description\n controlNo\n }\n }\n thumbnail\n input\n output\n viewType\n viewSource\n dueAt\n terminatedAt\n terminator { name\n email\n }\n createdAt\n }\n}`\n\nexport const ActivityThreadStatus = {\n Unassigned: 'unassigned',\n Assigned: 'assigned',\n Started: 'started',\n Delegated: 'delegated',\n Rejected: 'rejected',\n Ended: 'ended',\n Aborted: 'aborted'\n}\n\n@customElement('activity-thread-view-page')\nexport class ActivityThreadViewPage extends localize(i18next)(PageView) {\n static styles = [\n /* The frame owns the page shell and the reading column (ADR-0060 decision 8). */\n DocumentPageStyles,\n ScrollbarStyles,\n ActivityFieldsStyles,\n css`\n :host {\n color: var(--ui-ink, #17242c);\n font-size: var(--ui-t-body, 13px);\n }\n\n /* 카드가 담아 주므로 안에 들어오는 화면은 자기 면과 여백을 갖지 않는다. */\n /*\n * ── 줄어들지 않는다 — 줄어들면 본문이 잘린다 (2026-09-07) ──────────────\n * 이 칸은 flex 항목인데 크기를 안 정해 두어 기본값 flex: 0 1 auto 로 있었다. **1 이\n * 줄어든다는 뜻이다** — 세로가 모자라면 브라우저가 이 칸부터 줄인다. 그런데 여기엔\n * overflow: hidden 이 걸려 있어서(카드 모서리를 따라 자르려고) 줄어든 만큼이 **스크롤도\n * 없이 사라진다.**\n *\n * 실측(1400x620): 이 칸이 242px 로 줄었는데 안의 내용은 362px 이었다. 「업무 내용」 절이\n * 276~464 에 있어 대부분이 잘렸고, 잘린 자리 바로 아래에서 타임라인이 시작하니 **타임라인이\n * 본문을 덮은 것처럼** 보였다. 세로가 넉넉한 화면에서는 줄일 일이 없어 드러나지 않았다.\n *\n * 안에 오는 것은 셋 다 문서다(template · custom-element · 생성된 절 카드들). 높이를 정해\n * 주어야 하는 것은 board 뿐이고 board 는 이 칸을 거치지 않는다(activityContent 참조).\n * 문서는 제 높이로 서고, 화면이 모자라면 **페이지 전체가 스크롤한다** — :host 의\n * overflow: auto 가 이미 그 자리다.\n */\n section[hosted] {\n flex: none;\n padding: 0;\n overflow: hidden;\n }\n\n /*\n * 끝난 업무를 읽는 화면은 절이 여럿이라(기본 정보 · 업무 정보 · 수행 결과) 카드를 한 겹 더\n * 두르지 않는다. 절들이 곧 카드다.\n */\n section[hosted][plain] {\n margin: 0;\n background: none;\n border: none;\n border-radius: 0;\n }\n\n ox-board-viewer {\n width: 100%;\n height: 100%;\n }\n\n /*\n * 여백을 주지 않는다 — **안에 든 절들이 이미 자기 여백을 갖는다.**\n *\n * 여기에 padding 을 두면 두 겹이 된다. 실측으로 확인했다: 안쪽 절의 왼쪽이 233px,\n * 타임라인이 221px 이었다(--spacing-large 는 이 앱에서 12px 이다). 한 화면에서 카드마다\n * 왼쪽 기준선이 달랐다.\n */\n activity-thread-view {\n display: block;\n }\n\n activity-thread-timeline {\n margin: var(--spacing-large, 16px);\n }\n\n #custom-content {\n flex: 1;\n }\n\n @media print {\n :host {\n display: block;\n overflow: visible;\n }\n }\n `\n ]\n\n @state() activityThread: any\n\n /**\n * 조회를 마쳤나 — **「아직 안 읽었다」와 「없다」는 다르다.**\n *\n * 목록에서 줄을 눌러 들어온 사람이 방금 본 건이 없다는 말을 먼저 읽지 않게, 조회가 끝난 뒤에만\n * 그 말을 한다.\n */\n @state() loaded = false\n /** Why the task could not be read - ox-page-state says it, with retry (ADR-0060 decision 8). */\n @state() loadError: unknown = null\n private lastId?: string\n @state() board: any\n\n get context() {\n return {\n /*\n * 이 화면이 어떤 틀인가 — 동작 줄이 이것을 읽고 자기 오른쪽 끝을 내용에 맞춘다\n * (ADR-0060 결정 9 보탬). 안 적으면 창 폭이고, 그것은 작업면의 모양이다.\n */\n frame: 'document',\ntitle: this.lifecycle?.params?.['title'] || i18next.t('title.activity'),\n help: 'worklist/activity-thread-view-page',\n /*\n * 이 화면은 메뉴에 없다 — 「할 일」의 완료 묶음에서 줄을 눌러 들어온다. 그래서 왼쪽 메뉴가 가리킬\n * 항목이 없고, 표시가 사라져 들어온 사람이 자기가 어디에 있는지 잃는다.\n *\n * 어느 목록에서 열리는지는 이 화면이 안다. 그것을 적어 둔다.\n */\n menu: 'todo-list',\n /*\n * 동작 줄이 비어 있다 — 끝난 일을 보는 화면이라 여기서 내릴 결정이 없다. 나가기는 두지 않는다\n * (ADR-0060 결정 9 보탬 판정 2): 탭의 × 가 이미 하는 일이고, 같은 곳으로 가는 문을 둘 두면\n * 어느 쪽이 무엇을 하는지 사람이 눌러 봐야 안다.\n */\n actions: []\n // activityThread: this.activityThread\n }\n }\n\n render() {\n const activityThread = this.activityThread\n\n /* Reading and failing both drew nothing at all, so a failure looked like an empty screen. */\n return html`<div class=\"page\">\n <ox-page-state\n .loading=${!this.loaded && !this.loadError}\n .error=${this.loadError}\n @retry=${() => this.lastId && this.fetchActivityThread(this.lastId)}\n >${\n !activityThread\n ? this.loaded\n ? html`<div empty>\n <span class=\"title\">${i18next.t('text.no activity thread info')}</span>\n <span class=\"why\">${i18next.t('text.no-activity-thread-why')}</span>\n </div>`\n : nothing\n : this.renderThread(activityThread)\n }</ox-page-state\n >\n </div>`\n }\n\n private renderThread(activityThread: any) {\n return html`\n <activity-thread-ribon .activityThread=${activityThread}></activity-thread-ribon>\n ${this.activityContent()}\n <!--\n 여기서는 편다 — 끝난 업무를 보러 온 화면이라 「어떻게 여기까지 왔나」가 곧 본문이다.\n -->\n <activity-thread-timeline .activityThread=${activityThread} open short-form></activity-thread-timeline>\n `\n }\n\n activityContent() {\n switch (this.activityThread?.activityInstance?.viewType) {\n case 'template':\n return this.hostedContent(this.templateContent())\n case 'generated':\n return this.generatedContent()\n /* board 는 전체 화면을 쓰는 캔버스라 카드에 담지 않는다. */\n case 'board':\n return this.boardContent()\n case 'custom-element':\n return this.hostedContent(this.customElementContent())\n case 'page':\n case 'external':\n return html``\n default:\n return this.generatedContent()\n }\n }\n\n /**\n * 화면 종류가 달라도 같은 자리에 같은 모양으로 놓인다(activity-approval-page 의 같은 이름 참조).\n *\n * plain 은 안에 들어오는 것이 이미 절 카드 여럿을 갖고 있을 때다 — 카드를 두 겹 두르지 않는다.\n */\n hostedContent(content: unknown, plain = false) {\n return html`<section hosted ?plain=${plain}>${content}</section>`\n }\n\n templateContent() {\n if (!this.activityThread) {\n return html``\n }\n\n const { viewSource: template } = this.activityThread?.activityInstance\n return unsafeHTML(template)\n }\n\n generatedContent(): DirectiveResult {\n if (!this.activityThread) {\n return html``\n }\n\n /*\n * id 가 아니라 **값을 넘긴다.** 전에는 id 만 주고 그쪽이 스스로 다시 조회했다 — 이 화면이 이미\n * 같은 건을 조회한 뒤라서 한 번 열면 같은 질의가 두 번 나갔다.\n */\n return keyed(\n this.activityThread.id,\n this.hostedContent(\n html`<activity-thread-view .activityThread=${this.activityThread}></activity-thread-view>`,\n true\n )\n )\n }\n\n boardContent(): DirectiveResult {\n if (!this.activityThread) {\n return html``\n }\n\n const { output, activityInstance } = this.activityThread\n const { viewSource: boardId, input } = activityInstance || {}\n\n if (!this.board || this.board.id !== boardId) {\n this.board = { id: boardId }\n }\n\n /* \n ox-board-viewer에서 provider에 의해 공급되는 board가 각 id별로 instance를 하나씩 밖에 가지지 않으므로,\n 동일한 id의 보드를 다른 page에 뺏기는 경우가 있다.\n 따라서, Page가 active될 때마다 타임스탬프를 refresh key로 설정하였다.\n */\n return keyed(\n this.activityThread.id,\n html`\n <ox-board-viewer\n style=\"background-color: white;\"\n .board=${this.board}\n .provider=${provider}\n .values=${{ ...input, ...output }}\n hide-fullscreen\n hide-navigation\n ></ox-board-viewer>\n `\n )\n }\n\n customElementContent() {\n if (!this.activityThread) {\n return html``\n }\n\n const { output, activityInstance } = this.activityThread\n const { viewSource: tagName, input } = activityInstance || {}\n\n const element = document.createElement(tagName)\n element.id = 'custom-content'\n element.input = input\n element.output = output\n element.addEventListener('change', (e: CustomEvent) => {\n this.activityThread.output = e.detail\n })\n\n return element\n }\n\n updated(changes) {\n if (changes.has('activityThread')) {\n this.updateContext()\n }\n }\n\n async pageUpdated(changes, lifecycle, changedBefore) {\n if (this.active) {\n this.fetchActivityThread(lifecycle.resourceId)\n }\n }\n\n async fetchActivityThread(id) {\n this.lastId = id\n this.loadError = null\n\n let response: any\n try {\n response = await client.query({\n query: gql`\n query activityThread($id: String!) { activityThread(id: $id) ${ActivityThreadFetchResult}\n }\n `,\n variables: { id }\n })\n } catch (error) {\n this.loadError = error\n return\n }\n\n if (response.errors?.length || !response.data) {\n this.loadError = response.errors?.length\n ? response.errors\n : new Error(i18next.t('error.activity-thread not found', { activityThread: id }))\n return\n }\n\n this.activityThread = response.data.activityThread\n this.loaded = true\n\n this.updateContext()\n }\n}\n"]}
|
|
1
|
+
{"version":3,"file":"activity-thread-view-page.js","sourceRoot":"","sources":["../../../client/pages/activity-thread/activity-thread-view-page.ts"],"names":[],"mappings":";AAAA,OAAO,mCAAmC,CAAA;AAC1C,OAAO,sCAAsC,CAAA;AAC7C,OAAO,2CAA2C,CAAA;AAClD,OAAO,8CAA8C,CAAA;AACrD,OAAO,2BAA2B,CAAA;AAElC,OAAO,GAAG,MAAM,aAAa,CAAA;AAC7B,OAAO,EAAE,GAAG,EAAE,IAAI,EAAE,OAAO,EAAE,MAAM,KAAK,CAAA;AAExC,OAAO,EAAE,UAAU,EAAE,MAAM,oCAAoC,CAAA;AAC/D,OAAO,EAAE,aAAa,EAAmB,KAAK,EAAE,MAAM,mBAAmB,CAAA;AACzE,OAAO,EAAE,KAAK,EAAE,MAAM,yBAAyB,CAAA;AAC/C,OAAO,EAAE,MAAM,EAAE,MAAM,kBAAkB,CAAA;AACzC,OAAO,EAAE,OAAO,EAAE,QAAQ,EAAE,MAAM,eAAe,CAAA;AACjD,OAAO,EAAE,QAAQ,EAAE,MAAM,gBAAgB,CAAA;AACzC,OAAO,EAAE,kBAAkB,EAAE,eAAe,EAAE,MAAM,iBAAiB,CAAA;AACrE,OAAO,EAAE,QAAQ,EAAE,MAAM,kCAAkC,CAAA;AAE3D,OAAO,EAAE,oBAAoB,EAAE,MAAM,qCAAqC,CAAA;AAC1E,OAAO,EAAE,kBAAkB,EAAE,MAAM,sCAAsC,CAAA;AAEzE,MAAM,yBAAyB,GAAG;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;QAmC1B,kBAAkB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EAoCxB,CAAA;AAEF,MAAM,CAAC,MAAM,oBAAoB,GAAG;IAClC,UAAU,EAAE,YAAY;IACxB,QAAQ,EAAE,UAAU;IACpB,OAAO,EAAE,SAAS;IAClB,SAAS,EAAE,WAAW;IACtB,QAAQ,EAAE,UAAU;IACpB,KAAK,EAAE,OAAO;IACd,OAAO,EAAE,SAAS;CACnB,CAAA;AAGM,IAAM,sBAAsB,GAA5B,MAAM,sBAAuB,SAAQ,QAAQ,CAAC,OAAO,CAAC,CAAC,QAAQ,CAAC;IAAhE;;QAiFL;;;;;WAKG;QACM,WAAM,GAAG,KAAK,CAAA;QACvB,gGAAgG;QACvF,cAAS,GAAY,IAAI,CAAA;IAoNpC,CAAC;aA5SQ,WAAM,GAAG;QACd,iFAAiF;QACjF,kBAAkB;QAClB,eAAe;QACf,oBAAoB;QACpB,GAAG,CAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;KAsEF;KACF,AA5EY,CA4EZ;IAgBD,IAAI,OAAO;QACT,OAAO;YACC;;;SAGH;YACH,KAAK,EAAE,UAAU;YACvB,KAAK,EAAE,IAAI,CAAC,SAAS,EAAE,MAAM,EAAE,CAAC,OAAO,CAAC,IAAI,OAAO,CAAC,CAAC,CAAC,gBAAgB,CAAC;YACjE,IAAI,EAAE,oCAAoC;YAC1C;;;;;eAKG;YACH,IAAI,EAAE,WAAW;YACjB;;;;eAIG;YACH,OAAO,EAAE,EAAE;YACX,sCAAsC;SACvC,CAAA;IACH,CAAC;IAED,MAAM;QACJ,MAAM,cAAc,GAAG,IAAI,CAAC,cAAc,CAAA;QAE1C,6FAA6F;QAC7F,OAAO,IAAI,CAAA;;iBAEE,CAAC,IAAI,CAAC,MAAM,IAAI,CAAC,IAAI,CAAC,SAAS;eACjC,IAAI,CAAC,SAAS;eACd,GAAG,EAAE,CAAC,IAAI,CAAC,MAAM,IAAI,IAAI,CAAC,mBAAmB,CAAC,IAAI,CAAC,MAAM,CAAC;SAEjE,CAAC,cAAc;YACb,CAAC,CAAC,IAAI,CAAC,MAAM;gBACX,CAAC,CAAC,IAAI,CAAA;sCACoB,OAAO,CAAC,CAAC,CAAC,8BAA8B,CAAC;oCAC3C,OAAO,CAAC,CAAC,CAAC,6BAA6B,CAAC;qBACvD;gBACT,CAAC,CAAC,OAAO;YACX,CAAC,CAAC,IAAI,CAAC,YAAY,CAAC,cAAc,CACtC;;WAEK,CAAA;IACT,CAAC;IAEO,YAAY,CAAC,cAAmB;QACtC,OAAO,IAAI,CAAA;+CACgC,cAAc;QACrD,IAAI,CAAC,eAAe,EAAE;;;;kDAIoB,cAAc;KAC3D,CAAA;IACH,CAAC;IAED,eAAe;QACb,QAAQ,IAAI,CAAC,cAAc,EAAE,gBAAgB,EAAE,QAAQ,EAAE,CAAC;YACxD,KAAK,UAAU;gBACb,OAAO,IAAI,CAAC,aAAa,CAAC,IAAI,CAAC,eAAe,EAAE,CAAC,CAAA;YACnD,KAAK,WAAW;gBACd,OAAO,IAAI,CAAC,gBAAgB,EAAE,CAAA;YAChC,wCAAwC;YACxC,KAAK,OAAO;gBACV,OAAO,IAAI,CAAC,YAAY,EAAE,CAAA;YAC5B,KAAK,gBAAgB;gBACnB,OAAO,IAAI,CAAC,aAAa,CAAC,IAAI,CAAC,oBAAoB,EAAE,CAAC,CAAA;YACxD,KAAK,MAAM,CAAC;YACZ,KAAK,UAAU;gBACb,OAAO,IAAI,CAAA,EAAE,CAAA;YACf;gBACE,OAAO,IAAI,CAAC,gBAAgB,EAAE,CAAA;QAClC,CAAC;IACH,CAAC;IAED;;;;OAIG;IACH,aAAa,CAAC,OAAgB,EAAE,KAAK,GAAG,KAAK;QAC3C,OAAO,IAAI,CAAA,0BAA0B,KAAK,IAAI,OAAO,YAAY,CAAA;IACnE,CAAC;IAED,eAAe;QACb,IAAI,CAAC,IAAI,CAAC,cAAc,EAAE,CAAC;YACzB,OAAO,IAAI,CAAA,EAAE,CAAA;QACf,CAAC;QAED,MAAM,EAAE,UAAU,EAAE,QAAQ,EAAE,GAAG,IAAI,CAAC,cAAc,EAAE,gBAAgB,CAAA;QACtE,OAAO,UAAU,CAAC,QAAQ,CAAC,CAAA;IAC7B,CAAC;IAED,gBAAgB;QACd,IAAI,CAAC,IAAI,CAAC,cAAc,EAAE,CAAC;YACzB,OAAO,IAAI,CAAA,EAAE,CAAA;QACf,CAAC;QAED;;;WAGG;QACH,OAAO,KAAK,CACV,IAAI,CAAC,cAAc,CAAC,EAAE,EACtB,IAAI,CAAC,aAAa,CAChB,IAAI,CAAA,yCAAyC,IAAI,CAAC,cAAc,0BAA0B,EAC1F,IAAI,CACL,CACF,CAAA;IACH,CAAC;IAED,YAAY;QACV,IAAI,CAAC,IAAI,CAAC,cAAc,EAAE,CAAC;YACzB,OAAO,IAAI,CAAA,EAAE,CAAA;QACf,CAAC;QAED,MAAM,EAAE,MAAM,EAAE,gBAAgB,EAAE,GAAG,IAAI,CAAC,cAAc,CAAA;QACxD,MAAM,EAAE,UAAU,EAAE,OAAO,EAAE,KAAK,EAAE,GAAG,gBAAgB,IAAI,EAAE,CAAA;QAE7D,IAAI,CAAC,IAAI,CAAC,KAAK,IAAI,IAAI,CAAC,KAAK,CAAC,EAAE,KAAK,OAAO,EAAE,CAAC;YAC7C,IAAI,CAAC,KAAK,GAAG,EAAE,EAAE,EAAE,OAAO,EAAE,CAAA;QAC9B,CAAC;QAED;;;;YAII;QACJ,OAAO,KAAK,CACV,IAAI,CAAC,cAAc,CAAC,EAAE,EACtB,IAAI,CAAA;;;mBAGS,IAAI,CAAC,KAAK;sBACP,QAAQ;oBACV,EAAE,GAAG,KAAK,EAAE,GAAG,MAAM,EAAE;;;;OAIpC,CACF,CAAA;IACH,CAAC;IAED,oBAAoB;QAClB,IAAI,CAAC,IAAI,CAAC,cAAc,EAAE,CAAC;YACzB,OAAO,IAAI,CAAA,EAAE,CAAA;QACf,CAAC;QAED,MAAM,EAAE,MAAM,EAAE,gBAAgB,EAAE,GAAG,IAAI,CAAC,cAAc,CAAA;QACxD,MAAM,EAAE,UAAU,EAAE,OAAO,EAAE,KAAK,EAAE,GAAG,gBAAgB,IAAI,EAAE,CAAA;QAE7D,MAAM,OAAO,GAAG,QAAQ,CAAC,aAAa,CAAC,OAAO,CAAC,CAAA;QAC/C,OAAO,CAAC,EAAE,GAAG,gBAAgB,CAAA;QAC7B,OAAO,CAAC,KAAK,GAAG,KAAK,CAAA;QACrB,OAAO,CAAC,MAAM,GAAG,MAAM,CAAA;QACvB,OAAO,CAAC,gBAAgB,CAAC,QAAQ,EAAE,CAAC,CAAc,EAAE,EAAE;YACpD,IAAI,CAAC,cAAc,CAAC,MAAM,GAAG,CAAC,CAAC,MAAM,CAAA;QACvC,CAAC,CAAC,CAAA;QAEF,OAAO,OAAO,CAAA;IAChB,CAAC;IAED,OAAO,CAAC,OAAO;QACb,IAAI,OAAO,CAAC,GAAG,CAAC,gBAAgB,CAAC,EAAE,CAAC;YAClC,IAAI,CAAC,aAAa,EAAE,CAAA;QACtB,CAAC;IACH,CAAC;IAED,KAAK,CAAC,WAAW,CAAC,OAAO,EAAE,SAAS,EAAE,aAAa;QACjD,IAAI,IAAI,CAAC,MAAM,EAAE,CAAC;YAChB,IAAI,CAAC,mBAAmB,CAAC,SAAS,CAAC,UAAU,CAAC,CAAA;QAChD,CAAC;IACH,CAAC;IAED,KAAK,CAAC,mBAAmB,CAAC,EAAE;QAC1B,IAAI,CAAC,MAAM,GAAG,EAAE,CAAA;QAChB,IAAI,CAAC,SAAS,GAAG,IAAI,CAAA;QAErB,IAAI,QAAa,CAAA;QACjB,IAAI,CAAC;YACH,QAAQ,GAAG,MAAM,MAAM,CAAC,KAAK,CAAC;gBAC5B,KAAK,EAAE,GAAG,CAAA;iFAC+D,yBAAyB;;OAEnG;gBACC,SAAS,EAAE,EAAE,EAAE,EAAE;aAClB,CAAC,CAAA;QACJ,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,IAAI,CAAC,SAAS,GAAG,KAAK,CAAA;YACtB,OAAM;QACR,CAAC;QAED,IAAI,QAAQ,CAAC,MAAM,EAAE,MAAM,IAAI,CAAC,QAAQ,CAAC,IAAI,EAAE,CAAC;YAC9C,IAAI,CAAC,SAAS,GAAG,QAAQ,CAAC,MAAM,EAAE,MAAM;gBACtC,CAAC,CAAC,QAAQ,CAAC,MAAM;gBACjB,CAAC,CAAC,IAAI,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,iCAAiC,EAAE,EAAE,cAAc,EAAE,EAAE,EAAE,CAAC,CAAC,CAAA;YACnF,OAAM;QACR,CAAC;QAED,IAAI,CAAC,cAAc,GAAG,QAAQ,CAAC,IAAI,CAAC,cAAc,CAAA;QAClD,IAAI,CAAC,MAAM,GAAG,IAAI,CAAA;QAElB,IAAI,CAAC,aAAa,EAAE,CAAA;IACtB,CAAC;;AA7NQ;IAAR,KAAK,EAAE;;8DAAoB;AAQnB;IAAR,KAAK,EAAE;;sDAAe;AAEd;IAAR,KAAK,EAAE;;yDAA0B;AAEzB;IAAR,KAAK,EAAE;;qDAAW;AA3FR,sBAAsB;IADlC,aAAa,CAAC,2BAA2B,CAAC;GAC9B,sBAAsB,CA6SlC","sourcesContent":["import '@operato/board/ox-board-viewer.js'\nimport '@operato/list-state/ox-page-state.js'\nimport '../../components/activity-thread-ribon.js'\nimport '../../components/activity-thread-timeline.js'\nimport './activity-thread-view.js'\n\nimport gql from 'graphql-tag'\nimport { css, html, nothing } from 'lit'\nimport { DirectiveResult } from 'lit-html/directive.js'\nimport { unsafeHTML } from 'lit-html/directives/unsafe-html.js'\nimport { customElement, property, query, state } from 'lit/decorators.js'\nimport { keyed } from 'lit/directives/keyed.js'\nimport { client } from '@operato/graphql'\nimport { i18next, localize } from '@operato/i18n'\nimport { PageView } from '@operato/shell'\nimport { DocumentPageStyles, ScrollbarStyles } from '@operato/styles'\nimport { provider } from '@operato/board/board-provider.js'\n\nimport { ActivityFieldsStyles } from '../../components/activity-fields.js'\nimport { DecisionKeysFields } from '../../components/decision-content.js'\n\nconst ActivityThreadFetchResult = `\\\n{ id\n state\n dueAt\n assignedAt\n startedAt\n terminatedAt\n assignee { id\n name\n }\n output\n round\n activityApprovals { round\n order\n approver { id name\n }\n judgment\n comment\n createdAt\n updatedAt\n terminatedAt\n }\n activityThreadHistories { transaction\n reason\n updater { id name\n }\n updatedAt\n state\n output\n }\n activityInstance { id\n name\n description\n state\n activity { id\n ${DecisionKeysFields}\n model { name\n description\n active\n tag\n inout\n type\n unit\n options\n quantifier\n spec\n hidden\n }\n }\n approvalLine { type\n value\n participation\n notifyAfter\n approver { id\n name\n description\n controlNo\n }\n }\n thumbnail\n input\n output\n viewType\n viewSource\n dueAt\n terminatedAt\n terminator { name\n email\n }\n createdAt\n }\n}`\n\nexport const ActivityThreadStatus = {\n Unassigned: 'unassigned',\n Assigned: 'assigned',\n Started: 'started',\n Delegated: 'delegated',\n Rejected: 'rejected',\n Ended: 'ended',\n Aborted: 'aborted'\n}\n\n@customElement('activity-thread-view-page')\nexport class ActivityThreadViewPage extends localize(i18next)(PageView) {\n static styles = [\n /* The frame owns the page shell and the reading column (ADR-0060 decision 8). */\n DocumentPageStyles,\n ScrollbarStyles,\n ActivityFieldsStyles,\n css`\n :host {\n color: var(--ui-ink, #17242c);\n font-size: var(--ui-t-body, 13px);\n }\n\n /* 카드가 담아 주므로 안에 들어오는 화면은 자기 면과 여백을 갖지 않는다. */\n /*\n * ── 줄어들지 않는다 — 줄어들면 본문이 잘린다 (2026-09-07) ──────────────\n * 이 칸은 flex 항목인데 크기를 안 정해 두어 기본값 flex: 0 1 auto 로 있었다. **1 이\n * 줄어든다는 뜻이다** — 세로가 모자라면 브라우저가 이 칸부터 줄인다. 그런데 여기엔\n * overflow: hidden 이 걸려 있어서(카드 모서리를 따라 자르려고) 줄어든 만큼이 **스크롤도\n * 없이 사라진다.**\n *\n * 실측(1400x620): 이 칸이 242px 로 줄었는데 안의 내용은 362px 이었다. 「업무 내용」 절이\n * 276~464 에 있어 대부분이 잘렸고, 잘린 자리 바로 아래에서 타임라인이 시작하니 **타임라인이\n * 본문을 덮은 것처럼** 보였다. 세로가 넉넉한 화면에서는 줄일 일이 없어 드러나지 않았다.\n *\n * 안에 오는 것은 셋 다 문서다(template · custom-element · 생성된 절 카드들). 높이를 정해\n * 주어야 하는 것은 board 뿐이고 board 는 이 칸을 거치지 않는다(activityContent 참조).\n * 문서는 제 높이로 서고, 화면이 모자라면 **페이지 전체가 스크롤한다** — :host 의\n * overflow: auto 가 이미 그 자리다.\n */\n section[hosted] {\n flex: none;\n padding: 0;\n overflow: hidden;\n }\n\n /*\n * 끝난 업무를 읽는 화면은 절이 여럿이라(기본 정보 · 업무 정보 · 수행 결과) 카드를 한 겹 더\n * 두르지 않는다. 절들이 곧 카드다.\n */\n section[hosted][plain] {\n margin: 0;\n background: none;\n border: none;\n border-radius: 0;\n }\n\n ox-board-viewer {\n width: 100%;\n height: 100%;\n }\n\n /*\n * 여백을 주지 않는다 — **안에 든 절들이 이미 자기 여백을 갖는다.**\n *\n * 여기에 padding 을 두면 두 겹이 된다. 실측으로 확인했다: 안쪽 절의 왼쪽이 233px,\n * 타임라인이 221px 이었다(--spacing-large 는 이 앱에서 12px 이다). 한 화면에서 카드마다\n * 왼쪽 기준선이 달랐다.\n */\n activity-thread-view {\n display: block;\n }\n\n activity-thread-timeline {\n margin: var(--spacing-large, 16px);\n }\n\n #custom-content {\n flex: 1;\n }\n\n @media print {\n :host {\n display: block;\n overflow: visible;\n }\n }\n `\n ]\n\n @state() activityThread: any\n\n /**\n * 조회를 마쳤나 — **「아직 안 읽었다」와 「없다」는 다르다.**\n *\n * 목록에서 줄을 눌러 들어온 사람이 방금 본 건이 없다는 말을 먼저 읽지 않게, 조회가 끝난 뒤에만\n * 그 말을 한다.\n */\n @state() loaded = false\n /** Why the task could not be read - ox-page-state says it, with retry (ADR-0060 decision 8). */\n @state() loadError: unknown = null\n private lastId?: string\n @state() board: any\n\n get context() {\n return {\n /*\n * 이 화면이 어떤 틀인가 — 동작 줄이 이것을 읽고 자기 오른쪽 끝을 내용에 맞춘다\n * (ADR-0060 결정 9 보탬). 안 적으면 창 폭이고, 그것은 작업면의 모양이다.\n */\n frame: 'document',\ntitle: this.lifecycle?.params?.['title'] || i18next.t('title.activity'),\n help: 'worklist/activity-thread-view-page',\n /*\n * 이 화면은 메뉴에 없다 — 「할 일」의 완료 묶음에서 줄을 눌러 들어온다. 그래서 왼쪽 메뉴가 가리킬\n * 항목이 없고, 표시가 사라져 들어온 사람이 자기가 어디에 있는지 잃는다.\n *\n * 어느 목록에서 열리는지는 이 화면이 안다. 그것을 적어 둔다.\n */\n menu: 'todo-list',\n /*\n * 동작 줄이 비어 있다 — 끝난 일을 보는 화면이라 여기서 내릴 결정이 없다. 나가기는 두지 않는다\n * (ADR-0060 결정 9 보탬 판정 2): 탭의 × 가 이미 하는 일이고, 같은 곳으로 가는 문을 둘 두면\n * 어느 쪽이 무엇을 하는지 사람이 눌러 봐야 안다.\n */\n actions: []\n // activityThread: this.activityThread\n }\n }\n\n render() {\n const activityThread = this.activityThread\n\n /* Reading and failing both drew nothing at all, so a failure looked like an empty screen. */\n return html`<div class=\"page\">\n <ox-page-state\n .loading=${!this.loaded && !this.loadError}\n .error=${this.loadError}\n @retry=${() => this.lastId && this.fetchActivityThread(this.lastId)}\n >${\n !activityThread\n ? this.loaded\n ? html`<div empty>\n <span class=\"title\">${i18next.t('text.no activity thread info')}</span>\n <span class=\"why\">${i18next.t('text.no-activity-thread-why')}</span>\n </div>`\n : nothing\n : this.renderThread(activityThread)\n }</ox-page-state\n >\n </div>`\n }\n\n private renderThread(activityThread: any) {\n return html`\n <activity-thread-ribon .activityThread=${activityThread}></activity-thread-ribon>\n ${this.activityContent()}\n <!--\n 여기서는 편다 — 끝난 업무를 보러 온 화면이라 「어떻게 여기까지 왔나」가 곧 본문이다.\n -->\n <activity-thread-timeline .activityThread=${activityThread} open short-form></activity-thread-timeline>\n `\n }\n\n activityContent() {\n switch (this.activityThread?.activityInstance?.viewType) {\n case 'template':\n return this.hostedContent(this.templateContent())\n case 'generated':\n return this.generatedContent()\n /* board 는 전체 화면을 쓰는 캔버스라 카드에 담지 않는다. */\n case 'board':\n return this.boardContent()\n case 'custom-element':\n return this.hostedContent(this.customElementContent())\n case 'page':\n case 'external':\n return html``\n default:\n return this.generatedContent()\n }\n }\n\n /**\n * 화면 종류가 달라도 같은 자리에 같은 모양으로 놓인다(activity-approval-page 의 같은 이름 참조).\n *\n * plain 은 안에 들어오는 것이 이미 절 카드 여럿을 갖고 있을 때다 — 카드를 두 겹 두르지 않는다.\n */\n hostedContent(content: unknown, plain = false) {\n return html`<section hosted ?plain=${plain}>${content}</section>`\n }\n\n templateContent() {\n if (!this.activityThread) {\n return html``\n }\n\n const { viewSource: template } = this.activityThread?.activityInstance\n return unsafeHTML(template)\n }\n\n generatedContent(): DirectiveResult {\n if (!this.activityThread) {\n return html``\n }\n\n /*\n * id 가 아니라 **값을 넘긴다.** 전에는 id 만 주고 그쪽이 스스로 다시 조회했다 — 이 화면이 이미\n * 같은 건을 조회한 뒤라서 한 번 열면 같은 질의가 두 번 나갔다.\n */\n return keyed(\n this.activityThread.id,\n this.hostedContent(\n html`<activity-thread-view .activityThread=${this.activityThread}></activity-thread-view>`,\n true\n )\n )\n }\n\n boardContent(): DirectiveResult {\n if (!this.activityThread) {\n return html``\n }\n\n const { output, activityInstance } = this.activityThread\n const { viewSource: boardId, input } = activityInstance || {}\n\n if (!this.board || this.board.id !== boardId) {\n this.board = { id: boardId }\n }\n\n /* \n ox-board-viewer에서 provider에 의해 공급되는 board가 각 id별로 instance를 하나씩 밖에 가지지 않으므로,\n 동일한 id의 보드를 다른 page에 뺏기는 경우가 있다.\n 따라서, Page가 active될 때마다 타임스탬프를 refresh key로 설정하였다.\n */\n return keyed(\n this.activityThread.id,\n html`\n <ox-board-viewer\n style=\"background-color: white;\"\n .board=${this.board}\n .provider=${provider}\n .values=${{ ...input, ...output }}\n hide-fullscreen\n hide-navigation\n ></ox-board-viewer>\n `\n )\n }\n\n customElementContent() {\n if (!this.activityThread) {\n return html``\n }\n\n const { output, activityInstance } = this.activityThread\n const { viewSource: tagName, input } = activityInstance || {}\n\n const element = document.createElement(tagName)\n element.id = 'custom-content'\n element.input = input\n element.output = output\n element.addEventListener('change', (e: CustomEvent) => {\n this.activityThread.output = e.detail\n })\n\n return element\n }\n\n updated(changes) {\n if (changes.has('activityThread')) {\n this.updateContext()\n }\n }\n\n async pageUpdated(changes, lifecycle, changedBefore) {\n if (this.active) {\n this.fetchActivityThread(lifecycle.resourceId)\n }\n }\n\n async fetchActivityThread(id) {\n this.lastId = id\n this.loadError = null\n\n let response: any\n try {\n response = await client.query({\n query: gql`\n query activityThread($id: String!) { activityThread(id: $id) ${ActivityThreadFetchResult}\n }\n `,\n variables: { id }\n })\n } catch (error) {\n this.loadError = error\n return\n }\n\n if (response.errors?.length || !response.data) {\n this.loadError = response.errors?.length\n ? response.errors\n : new Error(i18next.t('error.activity-thread not found', { activityThread: id }))\n return\n }\n\n this.activityThread = response.data.activityThread\n this.loaded = true\n\n this.updateContext()\n }\n}\n"]}
|
|
@@ -5,6 +5,8 @@ import { i18next, localize } from '@operato/i18n';
|
|
|
5
5
|
import { ScrollbarStyles } from '@operato/styles';
|
|
6
6
|
import { ActivityThread } from '../../types/activity-thread.js';
|
|
7
7
|
import { ActivityFieldsStyles, inputSpecOf, outputSpecOf, renderGiven, fieldValue, personValue } from '../../components/activity-fields.js';
|
|
8
|
+
import { DecisionContentStyles, renderDecision } from '../../components/decision-content.js';
|
|
9
|
+
import { threadSectionsOf } from './thread-sections.js';
|
|
8
10
|
import { whenText } from '../../when.js';
|
|
9
11
|
/**
|
|
10
12
|
* 끝난 업무를 읽는 화면 — **완료 목록에서 줄을 눌러 들어온다.**
|
|
@@ -32,6 +34,7 @@ let ActivityThreadView = class ActivityThreadView extends localize(i18next)(LitE
|
|
|
32
34
|
static { this.styles = [
|
|
33
35
|
ScrollbarStyles,
|
|
34
36
|
ActivityFieldsStyles,
|
|
37
|
+
DecisionContentStyles,
|
|
35
38
|
css `
|
|
36
39
|
:host {
|
|
37
40
|
display: block;
|
|
@@ -57,7 +60,20 @@ let ActivityThreadView = class ActivityThreadView extends localize(i18next)(LitE
|
|
|
57
60
|
const model = activityInstance?.activity?.model;
|
|
58
61
|
const inputSpec = inputSpecOf(model);
|
|
59
62
|
const outputSpec = outputSpecOf(model);
|
|
63
|
+
/*
|
|
64
|
+
* The decision first, as on the task and approval screens (thread-sections). 상신함 opens what
|
|
65
|
+
* was put up here, and an expenditure request's payee and lines live only in its decision.
|
|
66
|
+
*/
|
|
67
|
+
const decision = renderDecision(activityInstance?.activity?.decisionKeys, input);
|
|
68
|
+
const sections = threadSectionsOf({
|
|
69
|
+
decision: decision !== nothing,
|
|
70
|
+
given: inputSpec.length,
|
|
71
|
+
written: outputSpec.length,
|
|
72
|
+
state: thread.state
|
|
73
|
+
});
|
|
60
74
|
return html `
|
|
75
|
+
${sections.decision ? decision : nothing}
|
|
76
|
+
|
|
61
77
|
<section readonly>
|
|
62
78
|
<h2>${i18next.t('label.thread-basics')}</h2>
|
|
63
79
|
<dl class="given">
|
|
@@ -88,7 +104,7 @@ let ActivityThreadView = class ActivityThreadView extends localize(i18next)(LitE
|
|
|
88
104
|
</dl>
|
|
89
105
|
</section>
|
|
90
106
|
|
|
91
|
-
${
|
|
107
|
+
${sections.given
|
|
92
108
|
? html `
|
|
93
109
|
<section readonly>
|
|
94
110
|
<h2>${i18next.t('label.activity-input')}</h2>
|
|
@@ -96,7 +112,7 @@ let ActivityThreadView = class ActivityThreadView extends localize(i18next)(LitE
|
|
|
96
112
|
</section>
|
|
97
113
|
`
|
|
98
114
|
: nothing}
|
|
99
|
-
${
|
|
115
|
+
${sections.written
|
|
100
116
|
? html `
|
|
101
117
|
<section readonly>
|
|
102
118
|
<h2>${i18next.t('field.artifact')}</h2>
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"activity-thread-view.js","sourceRoot":"","sources":["../../../client/pages/activity-thread/activity-thread-view.ts"],"names":[],"mappings":";AAAA,OAAO,EAAE,GAAG,EAAE,IAAI,EAAE,UAAU,EAAE,OAAO,EAAE,MAAM,KAAK,CAAA;AACpD,OAAO,EAAE,aAAa,EAAE,QAAQ,EAAE,MAAM,mBAAmB,CAAA;AAE3D,OAAO,EAAE,OAAO,EAAE,QAAQ,EAAE,MAAM,eAAe,CAAA;AACjD,OAAO,EAAE,eAAe,EAAE,MAAM,iBAAiB,CAAA;AAEjD,OAAO,EAAE,cAAc,EAAE,MAAM,gCAAgC,CAAA;AAC/D,OAAO,EAAE,oBAAoB,EAAE,WAAW,EAAE,YAAY,EAAE,WAAW,EAAE,UAAU,EAAE,WAAW,EAAE,MAAM,qCAAqC,CAAA;AAC3I,OAAO,EAAE,QAAQ,EAAE,MAAM,eAAe,CAAA;AAExC;;;;;;;;;;;;;;;;;;;;;GAqBG;AAEI,IAAM,kBAAkB,GAAxB,MAAM,kBAAmB,SAAQ,QAAQ,CAAC,OAAO,CAAC,CAAC,UAAU,CAAC;aAC5D,WAAM,GAAG;QACd,eAAe;QACf,oBAAoB;QACpB,GAAG,CAAA;;;;;;;;;;;;;KAaF;KACF,
|
|
1
|
+
{"version":3,"file":"activity-thread-view.js","sourceRoot":"","sources":["../../../client/pages/activity-thread/activity-thread-view.ts"],"names":[],"mappings":"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","sourcesContent":["import { css, html, LitElement, nothing } from 'lit'\nimport { customElement, property } from 'lit/decorators.js'\n\nimport { i18next, localize } from '@operato/i18n'\nimport { ScrollbarStyles } from '@operato/styles'\n\nimport { ActivityThread } from '../../types/activity-thread.js'\nimport { ActivityFieldsStyles, inputSpecOf, outputSpecOf, renderGiven, fieldValue, personValue } from '../../components/activity-fields.js'\nimport { DecisionContentStyles, renderDecision } from '../../components/decision-content.js'\nimport { threadSectionsOf } from './thread-sections.js'\nimport { whenText } from '../../when.js'\n\n/**\n * 끝난 업무를 읽는 화면 — **완료 목록에서 줄을 눌러 들어온다.**\n *\n * ── 무엇이 잘못되고 있었나 (2026-09-06) ────────────────────────────────────\n * 이 화면은 같은 건을 그리는 세 화면 중 하나인데(업무 상세 · 결재 상세 · 여기), 셋이 서로 다른\n * 말과 모양을 쓰고 있었다. 같은 값을 보는 사람이 화면을 옮길 때마다 다른 것을 본다.\n *\n * 항목 이름 결재 화면은 「승인이 필요한 이유」, 여기는 원문 because\n * 객체 값 결재 화면은 JSON, 여기는 [object Object]\n * 시각 결재 화면은 2026. 9. 1. 오전 11:55, 여기는 Tuesday, September 1, 2026 at 11:55 AM\n * 갈래 결재 화면은 받은 값 · 낼 값으로 갈라 보이고, 여기는 전부 「산출물」 한 표\n *\n * 마지막이 특히 나쁘다. because 는 업무를 시작할 때 받은 값인데 「산출물」 밑에 있었다 —\n * **화면이 값의 성격을 틀리게 말한다.**\n *\n * 그래서 셋이 activity-fields 한 벌을 쓰게 했다.\n *\n * ── 자기 조회를 하지 않는다 ────────────────────────────────────────────────\n * 전에는 이 요소가 activityThreadId 를 받아 **스스로 다시 조회했다.** 담고 있는 화면\n * (activity-thread-view-page)이 이미 같은 건을 조회한 뒤였다. 한 화면을 열면 같은 질의가 두 번\n * 나갔고, 두 응답이 어긋날 수 있는 자리도 생긴다. 값을 받아 그리기만 한다.\n */\n@customElement('activity-thread-view')\nexport class ActivityThreadView extends localize(i18next)(LitElement) {\n static styles = [\n ScrollbarStyles,\n ActivityFieldsStyles,\n DecisionContentStyles,\n css`\n :host {\n display: block;\n color: var(--ui-ink, #17242c);\n font-size: var(--ui-t-body, 13px);\n }\n\n @media print {\n :host {\n display: block;\n overflow: visible;\n }\n }\n `\n ]\n\n @property({ type: Object }) activityThread?: ActivityThread\n\n render() {\n const thread = this.activityThread\n\n if (!thread) {\n return nothing\n }\n\n const { assignee, output, round, assignedAt, startedAt, terminatedAt, activityInstance } = thread\n const { input } = activityInstance || ({} as any)\n\n const model = (activityInstance as any)?.activity?.model\n const inputSpec = inputSpecOf(model)\n const outputSpec = outputSpecOf(model)\n\n /*\n * The decision first, as on the task and approval screens (thread-sections). 상신함 opens what\n * was put up here, and an expenditure request's payee and lines live only in its decision.\n */\n const decision = renderDecision((activityInstance as any)?.activity?.decisionKeys, input)\n const sections = threadSectionsOf({\n decision: decision !== nothing,\n given: inputSpec.length,\n written: outputSpec.length,\n state: thread.state\n })\n\n return html`\n ${sections.decision ? decision : nothing}\n\n <section readonly>\n <h2>${i18next.t('label.thread-basics')}</h2>\n <dl class=\"given\">\n <!-- 이 화면이 부르는 이름은 「담당자」다 — 결재 목록의 칸과 같은 낱말을 쓴다. -->\n <dt>${i18next.t('field.wl-owner')}</dt>\n <dd>${personValue(assignee)}</dd>\n\n <dt>${i18next.t('field.assigned-at')}</dt>\n <dd>${fieldValue(whenText(assignedAt))}</dd>\n\n <dt>${i18next.t('field.started-at')}</dt>\n <dd>${fieldValue(whenText(startedAt))}</dd>\n\n <dt>${i18next.t('field.terminated-at')}</dt>\n <dd>${fieldValue(whenText(terminatedAt))}</dd>\n\n <!--\n 차수는 1일 때 적지 않는다. 거의 모든 건이 1차라 그 줄은 아무것도 알려 주지 않고,\n 2차 이상일 때만 「이 건은 한 번 되돌아왔다」는 사실이 된다.\n 결재 목록의 「N차 재상신」 표식과 같은 판단이다(activity-cells 의 approvalMarks).\n -->\n ${Number(round) > 1\n ? html`\n <dt>${i18next.t('field.round')}</dt>\n <dd>${round}</dd>\n `\n : nothing}\n </dl>\n </section>\n\n ${sections.given\n ? html`\n <section readonly>\n <h2>${i18next.t('label.activity-input')}</h2>\n ${renderGiven(inputSpec, input)}\n </section>\n `\n : nothing}\n ${sections.written\n ? html`\n <section readonly>\n <h2>${i18next.t('field.artifact')}</h2>\n ${renderGiven(outputSpec, output)}\n </section>\n `\n : nothing}\n `\n }\n}\n"]}
|