@things-factory/ops-master 10.1.255 → 10.1.257
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
|
@@ -32,8 +32,10 @@ export declare class MasterChangePolicyPanel extends MasterChangePolicyPanel_bas
|
|
|
32
32
|
* 이름으로 좁힌다 — 축이 어느 업무를 부르는지는 서버가 `approvalActivity` 로 답한다.
|
|
33
33
|
*/
|
|
34
34
|
activity?: string;
|
|
35
|
-
private
|
|
36
|
-
private
|
|
35
|
+
private policies;
|
|
36
|
+
private declaring;
|
|
37
|
+
private get axes();
|
|
38
|
+
private get canDeclare();
|
|
37
39
|
/**
|
|
38
40
|
* **아직 못 읽은 것과 없는 것을 가른다.**
|
|
39
41
|
*
|
|
@@ -41,11 +43,14 @@ export declare class MasterChangePolicyPanel extends MasterChangePolicyPanel_bas
|
|
|
41
43
|
* 부르는 기준정보가 없습니다」로 그려졌다 — 잠깐 뒤에 표가 나타난다. 사람이 그 잠깐을 보면 없는
|
|
42
44
|
* 줄 알고 나간다. 읽기 전에는 아무 말도 하지 않는다.
|
|
43
45
|
*/
|
|
44
|
-
private loaded;
|
|
45
|
-
/**
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
46
|
+
private get loaded();
|
|
47
|
+
/**
|
|
48
|
+
* 못 읽었으면 못 읽었다고 말한다. 빈 표는 「없다」로 읽힌다.
|
|
49
|
+
*
|
|
50
|
+
* 오류가 예외로 안 오고 답에 실려 올 수 있다 — 그러면 `data` 가 비어 「축 0」으로 읽힌다. 못 읽은 것이다.
|
|
51
|
+
*/
|
|
52
|
+
private get failed();
|
|
53
|
+
constructor();
|
|
49
54
|
/**
|
|
50
55
|
* 정하는 것도 바꾸는 것도 여기서 한다 — 바꾸면 정책 줄이 새로 서고, 지난 개정본은 자기 때의 줄을
|
|
51
56
|
* 계속 가리킨다. **결재에 안 태운다**(2026-09-22): 사업장 소유자가 정하는 것이라 확인만 받는다.
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import { __decorate, __metadata } from "tslib";
|
|
2
2
|
import { css, html, LitElement } from 'lit';
|
|
3
|
-
import { customElement, property
|
|
3
|
+
import { customElement, property } from 'lit/decorators.js';
|
|
4
4
|
import { i18next, localize } from '@operato/i18n';
|
|
5
5
|
import { navigate } from '@operato/shell';
|
|
6
|
-
import {
|
|
6
|
+
import { MutationController, QUERY_ANSWERED, QueryController } from '@operato/graphql';
|
|
7
7
|
import { OxPrompt } from '@operato/popup';
|
|
8
8
|
import gql from 'graphql-tag';
|
|
9
9
|
import '@operato/help/ox-help-icon.js';
|
|
@@ -39,21 +39,6 @@ import { axesForActivity, panelContentSignal } from './master-change-policy-axes
|
|
|
39
39
|
* 「등록되지 않았습니다」였고, 이 화면이 그 말로 떴다(2026-09-22 화면에서 확인).
|
|
40
40
|
*/
|
|
41
41
|
let MasterChangePolicyPanel = class MasterChangePolicyPanel extends localize(i18next)(LitElement) {
|
|
42
|
-
constructor() {
|
|
43
|
-
super(...arguments);
|
|
44
|
-
this.axes = [];
|
|
45
|
-
this.canDeclare = false;
|
|
46
|
-
/**
|
|
47
|
-
* **아직 못 읽은 것과 없는 것을 가른다.**
|
|
48
|
-
*
|
|
49
|
-
* 읽기 전에는 `axes` 가 비어 있고, 업무 하나로 좁힌 자리에서는 그 빈 목록이 곧바로 「이 업무를
|
|
50
|
-
* 부르는 기준정보가 없습니다」로 그려졌다 — 잠깐 뒤에 표가 나타난다. 사람이 그 잠깐을 보면 없는
|
|
51
|
-
* 줄 알고 나간다. 읽기 전에는 아무 말도 하지 않는다.
|
|
52
|
-
*/
|
|
53
|
-
this.loaded = false;
|
|
54
|
-
/** 못 읽었으면 못 읽었다고 말한다. 빈 표는 「없다」로 읽힌다. */
|
|
55
|
-
this.failed = false;
|
|
56
|
-
}
|
|
57
42
|
static { this.styles = [
|
|
58
43
|
css `
|
|
59
44
|
table {
|
|
@@ -231,44 +216,51 @@ let MasterChangePolicyPanel = class MasterChangePolicyPanel extends localize(i18
|
|
|
231
216
|
}
|
|
232
217
|
`
|
|
233
218
|
]; }
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
this.load();
|
|
219
|
+
get axes() {
|
|
220
|
+
return this.policies.data?.masterChangePolicies?.axes ?? [];
|
|
237
221
|
}
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
222
|
+
get canDeclare() {
|
|
223
|
+
return !!this.policies.data?.masterChangePolicies?.canDeclare;
|
|
224
|
+
}
|
|
225
|
+
/**
|
|
226
|
+
* **아직 못 읽은 것과 없는 것을 가른다.**
|
|
227
|
+
*
|
|
228
|
+
* 읽기 전에는 `axes` 가 비어 있고, 업무 하나로 좁힌 자리에서는 그 빈 목록이 곧바로 「이 업무를
|
|
229
|
+
* 부르는 기준정보가 없습니다」로 그려졌다 — 잠깐 뒤에 표가 나타난다. 사람이 그 잠깐을 보면 없는
|
|
230
|
+
* 줄 알고 나간다. 읽기 전에는 아무 말도 하지 않는다.
|
|
231
|
+
*/
|
|
232
|
+
get loaded() {
|
|
233
|
+
return !!this.policies.data || !!this.policies.error;
|
|
234
|
+
}
|
|
235
|
+
/**
|
|
236
|
+
* 못 읽었으면 못 읽었다고 말한다. 빈 표는 「없다」로 읽힌다.
|
|
237
|
+
*
|
|
238
|
+
* 오류가 예외로 안 오고 답에 실려 올 수 있다 — 그러면 `data` 가 비어 「축 0」으로 읽힌다. 못 읽은 것이다.
|
|
239
|
+
*/
|
|
240
|
+
get failed() {
|
|
241
|
+
return !!this.policies.error;
|
|
242
|
+
}
|
|
243
|
+
constructor() {
|
|
244
|
+
super();
|
|
245
|
+
/* The policy of each axis in this domain (ADR-0190). */
|
|
246
|
+
this.policies = new QueryController(this, gql `
|
|
247
|
+
query {
|
|
248
|
+
masterChangePolicies
|
|
249
|
+
}
|
|
250
|
+
`);
|
|
251
|
+
this.declaring = new MutationController(this, gql `
|
|
252
|
+
mutation ($axis: String!, $approvalRequired: Boolean!, $reason: String!) {
|
|
253
|
+
declareMasterChangePolicy(axis: $axis, approvalRequired: $approvalRequired, reason: $reason)
|
|
254
|
+
}
|
|
255
|
+
`, { refetch: () => [this.policies] });
|
|
256
|
+
this.addEventListener(QUERY_ANSWERED, () => {
|
|
257
|
+
if (this.failed)
|
|
258
|
+
return console.warn(this.policies.error);
|
|
259
|
+
const signal = panelContentSignal(this.axes, this.activity, this.failed);
|
|
260
|
+
if (signal) {
|
|
261
|
+
this.dispatchEvent(new CustomEvent(ACTIVITY_PANEL_CONTENT, { detail: signal, bubbles: true, composed: true }));
|
|
262
|
+
}
|
|
263
|
+
});
|
|
272
264
|
}
|
|
273
265
|
/**
|
|
274
266
|
* 정하는 것도 바꾸는 것도 여기서 한다 — 바꾸면 정책 줄이 새로 서고, 지난 개정본은 자기 때의 줄을
|
|
@@ -313,27 +305,11 @@ let MasterChangePolicyPanel = class MasterChangePolicyPanel extends localize(i18
|
|
|
313
305
|
* 일어나는 화면을 봤다. 규제를 거는 쪽은 **결재선이 비어 있으면 거절된다**
|
|
314
306
|
* (`MASTER_APPROVAL_LINE_REQUIRED`) — 그 말을 그대로 보여야 어디를 고칠지 안다.
|
|
315
307
|
*/
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
}
|
|
322
|
-
`,
|
|
323
|
-
variables: { axis, approvalRequired, reason: i18next.t('master-policy.reason-from-setting') }
|
|
324
|
-
});
|
|
325
|
-
if (response.errors?.length) {
|
|
326
|
-
throw new Error(response.errors[0].message);
|
|
327
|
-
}
|
|
328
|
-
}
|
|
329
|
-
catch (error) {
|
|
330
|
-
/*
|
|
331
|
-
* 거절은 **틀이 이미 붉은 쪽지로 말한다** — 서버가 그 사람의 말로 지은 문장 그대로. 여기서 또
|
|
332
|
-
* 창을 띄우면 같은 말이 두 번 나온다(2026-09-22 화면에서 확인). 여기서는 다시 읽기만 한다.
|
|
333
|
-
*/
|
|
334
|
-
console.warn(error?.message ?? error);
|
|
335
|
-
}
|
|
336
|
-
this.load();
|
|
308
|
+
/*
|
|
309
|
+
* 거절은 **틀이 이미 붉은 쪽지로 말한다** — 서버가 그 사람의 말로 지은 문장 그대로. 여기서 또
|
|
310
|
+
* 창을 띄우면 같은 말이 두 번 나온다(2026-09-22 화면에서 확인). 정책은 바뀌었으면 다시 읽힌다.
|
|
311
|
+
*/
|
|
312
|
+
await this.declaring.run({ axis, approvalRequired, reason: i18next.t('master-policy.reason-from-setting') });
|
|
337
313
|
}
|
|
338
314
|
render() {
|
|
339
315
|
/* 읽기 전에는 아무 말도 하지 않는다. 「없다」도 아직 말할 수 없다. */
|
|
@@ -431,24 +407,9 @@ __decorate([
|
|
|
431
407
|
property({ type: String }),
|
|
432
408
|
__metadata("design:type", String)
|
|
433
409
|
], MasterChangePolicyPanel.prototype, "activity", void 0);
|
|
434
|
-
__decorate([
|
|
435
|
-
state(),
|
|
436
|
-
__metadata("design:type", Array)
|
|
437
|
-
], MasterChangePolicyPanel.prototype, "axes", void 0);
|
|
438
|
-
__decorate([
|
|
439
|
-
state(),
|
|
440
|
-
__metadata("design:type", Object)
|
|
441
|
-
], MasterChangePolicyPanel.prototype, "canDeclare", void 0);
|
|
442
|
-
__decorate([
|
|
443
|
-
state(),
|
|
444
|
-
__metadata("design:type", Object)
|
|
445
|
-
], MasterChangePolicyPanel.prototype, "loaded", void 0);
|
|
446
|
-
__decorate([
|
|
447
|
-
state(),
|
|
448
|
-
__metadata("design:type", Object)
|
|
449
|
-
], MasterChangePolicyPanel.prototype, "failed", void 0);
|
|
450
410
|
MasterChangePolicyPanel = __decorate([
|
|
451
|
-
customElement('master-change-policy-panel')
|
|
411
|
+
customElement('master-change-policy-panel'),
|
|
412
|
+
__metadata("design:paramtypes", [])
|
|
452
413
|
], MasterChangePolicyPanel);
|
|
453
414
|
export { MasterChangePolicyPanel };
|
|
454
415
|
//# sourceMappingURL=master-change-policy-panel.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"master-change-policy-panel.js","sourceRoot":"","sources":["../client/master-change-policy-panel.ts"],"names":[],"mappings":"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","sourcesContent":["import { css, html, LitElement } from 'lit'\nimport { customElement, property, state } from 'lit/decorators.js'\nimport { i18next, localize } from '@operato/i18n'\nimport { navigate } from '@operato/shell'\nimport { client } from '@operato/graphql'\nimport { OxPrompt } from '@operato/popup'\nimport gql from 'graphql-tag'\nimport '@operato/help/ox-help-icon.js'\n\n/* The signal name is worklist's; ops-master builds on worklist since it owns the approval flow (ADR-0086). */\nimport { ACTIVITY_PANEL_CONTENT } from '@things-factory/worklist/dist-client'\n\nimport { axesForActivity, panelContentSignal, PolicyAxis } from './master-change-policy-axes.js'\n\n/**\n * **이 사업장이 어느 기준정보를 승인제로 두는가.**\n *\n * ── 왜 설정이 아닌가 (2026-09-23, 사용자 판단) ────────────────────────────\n * 처음에는 사업장 설정의 한 칸이었다. 설정은 내가 무엇을 보는지 고르는 자리이고, **다른 사람의 일이\n * 늘어나는 것은 설정이 아니다** — 축 하나를 승인제로 돌리면 그 축의 수정이 앞으로 결재로 흘러간다.\n * 그래서 업무를 다루는 화면으로 옮긴다.\n *\n * 그때 표가 두 자리에 선다. **자리마다 고르는 목록이 다르다** — `master-change-policy-axes.ts` 가\n * 그 판단을 갖는다. 제목은 이 부품이 아니라 **담는 쪽**이 붙인다.\n *\n * ── 이 선언이 무엇인가 ─────────────────────────────────────────────────────\n * 사람의 취향이 아니라 **이 사업장의 규칙**이다. 축마다 한 번 정하고, 정하면 그 축의 마스터는\n * 승인을 지나야 바뀐다.\n *\n * ── 왜 화면이 필요했나 ─────────────────────────────────────────────────────\n * 문은 있었는데 **그리로 가는 길이 없었다.** 정책을 안 정한 축은 화면이 열리다 말고 거절을 냈고\n * (`MASTER_POLICY_REQUIRED`), 정하러 들어갈 자리도 없었다.\n *\n * ── 소유자만 정한다 ────────────────────────────────────────────────────────\n * 읽기는 누구나 한다 — 기준정보를 고치려다 막힌 사람이 **왜 막혔는지** 여기서 알아야 한다.\n * 정하는 것은 도메인 소유자뿐이고, 소유자가 아니면 그렇게 적어 준다.\n */\n/*\n * ⚠ 문구 키에 `master-policy.` 를 붙인다. 번역이 한 평면에 병합되고 **마지막이 이기므로**,\n * `text.not-declared` 처럼 흔한 이름은 다른 패키지가 다른 뜻으로 이미 쓰고 있다 — plant 에서는\n * 「등록되지 않았습니다」였고, 이 화면이 그 말로 떴다(2026-09-22 화면에서 확인).\n */\n@customElement('master-change-policy-panel')\nexport class MasterChangePolicyPanel extends localize(i18next)(LitElement) {\n static styles = [\n css`\n table {\n width: 100%;\n border-collapse: collapse;\n }\n\n /* 머리줄은 내용과 달라야 한다 — 같은 글자에 같은 선이면 첫 줄도 자료로 읽힌다. */\n th {\n text-align: left;\n padding: var(--spacing-small, 8px);\n background: var(--md-sys-color-surface-container-high);\n color: var(--md-sys-color-on-surface-variant);\n font: var(--label-font);\n font-weight: 500;\n border-bottom: 1px solid var(--md-sys-color-outline);\n white-space: nowrap;\n }\n\n td {\n text-align: left;\n vertical-align: middle;\n padding: var(--spacing-small, 8px);\n border-bottom: 1px solid var(--md-sys-color-outline-variant);\n font: var(--label-font);\n color: var(--md-sys-color-on-surface);\n }\n\n tr:last-child td {\n border-bottom: none;\n }\n\n /*\n * 둘을 나란히 두고 **지금 것을 채워서** 보인다. 채운 쪽이 지금 서 있는 것이고, 못 누른다.\n * 반대쪽은 비어 있고 눌린다 — 무엇이 서 있는지와 무엇을 고를 수 있는지가 한 자리에서 읽힌다.\n *\n * 처음엔 두 쪽의 차이가 옅은 바탕색 하나였다. 나란히 놓고 보면 둘 다 버튼으로만 보여서 어느\n * 것이 지금 것인지 안 읽혔다(2026-09-22 화면에서 확인). 채움과 비움으로 가른다.\n *\n * 둘 다 비어 있으면 **아직 안 정한 것**이다. 그 줄만 두 쪽이 다 눌린다.\n */\n /*\n * 칸을 flex 로 만들지 않는다. 그러면 그 칸만 표의 줄 높이를 안 따라가서, 옆 칸의 글자와 단추가\n * 서로 다른 높이에 놓인다(2026-09-22 화면에서 확인). 칸은 칸으로 두고 단추 사이만 띄운다.\n */\n .choice {\n white-space: nowrap;\n text-align: right;\n }\n\n .choice button + button {\n margin-left: var(--spacing-small, 6px);\n }\n\n .choice button {\n padding: 3px 12px;\n border: 1px solid var(--md-sys-color-outline-variant);\n border-radius: var(--border-radius, 4px);\n background: transparent;\n color: var(--md-sys-color-on-surface-variant);\n font: var(--label-font);\n cursor: pointer;\n }\n\n .choice button:hover {\n border-color: var(--md-sys-color-primary);\n color: var(--md-sys-color-primary);\n }\n\n /*\n * 결재선이 없어 **아직 고를 수 없는 쪽**은 그렇게 보인다. 눌러는 진다 — 왜 못 고르는지는 눌러야\n * 들을 수 있고, 못 누르게 막으면 그 까닭이 어디에도 없다.\n */\n .choice button.blocked {\n border-style: dashed;\n color: var(--md-sys-color-outline);\n }\n\n .choice button.on {\n background: var(--md-sys-color-primary);\n color: var(--md-sys-color-on-primary);\n border-color: var(--md-sys-color-primary);\n font-weight: 700;\n cursor: default;\n }\n\n /*\n * 축 이름만으로는 무엇을 정하는 것인지 안 읽힌다 — 「라우팅」과 「제조법」이 무엇이 다른지\n * 여기서 알아야 고를 수 있다.\n *\n * 한 줄은 **이름 밑에 그냥 적는다.** 마우스를 올려야 보이는 것은 안 올려 보면 없는 것과 같다.\n *\n * 더 알고 싶은 사람에게는 도움말 아이콘이 있다. 축이 무엇이고 무엇을 좌우하는지는 이 화면이\n * 한 줄로 다 말할 것이 아니라 도움말이 맡을 내용이다 — 여기서는 /master-data/<축> 으로\n * 길만 낸다. 내용은 도움말 쪽이 채운다.\n */\n /*\n * 표준 도움말 아이콘은 18px 에 불투명도 0.75 다. 그것은 폼의 이름표 옆에 하나 놓일 때의 크기고,\n * 여기서는 14px 글자 옆에 열여섯 번 되풀이돼서 이름보다 먼저 보였다. 그래서 **이 표에서만**\n * 글자에 맞춰 줄이고 뒤로 물린다. 색과 동작은 표준 그대로다.\n */\n ox-help-icon {\n vertical-align: middle;\n --help-icon-size: 15px;\n --help-icon-opacity: 0.45;\n }\n .axis {\n white-space: nowrap;\n font-weight: 500;\n }\n\n .what {\n color: var(--md-sys-color-on-surface-variant);\n font-size: 11px;\n line-height: 1.35;\n }\n\n /* 설명이 남는 자리를 먹고, 이름과 버튼은 자기 폭만 쓴다. */\n .what-column {\n width: 100%;\n }\n\n /* 넓을 때는 설명이 자기 칸에 있다. 이름 밑의 것은 접혀 있다. */\n .folded {\n display: none;\n }\n\n /*\n * 좁아지면 **설명 칸을 접어 이름 밑으로 넣는다.** 세 칸이 다 남으면 이름과 버튼이 눌려서\n * 낱말마다 줄이 바뀐다 — 고르는 화면인데 고를 것이 안 읽힌다.\n */\n @media (max-width: 720px) {\n .what-column {\n display: none;\n }\n\n .folded {\n display: block;\n margin-top: 2px;\n white-space: normal;\n }\n\n .axis {\n white-space: normal;\n }\n }\n\n /*\n * 더 좁아지면 **설명을 아주 뺀다.** 접어 넣은 두 줄이 이름보다 길어져서, 줄마다 무엇을 고르는\n * 화면인지가 안 보인다. 알고 싶은 사람은 도움말 아이콘으로 간다.\n */\n @media (max-width: 480px) {\n .folded {\n display: none;\n }\n }\n\n /*\n * 결재를 타는 축은 **결재선이 있는지 없는지를 여기서 말한다.** 없으면 정하러 가는 길도 같이\n * 낸다 — 결재선이 어디서 정해지는지(업무 목록의 그 줄) 아는 사람이 많지 않다.\n */\n .line {\n margin-top: 3px;\n color: var(--md-sys-color-on-surface-variant);\n font-size: 11px;\n }\n\n .line a {\n color: var(--md-sys-color-primary);\n }\n\n .note {\n color: var(--md-sys-color-on-surface-variant);\n padding: var(--spacing-small, 8px);\n }\n `\n ]\n\n /**\n * 업무 하나의 화면에 설 때 그 업무의 이름. 없으면 축 전부를 보인다.\n *\n * 이름으로 좁힌다 — 축이 어느 업무를 부르는지는 서버가 `approvalActivity` 로 답한다.\n */\n @property({ type: String }) activity?: string\n\n @state() private axes: PolicyAxis[] = []\n @state() private canDeclare = false\n\n /**\n * **아직 못 읽은 것과 없는 것을 가른다.**\n *\n * 읽기 전에는 `axes` 가 비어 있고, 업무 하나로 좁힌 자리에서는 그 빈 목록이 곧바로 「이 업무를\n * 부르는 기준정보가 없습니다」로 그려졌다 — 잠깐 뒤에 표가 나타난다. 사람이 그 잠깐을 보면 없는\n * 줄 알고 나간다. 읽기 전에는 아무 말도 하지 않는다.\n */\n @state() private loaded = false\n\n /** 못 읽었으면 못 읽었다고 말한다. 빈 표는 「없다」로 읽힌다. */\n @state() private failed = false\n\n connectedCallback() {\n super.connectedCallback()\n this.load()\n }\n\n private async load() {\n try {\n const response = await client.query({\n query: gql`\n query {\n masterChangePolicies\n }\n `,\n fetchPolicy: 'network-only'\n })\n\n /*\n * 오류가 예외로 안 오고 답에 실려 올 수 있다 — 그러면 `data` 가 비어 「축 0」으로 읽힌다. 못 읽은\n * 것이다.\n */\n if (response.errors?.length) throw new Error(response.errors.map((one: any) => one.message).join('; '))\n\n const found = response.data?.masterChangePolicies\n\n this.axes = found?.axes ?? []\n this.canDeclare = !!found?.canDeclare\n this.failed = false\n } catch (thrown) {\n /* 삼키지 않는다 — 빈 표를 그리면 「이 사업장은 아무것도 승인제가 아니다」로 읽힌다. */\n this.axes = []\n this.failed = true\n console.warn(thrown)\n } finally {\n this.loaded = true\n }\n\n const signal = panelContentSignal(this.axes, this.activity, this.failed)\n if (signal) {\n this.dispatchEvent(new CustomEvent(ACTIVITY_PANEL_CONTENT, { detail: signal, bubbles: true, composed: true }))\n }\n }\n\n /**\n * 정하는 것도 바꾸는 것도 여기서 한다 — 바꾸면 정책 줄이 새로 서고, 지난 개정본은 자기 때의 줄을\n * 계속 가리킨다. **결재에 안 태운다**(2026-09-22): 사업장 소유자가 정하는 것이라 확인만 받는다.\n *\n * ⚠ **사유는 사람에게 안 묻는다.** 서버가 필수로 받지만 그것은 「누가 어디서 정했나」를 남기려는\n * 것이다. 시스템 설정에 사람이 글을 쓸 일이 아니다.\n */\n private async declare(\n one: { axis: string; revisable?: boolean; approvalReady?: boolean; approvalActivity?: string | null },\n approvalRequired: boolean\n ) {\n const { axis } = one\n const how = i18next.t(approvalRequired ? 'master-policy.approval-required' : 'master-policy.direct-change-allowed')\n const name = i18next.t(`axis.${axis}`, { defaultValue: axis })\n\n /*\n * **걸 수 없는 것을 골라 보게 하지 않는다.** 결재선이 비어 있으면 서버가 거절하는데, 그것을 누른\n * 뒤에 알면 「예」를 고르고 나서 안 된다는 말을 듣는 꼴이다. 묻기 전에 먼저 본다.\n */\n if (approvalRequired && one.approvalReady === false) {\n await OxPrompt.open({\n type: 'warning',\n title: i18next.t('master-policy.approval-line-missing'),\n text: i18next.t('master-policy.set-the-approval-line', { activity: one.approvalActivity ?? '' }),\n confirmButton: { text: i18next.t('button.confirm') }\n })\n return\n }\n\n /*\n * 경고다. 이 사업장의 기준정보가 앞으로 어떻게 바뀌는가를 정하는 자리고, 규제를 푸는 쪽으로\n * 누르면 결재 없이 바로 고쳐지기 시작한다. 되묻는 말투가 아니라 멈춰 세우는 말투여야 한다.\n */\n const yes = await OxPrompt.open({\n type: 'warning',\n title: i18next.t('master-policy.confirm-title'),\n text: i18next.t('master-policy.confirm-text', { master: name, how }),\n confirmButton: { text: i18next.t('button.confirm') },\n cancelButton: { text: i18next.t('button.cancel') }\n })\n\n if (!yes) {\n return\n }\n\n /*\n * 거절을 삼키지 않는다. 앞서는 오류가 있으면 그냥 다시 읽었고, 사람은 눌렀는데 아무 일도 안\n * 일어나는 화면을 봤다. 규제를 거는 쪽은 **결재선이 비어 있으면 거절된다**\n * (`MASTER_APPROVAL_LINE_REQUIRED`) — 그 말을 그대로 보여야 어디를 고칠지 안다.\n */\n try {\n const response = await client.mutate({\n mutation: gql`\n mutation ($axis: String!, $approvalRequired: Boolean!, $reason: String!) {\n declareMasterChangePolicy(axis: $axis, approvalRequired: $approvalRequired, reason: $reason)\n }\n `,\n variables: { axis, approvalRequired, reason: i18next.t('master-policy.reason-from-setting') }\n })\n\n if (response.errors?.length) {\n throw new Error(response.errors[0].message)\n }\n } catch (error: any) {\n /*\n * 거절은 **틀이 이미 붉은 쪽지로 말한다** — 서버가 그 사람의 말로 지은 문장 그대로. 여기서 또\n * 창을 띄우면 같은 말이 두 번 나온다(2026-09-22 화면에서 확인). 여기서는 다시 읽기만 한다.\n */\n console.warn(error?.message ?? error)\n }\n\n this.load()\n }\n\n render() {\n /* 읽기 전에는 아무 말도 하지 않는다. 「없다」도 아직 말할 수 없다. */\n if (!this.loaded) {\n return html``\n }\n\n if (this.failed) {\n return html`<div class=\"note\">${i18next.t('master-policy.could-not-read')}</div>`\n }\n\n const shown = axesForActivity(this.axes, this.activity)\n\n /*\n * 좁혔는데 하나도 없으면 **그 사실을 말한다.** 빈 표를 두면 「이 업무를 부르는 축이 없다」와\n * 「아직 못 읽었다」가 같은 화면이 된다.\n */\n if (this.activity && !shown.length) {\n return html`<div class=\"note\">${i18next.t('master-policy.no-axis-for-activity')}</div>`\n }\n\n return html`\n <div>\n ${this.canDeclare ? '' : html`<div class=\"note\">${i18next.t('master-policy.only-the-owner')}</div>`}\n\n <table>\n <tr>\n <th>${i18next.t('master-policy.field.axis')}</th>\n <th class=\"what-column\">${i18next.t('master-policy.field.what')}</th>\n <th>${i18next.t('master-policy.field.state')}</th>\n </tr>\n ${shown.map(\n one => html`\n <tr>\n <td class=\"axis\">\n ${i18next.t(`axis.${one.axis}`, { defaultValue: one.axis })}\n <ox-help-icon topic=${`/master-data/${one.axis}`}></ox-help-icon>\n <span class=\"what folded\">${i18next.t(`axis-help.${one.axis}`, { defaultValue: '' })}</span>\n </td>\n <td class=\"what what-column\">${i18next.t(`axis-help.${one.axis}`, { defaultValue: '' })}</td>\n ${!this.canDeclare\n ? html`<td>\n ${one.approvalRequired\n ? i18next.t('master-policy.approval-required')\n : i18next.t('master-policy.direct-change-allowed')}\n </td>`\n : one.revisable === false && one.approvalRequired !== true\n ? /*\n * 개정본 문이 없는 축은 소유자가 고를 것이 없다 — 버튼 대신 지금 상태와 한 줄(UX, 2026-09-24).\n * 막힌 버튼은 사람이 풀 수 있는 막힘(결재선 없음)에만 쓴다.\n */\n html`<td class=\"choice\">\n ${i18next.t('master-policy.direct-change-allowed')}\n <div class=\"line\">${i18next.t('master-policy.no-revision-path')}</div>\n </td>`\n : html`<td class=\"choice\">\n <button\n class=\"${one.approvalRequired === true ? 'on' : ''} ${one.approvalReady === false\n ? 'blocked'\n : ''}\"\n ?disabled=${one.approvalRequired === true}\n @click=${() => this.declare(one, true)}\n >\n ${i18next.t('master-policy.button.approval-required')}\n </button>\n <button\n class=${one.approvalRequired === false ? 'on' : ''}\n ?disabled=${one.approvalRequired === false}\n @click=${() => this.declare(one, false)}\n >\n ${i18next.t('master-policy.button.direct-change')}\n </button>\n ${one.revisable === false\n ? html`<div class=\"line\">${i18next.t('master-policy.no-revision-path')}</div>`\n : ''}\n ${one.approvalActivity\n ? html`<div class=\"line\">\n ${one.approvalReady\n ? i18next.t('master-policy.approval-line-set')\n : this.activity\n ? i18next.t('master-policy.approval-line-none-here')\n : html`${i18next.t('master-policy.approval-line-none')} ·\n <a\n href=\"javascript:void(0)\"\n @click=${() =>\n navigate(\n 'activity-detail?name=' + encodeURIComponent(one.approvalActivity as string)\n )}\n >\n ${i18next.t('master-policy.go-set-the-line')}\n </a>`}\n </div>`\n : ''}\n </td>`}\n </tr>\n `\n )}\n </table>\n </div>\n `\n }\n}\n"]}
|
|
1
|
+
{"version":3,"file":"master-change-policy-panel.js","sourceRoot":"","sources":["../client/master-change-policy-panel.ts"],"names":[],"mappings":"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","sourcesContent":["import { css, html, LitElement } from 'lit'\nimport { customElement, property } from 'lit/decorators.js'\nimport { i18next, localize } from '@operato/i18n'\nimport { navigate } from '@operato/shell'\nimport { MutationController, QUERY_ANSWERED, QueryController } from '@operato/graphql'\nimport { OxPrompt } from '@operato/popup'\nimport gql from 'graphql-tag'\nimport '@operato/help/ox-help-icon.js'\n\n/* The signal name is worklist's; ops-master builds on worklist since it owns the approval flow (ADR-0086). */\nimport { ACTIVITY_PANEL_CONTENT } from '@things-factory/worklist/dist-client'\n\nimport { axesForActivity, panelContentSignal, PolicyAxis } from './master-change-policy-axes.js'\n\n/**\n * **이 사업장이 어느 기준정보를 승인제로 두는가.**\n *\n * ── 왜 설정이 아닌가 (2026-09-23, 사용자 판단) ────────────────────────────\n * 처음에는 사업장 설정의 한 칸이었다. 설정은 내가 무엇을 보는지 고르는 자리이고, **다른 사람의 일이\n * 늘어나는 것은 설정이 아니다** — 축 하나를 승인제로 돌리면 그 축의 수정이 앞으로 결재로 흘러간다.\n * 그래서 업무를 다루는 화면으로 옮긴다.\n *\n * 그때 표가 두 자리에 선다. **자리마다 고르는 목록이 다르다** — `master-change-policy-axes.ts` 가\n * 그 판단을 갖는다. 제목은 이 부품이 아니라 **담는 쪽**이 붙인다.\n *\n * ── 이 선언이 무엇인가 ─────────────────────────────────────────────────────\n * 사람의 취향이 아니라 **이 사업장의 규칙**이다. 축마다 한 번 정하고, 정하면 그 축의 마스터는\n * 승인을 지나야 바뀐다.\n *\n * ── 왜 화면이 필요했나 ─────────────────────────────────────────────────────\n * 문은 있었는데 **그리로 가는 길이 없었다.** 정책을 안 정한 축은 화면이 열리다 말고 거절을 냈고\n * (`MASTER_POLICY_REQUIRED`), 정하러 들어갈 자리도 없었다.\n *\n * ── 소유자만 정한다 ────────────────────────────────────────────────────────\n * 읽기는 누구나 한다 — 기준정보를 고치려다 막힌 사람이 **왜 막혔는지** 여기서 알아야 한다.\n * 정하는 것은 도메인 소유자뿐이고, 소유자가 아니면 그렇게 적어 준다.\n */\n/*\n * ⚠ 문구 키에 `master-policy.` 를 붙인다. 번역이 한 평면에 병합되고 **마지막이 이기므로**,\n * `text.not-declared` 처럼 흔한 이름은 다른 패키지가 다른 뜻으로 이미 쓰고 있다 — plant 에서는\n * 「등록되지 않았습니다」였고, 이 화면이 그 말로 떴다(2026-09-22 화면에서 확인).\n */\n@customElement('master-change-policy-panel')\nexport class MasterChangePolicyPanel extends localize(i18next)(LitElement) {\n static styles = [\n css`\n table {\n width: 100%;\n border-collapse: collapse;\n }\n\n /* 머리줄은 내용과 달라야 한다 — 같은 글자에 같은 선이면 첫 줄도 자료로 읽힌다. */\n th {\n text-align: left;\n padding: var(--spacing-small, 8px);\n background: var(--md-sys-color-surface-container-high);\n color: var(--md-sys-color-on-surface-variant);\n font: var(--label-font);\n font-weight: 500;\n border-bottom: 1px solid var(--md-sys-color-outline);\n white-space: nowrap;\n }\n\n td {\n text-align: left;\n vertical-align: middle;\n padding: var(--spacing-small, 8px);\n border-bottom: 1px solid var(--md-sys-color-outline-variant);\n font: var(--label-font);\n color: var(--md-sys-color-on-surface);\n }\n\n tr:last-child td {\n border-bottom: none;\n }\n\n /*\n * 둘을 나란히 두고 **지금 것을 채워서** 보인다. 채운 쪽이 지금 서 있는 것이고, 못 누른다.\n * 반대쪽은 비어 있고 눌린다 — 무엇이 서 있는지와 무엇을 고를 수 있는지가 한 자리에서 읽힌다.\n *\n * 처음엔 두 쪽의 차이가 옅은 바탕색 하나였다. 나란히 놓고 보면 둘 다 버튼으로만 보여서 어느\n * 것이 지금 것인지 안 읽혔다(2026-09-22 화면에서 확인). 채움과 비움으로 가른다.\n *\n * 둘 다 비어 있으면 **아직 안 정한 것**이다. 그 줄만 두 쪽이 다 눌린다.\n */\n /*\n * 칸을 flex 로 만들지 않는다. 그러면 그 칸만 표의 줄 높이를 안 따라가서, 옆 칸의 글자와 단추가\n * 서로 다른 높이에 놓인다(2026-09-22 화면에서 확인). 칸은 칸으로 두고 단추 사이만 띄운다.\n */\n .choice {\n white-space: nowrap;\n text-align: right;\n }\n\n .choice button + button {\n margin-left: var(--spacing-small, 6px);\n }\n\n .choice button {\n padding: 3px 12px;\n border: 1px solid var(--md-sys-color-outline-variant);\n border-radius: var(--border-radius, 4px);\n background: transparent;\n color: var(--md-sys-color-on-surface-variant);\n font: var(--label-font);\n cursor: pointer;\n }\n\n .choice button:hover {\n border-color: var(--md-sys-color-primary);\n color: var(--md-sys-color-primary);\n }\n\n /*\n * 결재선이 없어 **아직 고를 수 없는 쪽**은 그렇게 보인다. 눌러는 진다 — 왜 못 고르는지는 눌러야\n * 들을 수 있고, 못 누르게 막으면 그 까닭이 어디에도 없다.\n */\n .choice button.blocked {\n border-style: dashed;\n color: var(--md-sys-color-outline);\n }\n\n .choice button.on {\n background: var(--md-sys-color-primary);\n color: var(--md-sys-color-on-primary);\n border-color: var(--md-sys-color-primary);\n font-weight: 700;\n cursor: default;\n }\n\n /*\n * 축 이름만으로는 무엇을 정하는 것인지 안 읽힌다 — 「라우팅」과 「제조법」이 무엇이 다른지\n * 여기서 알아야 고를 수 있다.\n *\n * 한 줄은 **이름 밑에 그냥 적는다.** 마우스를 올려야 보이는 것은 안 올려 보면 없는 것과 같다.\n *\n * 더 알고 싶은 사람에게는 도움말 아이콘이 있다. 축이 무엇이고 무엇을 좌우하는지는 이 화면이\n * 한 줄로 다 말할 것이 아니라 도움말이 맡을 내용이다 — 여기서는 /master-data/<축> 으로\n * 길만 낸다. 내용은 도움말 쪽이 채운다.\n */\n /*\n * 표준 도움말 아이콘은 18px 에 불투명도 0.75 다. 그것은 폼의 이름표 옆에 하나 놓일 때의 크기고,\n * 여기서는 14px 글자 옆에 열여섯 번 되풀이돼서 이름보다 먼저 보였다. 그래서 **이 표에서만**\n * 글자에 맞춰 줄이고 뒤로 물린다. 색과 동작은 표준 그대로다.\n */\n ox-help-icon {\n vertical-align: middle;\n --help-icon-size: 15px;\n --help-icon-opacity: 0.45;\n }\n .axis {\n white-space: nowrap;\n font-weight: 500;\n }\n\n .what {\n color: var(--md-sys-color-on-surface-variant);\n font-size: 11px;\n line-height: 1.35;\n }\n\n /* 설명이 남는 자리를 먹고, 이름과 버튼은 자기 폭만 쓴다. */\n .what-column {\n width: 100%;\n }\n\n /* 넓을 때는 설명이 자기 칸에 있다. 이름 밑의 것은 접혀 있다. */\n .folded {\n display: none;\n }\n\n /*\n * 좁아지면 **설명 칸을 접어 이름 밑으로 넣는다.** 세 칸이 다 남으면 이름과 버튼이 눌려서\n * 낱말마다 줄이 바뀐다 — 고르는 화면인데 고를 것이 안 읽힌다.\n */\n @media (max-width: 720px) {\n .what-column {\n display: none;\n }\n\n .folded {\n display: block;\n margin-top: 2px;\n white-space: normal;\n }\n\n .axis {\n white-space: normal;\n }\n }\n\n /*\n * 더 좁아지면 **설명을 아주 뺀다.** 접어 넣은 두 줄이 이름보다 길어져서, 줄마다 무엇을 고르는\n * 화면인지가 안 보인다. 알고 싶은 사람은 도움말 아이콘으로 간다.\n */\n @media (max-width: 480px) {\n .folded {\n display: none;\n }\n }\n\n /*\n * 결재를 타는 축은 **결재선이 있는지 없는지를 여기서 말한다.** 없으면 정하러 가는 길도 같이\n * 낸다 — 결재선이 어디서 정해지는지(업무 목록의 그 줄) 아는 사람이 많지 않다.\n */\n .line {\n margin-top: 3px;\n color: var(--md-sys-color-on-surface-variant);\n font-size: 11px;\n }\n\n .line a {\n color: var(--md-sys-color-primary);\n }\n\n .note {\n color: var(--md-sys-color-on-surface-variant);\n padding: var(--spacing-small, 8px);\n }\n `\n ]\n\n /**\n * 업무 하나의 화면에 설 때 그 업무의 이름. 없으면 축 전부를 보인다.\n *\n * 이름으로 좁힌다 — 축이 어느 업무를 부르는지는 서버가 `approvalActivity` 로 답한다.\n */\n @property({ type: String }) activity?: string\n\n /* The policy of each axis in this domain (ADR-0190). */\n private policies = new QueryController<{ masterChangePolicies?: { axes?: PolicyAxis[]; canDeclare?: boolean } }>(\n this,\n gql`\n query {\n masterChangePolicies\n }\n `\n )\n\n private declaring = new MutationController(\n this,\n gql`\n mutation ($axis: String!, $approvalRequired: Boolean!, $reason: String!) {\n declareMasterChangePolicy(axis: $axis, approvalRequired: $approvalRequired, reason: $reason)\n }\n `,\n { refetch: () => [this.policies] }\n )\n\n private get axes(): PolicyAxis[] {\n return this.policies.data?.masterChangePolicies?.axes ?? []\n }\n\n private get canDeclare() {\n return !!this.policies.data?.masterChangePolicies?.canDeclare\n }\n\n /**\n * **아직 못 읽은 것과 없는 것을 가른다.**\n *\n * 읽기 전에는 `axes` 가 비어 있고, 업무 하나로 좁힌 자리에서는 그 빈 목록이 곧바로 「이 업무를\n * 부르는 기준정보가 없습니다」로 그려졌다 — 잠깐 뒤에 표가 나타난다. 사람이 그 잠깐을 보면 없는\n * 줄 알고 나간다. 읽기 전에는 아무 말도 하지 않는다.\n */\n private get loaded() {\n return !!this.policies.data || !!this.policies.error\n }\n\n /**\n * 못 읽었으면 못 읽었다고 말한다. 빈 표는 「없다」로 읽힌다.\n *\n * 오류가 예외로 안 오고 답에 실려 올 수 있다 — 그러면 `data` 가 비어 「축 0」으로 읽힌다. 못 읽은 것이다.\n */\n private get failed() {\n return !!this.policies.error\n }\n\n constructor() {\n super()\n this.addEventListener(QUERY_ANSWERED, () => {\n if (this.failed) return console.warn(this.policies.error)\n const signal = panelContentSignal(this.axes, this.activity, this.failed)\n if (signal) {\n this.dispatchEvent(new CustomEvent(ACTIVITY_PANEL_CONTENT, { detail: signal, bubbles: true, composed: true }))\n }\n })\n }\n\n /**\n * 정하는 것도 바꾸는 것도 여기서 한다 — 바꾸면 정책 줄이 새로 서고, 지난 개정본은 자기 때의 줄을\n * 계속 가리킨다. **결재에 안 태운다**(2026-09-22): 사업장 소유자가 정하는 것이라 확인만 받는다.\n *\n * ⚠ **사유는 사람에게 안 묻는다.** 서버가 필수로 받지만 그것은 「누가 어디서 정했나」를 남기려는\n * 것이다. 시스템 설정에 사람이 글을 쓸 일이 아니다.\n */\n private async declare(\n one: { axis: string; revisable?: boolean; approvalReady?: boolean; approvalActivity?: string | null },\n approvalRequired: boolean\n ) {\n const { axis } = one\n const how = i18next.t(approvalRequired ? 'master-policy.approval-required' : 'master-policy.direct-change-allowed')\n const name = i18next.t(`axis.${axis}`, { defaultValue: axis })\n\n /*\n * **걸 수 없는 것을 골라 보게 하지 않는다.** 결재선이 비어 있으면 서버가 거절하는데, 그것을 누른\n * 뒤에 알면 「예」를 고르고 나서 안 된다는 말을 듣는 꼴이다. 묻기 전에 먼저 본다.\n */\n if (approvalRequired && one.approvalReady === false) {\n await OxPrompt.open({\n type: 'warning',\n title: i18next.t('master-policy.approval-line-missing'),\n text: i18next.t('master-policy.set-the-approval-line', { activity: one.approvalActivity ?? '' }),\n confirmButton: { text: i18next.t('button.confirm') }\n })\n return\n }\n\n /*\n * 경고다. 이 사업장의 기준정보가 앞으로 어떻게 바뀌는가를 정하는 자리고, 규제를 푸는 쪽으로\n * 누르면 결재 없이 바로 고쳐지기 시작한다. 되묻는 말투가 아니라 멈춰 세우는 말투여야 한다.\n */\n const yes = await OxPrompt.open({\n type: 'warning',\n title: i18next.t('master-policy.confirm-title'),\n text: i18next.t('master-policy.confirm-text', { master: name, how }),\n confirmButton: { text: i18next.t('button.confirm') },\n cancelButton: { text: i18next.t('button.cancel') }\n })\n\n if (!yes) {\n return\n }\n\n /*\n * 거절을 삼키지 않는다. 앞서는 오류가 있으면 그냥 다시 읽었고, 사람은 눌렀는데 아무 일도 안\n * 일어나는 화면을 봤다. 규제를 거는 쪽은 **결재선이 비어 있으면 거절된다**\n * (`MASTER_APPROVAL_LINE_REQUIRED`) — 그 말을 그대로 보여야 어디를 고칠지 안다.\n */\n /*\n * 거절은 **틀이 이미 붉은 쪽지로 말한다** — 서버가 그 사람의 말로 지은 문장 그대로. 여기서 또\n * 창을 띄우면 같은 말이 두 번 나온다(2026-09-22 화면에서 확인). 정책은 바뀌었으면 다시 읽힌다.\n */\n await this.declaring.run({ axis, approvalRequired, reason: i18next.t('master-policy.reason-from-setting') })\n }\n\n render() {\n /* 읽기 전에는 아무 말도 하지 않는다. 「없다」도 아직 말할 수 없다. */\n if (!this.loaded) {\n return html``\n }\n\n if (this.failed) {\n return html`<div class=\"note\">${i18next.t('master-policy.could-not-read')}</div>`\n }\n\n const shown = axesForActivity(this.axes, this.activity)\n\n /*\n * 좁혔는데 하나도 없으면 **그 사실을 말한다.** 빈 표를 두면 「이 업무를 부르는 축이 없다」와\n * 「아직 못 읽었다」가 같은 화면이 된다.\n */\n if (this.activity && !shown.length) {\n return html`<div class=\"note\">${i18next.t('master-policy.no-axis-for-activity')}</div>`\n }\n\n return html`\n <div>\n ${this.canDeclare ? '' : html`<div class=\"note\">${i18next.t('master-policy.only-the-owner')}</div>`}\n\n <table>\n <tr>\n <th>${i18next.t('master-policy.field.axis')}</th>\n <th class=\"what-column\">${i18next.t('master-policy.field.what')}</th>\n <th>${i18next.t('master-policy.field.state')}</th>\n </tr>\n ${shown.map(\n one => html`\n <tr>\n <td class=\"axis\">\n ${i18next.t(`axis.${one.axis}`, { defaultValue: one.axis })}\n <ox-help-icon topic=${`/master-data/${one.axis}`}></ox-help-icon>\n <span class=\"what folded\">${i18next.t(`axis-help.${one.axis}`, { defaultValue: '' })}</span>\n </td>\n <td class=\"what what-column\">${i18next.t(`axis-help.${one.axis}`, { defaultValue: '' })}</td>\n ${!this.canDeclare\n ? html`<td>\n ${one.approvalRequired\n ? i18next.t('master-policy.approval-required')\n : i18next.t('master-policy.direct-change-allowed')}\n </td>`\n : one.revisable === false && one.approvalRequired !== true\n ? /*\n * 개정본 문이 없는 축은 소유자가 고를 것이 없다 — 버튼 대신 지금 상태와 한 줄(UX, 2026-09-24).\n * 막힌 버튼은 사람이 풀 수 있는 막힘(결재선 없음)에만 쓴다.\n */\n html`<td class=\"choice\">\n ${i18next.t('master-policy.direct-change-allowed')}\n <div class=\"line\">${i18next.t('master-policy.no-revision-path')}</div>\n </td>`\n : html`<td class=\"choice\">\n <button\n class=\"${one.approvalRequired === true ? 'on' : ''} ${one.approvalReady === false\n ? 'blocked'\n : ''}\"\n ?disabled=${one.approvalRequired === true}\n @click=${() => this.declare(one, true)}\n >\n ${i18next.t('master-policy.button.approval-required')}\n </button>\n <button\n class=${one.approvalRequired === false ? 'on' : ''}\n ?disabled=${one.approvalRequired === false}\n @click=${() => this.declare(one, false)}\n >\n ${i18next.t('master-policy.button.direct-change')}\n </button>\n ${one.revisable === false\n ? html`<div class=\"line\">${i18next.t('master-policy.no-revision-path')}</div>`\n : ''}\n ${one.approvalActivity\n ? html`<div class=\"line\">\n ${one.approvalReady\n ? i18next.t('master-policy.approval-line-set')\n : this.activity\n ? i18next.t('master-policy.approval-line-none-here')\n : html`${i18next.t('master-policy.approval-line-none')} ·\n <a\n href=\"javascript:void(0)\"\n @click=${() =>\n navigate(\n 'activity-detail?name=' + encodeURIComponent(one.approvalActivity as string)\n )}\n >\n ${i18next.t('master-policy.go-set-the-line')}\n </a>`}\n </div>`\n : ''}\n </td>`}\n </tr>\n `\n )}\n </table>\n </div>\n `\n }\n}\n"]}
|