@things-factory/dataset 6.0.41 → 6.0.42
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-server/tsconfig.tsbuildinfo +1 -1
- package/package.json +3 -3
- package/dist-client/components/data-collect-activity-view.d.ts +0 -19
- package/dist-client/components/data-collect-activity-view.js +0 -101
- package/dist-client/components/data-collect-activity-view.js.map +0 -1
- package/dist-client/components/data-ooc-activity-view.d.ts +0 -1
- package/dist-client/components/data-ooc-activity-view.js +0 -154
- package/dist-client/components/data-ooc-activity-view.js.map +0 -1
- package/dist-client/components/ooc-resolve-activity-view.d.ts +0 -1
- package/dist-client/components/ooc-resolve-activity-view.js +0 -175
- package/dist-client/components/ooc-resolve-activity-view.js.map +0 -1
- package/dist-client/components/ooc-review-activity-view.d.ts +0 -1
- package/dist-client/components/ooc-review-activity-view.js +0 -155
- package/dist-client/components/ooc-review-activity-view.js.map +0 -1
- package/dist-client/components/ox-data-entry-view.d.ts +0 -12
- package/dist-client/components/ox-data-entry-view.js +0 -181
- package/dist-client/components/ox-data-entry-view.js.map +0 -1
- package/dist-server/controllers/activity-template/activity-data-collect.js +0 -82
- package/dist-server/controllers/activity-template/activity-data-collect.js.map +0 -1
- package/dist-server/controllers/activity-template/activity-ooc-resolve.js +0 -100
- package/dist-server/controllers/activity-template/activity-ooc-resolve.js.map +0 -1
- package/dist-server/controllers/activity-template/activity-ooc-review.js +0 -107
- package/dist-server/controllers/activity-template/activity-ooc-review.js.map +0 -1
- package/dist-server/controllers/activity-template/activity-ooc.js +0 -59
- package/dist-server/controllers/activity-template/activity-ooc.js.map +0 -1
@@ -1 +0,0 @@
|
|
1
|
-
{"version":3,"file":"ooc-review-activity-view.js","sourceRoot":"","sources":["../../client/components/ooc-review-activity-view.ts"],"names":[],"mappings":";AAAA,OAAO,yCAAyC,CAAA;AAEhD,OAAO,GAAG,MAAM,aAAa,CAAA;AAC7B,OAAO,EAAE,GAAG,EAAE,IAAI,EAAE,UAAU,EAAE,MAAM,KAAK,CAAA;AAC3C,OAAO,EAAE,aAAa,EAAE,QAAQ,EAAE,KAAK,EAAE,KAAK,EAAE,MAAM,mBAAmB,CAAA;AAEzE,OAAO,EAAE,MAAM,EAAE,MAAM,kBAAkB,CAAA;AACzC,OAAO,EAAE,OAAO,EAAE,QAAQ,EAAE,MAAM,eAAe,CAAA;AACjD,OAAO,EAAE,eAAe,EAAE,MAAM,iBAAiB,CAAA;AAGjD,IAAM,qBAAqB,GAA3B,MAAM,qBAAsB,SAAQ,QAAQ,CAAC,OAAO,CAAC,CAAC,UAAU,CAAC;IA8D/D,MAAM;;QACJ,MAAM,WAAW,GAAG,MAAA,IAAI,CAAC,MAAM,0CAAE,WAAW,CAAA;QAE5C,OAAO,IAAI,CAAA;;2CAE4B,IAAI,CAAC,OAAO;;;;;;;mBAOpC,WAAW,IAAI,EAAE;oBAChB,IAAI,CAAC,mBAAmB;;;KAGvC,CAAA;IACH,CAAC;IAED,mBAAmB,CAAC,CAAQ;QAC1B,IAAI,CAAC,MAAM,KAAX,IAAI,CAAC,MAAM,GAAK,EAAE,EAAA;QAClB,IAAI,CAAC,MAAM,CAAC,WAAW,GAAI,CAAC,CAAC,MAA8B,CAAC,KAAK,CAAA;QAEjE,IAAI,CAAC,aAAa,CAChB,IAAI,WAAW,CAAC,QAAQ,EAAE;YACxB,MAAM,EAAE,IAAI,CAAC,MAAM;SACpB,CAAC,CACH,CAAA;IACH,CAAC;IAED,OAAO,CAAC,OAAO;QACb,IAAI,OAAO,CAAC,GAAG,CAAC,OAAO,CAAC,EAAE;YACxB,IAAI,CAAC,YAAY,EAAE,CAAA;SACpB;IACH,CAAC;IAED,KAAK,CAAC,YAAY;;QAChB,MAAM,EAAE,GAAG,MAAA,IAAI,CAAC,KAAK,0CAAE,SAAS,CAAA;QAEhC,IAAI,EAAE,EAAE;YACN,MAAM,QAAQ,GAAG,MAAM,MAAM,CAAC,KAAK,CAAC;gBAClC,KAAK,EAAE,GAAG,CAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;SA6BT;gBACD,SAAS,EAAE;oBACT,EAAE;iBACH;aACF,CAAC,CAAA;YAEF,IAAI,CAAC,OAAO,GAAG,QAAQ,CAAC,IAAI,CAAC,OAAO,CAAA;SACrC;IACH,CAAC;;AA3IM,4BAAM,GAAG;IACd,eAAe;IACf,GAAG,CAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;KAiDF;CACF,CAAA;AAED;IAAC,QAAQ,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,CAAC;;oDAAY;AACvC;IAAC,QAAQ,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,CAAC;;qDAAa;AAExC;IAAC,KAAK,EAAE;;sDAAc;AAEtB;IAAC,KAAK,CAAC,UAAU,CAAC;8BAAuB,mBAAmB;kEAAA;AA5DxD,qBAAqB;IAD1B,aAAa,CAAC,0BAA0B,CAAC;GACpC,qBAAqB,CA6I1B","sourcesContent":["import '@operato/dataset/ox-data-sample-view.js'\n\nimport gql from 'graphql-tag'\nimport { css, html, LitElement } 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\n@customElement('ooc-review-activity-view')\nclass OocReviewActivityView extends localize(i18next)(LitElement) {\n static styles = [\n ScrollbarStyles,\n css`\n :host {\n display: flex;\n flex-direction: column;\n\n background-color: #fff;\n }\n\n div[content] {\n flex: 1;\n flex-direction: column;\n\n display: flex;\n overflow: auto;\n }\n\n ox-data-sample-view {\n flex: 1;\n padding: var(--padding-wide);\n overflow: auto;\n }\n\n label[instruction] {\n display: flex;\n flex-direction: column;\n\n padding: var(--padding-wide);\n }\n\n label[instruction] div {\n display: flex;\n }\n\n mwc-icon {\n color: var(--status-danger-color);\n }\n\n textarea {\n border: var(--input-field-border);\n border-radius: var(--input-border-radius);\n padding: var(--input-field-padding);\n font: var(--input-field-font);\n }\n\n .button-container {\n display: flex;\n margin-left: auto;\n padding: var(--padding-default);\n }\n `\n ]\n\n @property({ type: Object }) input?: any\n @property({ type: Object }) output?: any\n\n @state() dataOoc?: any\n\n @query('textarea') instructionTextArea!: HTMLTextAreaElement\n\n render() {\n const instruction = this.output?.instruction\n\n return html`\n <div content>\n <ox-data-sample-view .dataSample=${this.dataOoc}></ox-data-sample-view>\n </div>\n\n <label instruction>\n <div><mwc-icon>build_circle</mwc-icon> <span>corrective instruction</span></div>\n <textarea\n placeholder=\"시정 및 예방을 위한 조치 지시 사항을 입력해주세요.\"\n .value=${instruction || ''}\n @change=${this.onChangeInstruction}\n ></textarea>\n </label>\n `\n }\n\n onChangeInstruction(e: Event) {\n this.output ||= {}\n this.output.instruction = (e.target as HTMLTextAreaElement).value\n\n this.dispatchEvent(\n new CustomEvent('change', {\n detail: this.output\n })\n )\n }\n\n updated(changes) {\n if (changes.has('input')) {\n this.fetchDataOoc()\n }\n }\n\n async fetchDataOoc() {\n const id = this.input?.dataOocId\n\n if (id) {\n const response = await client.query({\n query: gql`\n query ($id: String!) {\n dataOoc(id: $id) {\n id\n name\n description\n ooc\n oos\n state\n type\n useCase\n data\n judgment\n dataItems {\n name\n description\n active\n tag\n type\n unit\n options\n quota\n spec\n }\n workDate\n workShift\n collectedAt\n }\n }\n `,\n variables: {\n id\n }\n })\n\n this.dataOoc = response.data.dataOoc\n }\n }\n}\n"]}
|
@@ -1,12 +0,0 @@
|
|
1
|
-
import '@operato/input/ox-input-file.js';
|
2
|
-
import { LitElement } from 'lit';
|
3
|
-
import { DataSet } from '@operato/dataset';
|
4
|
-
export declare class OxDataEntryView extends LitElement {
|
5
|
-
static styles: import("lit").CSSResult;
|
6
|
-
dataSet?: DataSet;
|
7
|
-
value?: {
|
8
|
-
[tag: string]: any;
|
9
|
-
};
|
10
|
-
render(): import("lit-html").TemplateResult<1>;
|
11
|
-
private buildEntryViews;
|
12
|
-
}
|
@@ -1,181 +0,0 @@
|
|
1
|
-
import { __decorate, __metadata } from "tslib";
|
2
|
-
import '@operato/input/ox-input-file.js';
|
3
|
-
import { css, html, LitElement } from 'lit';
|
4
|
-
import { customElement, property } from 'lit/decorators.js';
|
5
|
-
let OxDataEntryView = class OxDataEntryView extends LitElement {
|
6
|
-
render() {
|
7
|
-
var _a, _b;
|
8
|
-
return html `<form>
|
9
|
-
<h2>${((_a = this.dataSet) === null || _a === void 0 ? void 0 : _a.name) || ''}</h2>
|
10
|
-
<h3>${((_b = this.dataSet) === null || _b === void 0 ? void 0 : _b.description) || ''}</h3>
|
11
|
-
${this.buildEntryViews()}
|
12
|
-
</form> `;
|
13
|
-
}
|
14
|
-
buildEntryViews() {
|
15
|
-
var _a;
|
16
|
-
const dataItems = (_a = this.dataSet) === null || _a === void 0 ? void 0 : _a.dataItems.filter(item => item.active);
|
17
|
-
return (dataItems || []).map(dataItem => {
|
18
|
-
const { name, description, tag, type, quota = 1, options = {}, unit } = dataItem;
|
19
|
-
const samples = new Array(quota).fill(0);
|
20
|
-
const value = this.value && this.value[tag];
|
21
|
-
const elements = samples.map((_, idx) => {
|
22
|
-
const v = value instanceof Array ? value[idx] : idx === 0 ? value : undefined;
|
23
|
-
switch (type) {
|
24
|
-
case 'select':
|
25
|
-
return html ` <select .name=${tag} disabled>
|
26
|
-
<option value=""></option>
|
27
|
-
${(options.options || []).map(option => html `<option value=${option.value} ?selected=${option.value === v}>${option.text}</option>`)}
|
28
|
-
</select>`;
|
29
|
-
break;
|
30
|
-
case 'boolean':
|
31
|
-
return html ` <input type="checkbox" name=${tag} .checked=${v} disabled />`;
|
32
|
-
break;
|
33
|
-
case 'number':
|
34
|
-
return html ` <input type="number" name=${tag} value=${v} disabled />`;
|
35
|
-
break;
|
36
|
-
case 'file':
|
37
|
-
return html `<ox-input-file
|
38
|
-
name=${tag}
|
39
|
-
label="Attach Files"
|
40
|
-
accept="*/*"
|
41
|
-
multiple="true"
|
42
|
-
hide-filelist
|
43
|
-
disabled
|
44
|
-
></ox-input-file>`;
|
45
|
-
case 'string':
|
46
|
-
default:
|
47
|
-
return html ` <input type="text" name=${tag} value=${v} disabled />`;
|
48
|
-
}
|
49
|
-
});
|
50
|
-
return html ` <label .title=${description}>
|
51
|
-
<div name>${name}${unit ? `(${unit})` : ''}</div>
|
52
|
-
<div description><mwc-icon>info_outline</mwc-icon> ${description}</div>
|
53
|
-
<div elements>${elements}</div>
|
54
|
-
</label>`;
|
55
|
-
});
|
56
|
-
}
|
57
|
-
};
|
58
|
-
OxDataEntryView.styles = css `
|
59
|
-
:host {
|
60
|
-
display: flex;
|
61
|
-
flex-direction: row;
|
62
|
-
|
63
|
-
--item-description-font: normal 0.8rem/1rem var(--theme-font);
|
64
|
-
--item-description-color: var(--page-description-color);
|
65
|
-
}
|
66
|
-
|
67
|
-
h2 {
|
68
|
-
margin: var(--title-margin);
|
69
|
-
font: var(--title-font);
|
70
|
-
color: var(--title-text-color);
|
71
|
-
text-transform: capitalize;
|
72
|
-
text-align: center;
|
73
|
-
}
|
74
|
-
h3 {
|
75
|
-
margin: var(--page-description-margin);
|
76
|
-
font: var(--page-description-font);
|
77
|
-
color: var(--page-description-color);
|
78
|
-
text-transform: capitalize;
|
79
|
-
text-align: center;
|
80
|
-
}
|
81
|
-
|
82
|
-
form {
|
83
|
-
flex: 1;
|
84
|
-
|
85
|
-
display: flex;
|
86
|
-
flex-direction: column;
|
87
|
-
}
|
88
|
-
|
89
|
-
label {
|
90
|
-
display: grid;
|
91
|
-
|
92
|
-
grid-template-rows: auto 1fr;
|
93
|
-
grid-template-columns: 1fr 5fr;
|
94
|
-
grid-template-areas: 'name description' 'empty inputs';
|
95
|
-
|
96
|
-
grid-gap: 9px;
|
97
|
-
align-items: center;
|
98
|
-
margin-bottom: var(--margin-default);
|
99
|
-
}
|
100
|
-
|
101
|
-
label:nth-child(odd) {
|
102
|
-
background-color: var(--main-section-background-color);
|
103
|
-
padding: var(--padding-default) 0;
|
104
|
-
}
|
105
|
-
|
106
|
-
div[name] {
|
107
|
-
grid-area: name;
|
108
|
-
font: var(--label-font);
|
109
|
-
color: var(--label-color);
|
110
|
-
text-align: right;
|
111
|
-
}
|
112
|
-
|
113
|
-
div[description] {
|
114
|
-
grid-area: description;
|
115
|
-
opacity: 0.7;
|
116
|
-
font: var(--item-description-font);
|
117
|
-
color: var(--item-description-color);
|
118
|
-
text-align: left;
|
119
|
-
}
|
120
|
-
|
121
|
-
div[description] * {
|
122
|
-
vertical-align: middle;
|
123
|
-
}
|
124
|
-
|
125
|
-
div[description] mwc-icon {
|
126
|
-
margin-top: -3px;
|
127
|
-
font-size: 0.9rem;
|
128
|
-
}
|
129
|
-
|
130
|
-
div[elements] {
|
131
|
-
grid-area: inputs;
|
132
|
-
display: flex;
|
133
|
-
flex-direction: row;
|
134
|
-
flex-wrap: wrap;
|
135
|
-
gap: 10px;
|
136
|
-
padding-right: var(--padding-default);
|
137
|
-
}
|
138
|
-
|
139
|
-
div[elements] * {
|
140
|
-
flex: 1;
|
141
|
-
}
|
142
|
-
|
143
|
-
div[elements] input,
|
144
|
-
div[elements] select {
|
145
|
-
border: var(--input-field-border);
|
146
|
-
border-radius: var(--input-field-border-radius);
|
147
|
-
padding: var(--input-field-padding);
|
148
|
-
font: var(--input-field-font);
|
149
|
-
}
|
150
|
-
|
151
|
-
@media only screen and (max-width: 460px) {
|
152
|
-
label {
|
153
|
-
display: grid;
|
154
|
-
|
155
|
-
grid-template-rows: auto auto 1fr;
|
156
|
-
grid-template-columns: 1fr;
|
157
|
-
grid-template-areas: 'name' 'description' 'inputs';
|
158
|
-
|
159
|
-
grid-gap: 9px;
|
160
|
-
align-items: center;
|
161
|
-
margin-bottom: var(--margin-default);
|
162
|
-
}
|
163
|
-
|
164
|
-
div[name] {
|
165
|
-
text-align: left;
|
166
|
-
}
|
167
|
-
}
|
168
|
-
`;
|
169
|
-
__decorate([
|
170
|
-
property({ type: Object }),
|
171
|
-
__metadata("design:type", Object)
|
172
|
-
], OxDataEntryView.prototype, "dataSet", void 0);
|
173
|
-
__decorate([
|
174
|
-
property({ type: Object }),
|
175
|
-
__metadata("design:type", Object)
|
176
|
-
], OxDataEntryView.prototype, "value", void 0);
|
177
|
-
OxDataEntryView = __decorate([
|
178
|
-
customElement('ox-data-entry-view')
|
179
|
-
], OxDataEntryView);
|
180
|
-
export { OxDataEntryView };
|
181
|
-
//# sourceMappingURL=ox-data-entry-view.js.map
|
@@ -1 +0,0 @@
|
|
1
|
-
{"version":3,"file":"ox-data-entry-view.js","sourceRoot":"","sources":["../../client/components/ox-data-entry-view.ts"],"names":[],"mappings":"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","sourcesContent":["import '@operato/input/ox-input-file.js'\n\nimport { css, html, LitElement } from 'lit'\nimport { customElement, property } from 'lit/decorators.js'\n\nimport { DataSet } from '@operato/dataset'\n\n@customElement('ox-data-entry-view')\nexport class OxDataEntryView extends LitElement {\n static styles = css`\n :host {\n display: flex;\n flex-direction: row;\n\n --item-description-font: normal 0.8rem/1rem var(--theme-font);\n --item-description-color: var(--page-description-color);\n }\n\n h2 {\n margin: var(--title-margin);\n font: var(--title-font);\n color: var(--title-text-color);\n text-transform: capitalize;\n text-align: center;\n }\n h3 {\n margin: var(--page-description-margin);\n font: var(--page-description-font);\n color: var(--page-description-color);\n text-transform: capitalize;\n text-align: center;\n }\n\n form {\n flex: 1;\n\n display: flex;\n flex-direction: column;\n }\n\n label {\n display: grid;\n\n grid-template-rows: auto 1fr;\n grid-template-columns: 1fr 5fr;\n grid-template-areas: 'name description' 'empty inputs';\n\n grid-gap: 9px;\n align-items: center;\n margin-bottom: var(--margin-default);\n }\n\n label:nth-child(odd) {\n background-color: var(--main-section-background-color);\n padding: var(--padding-default) 0;\n }\n\n div[name] {\n grid-area: name;\n font: var(--label-font);\n color: var(--label-color);\n text-align: right;\n }\n\n div[description] {\n grid-area: description;\n opacity: 0.7;\n font: var(--item-description-font);\n color: var(--item-description-color);\n text-align: left;\n }\n\n div[description] * {\n vertical-align: middle;\n }\n\n div[description] mwc-icon {\n margin-top: -3px;\n font-size: 0.9rem;\n }\n\n div[elements] {\n grid-area: inputs;\n display: flex;\n flex-direction: row;\n flex-wrap: wrap;\n gap: 10px;\n padding-right: var(--padding-default);\n }\n\n div[elements] * {\n flex: 1;\n }\n\n div[elements] input,\n div[elements] select {\n border: var(--input-field-border);\n border-radius: var(--input-field-border-radius);\n padding: var(--input-field-padding);\n font: var(--input-field-font);\n }\n\n @media only screen and (max-width: 460px) {\n label {\n display: grid;\n\n grid-template-rows: auto auto 1fr;\n grid-template-columns: 1fr;\n grid-template-areas: 'name' 'description' 'inputs';\n\n grid-gap: 9px;\n align-items: center;\n margin-bottom: var(--margin-default);\n }\n\n div[name] {\n text-align: left;\n }\n }\n `\n\n @property({ type: Object }) dataSet?: DataSet\n @property({ type: Object }) value?: { [tag: string]: any }\n\n render() {\n return html`<form>\n <h2>${this.dataSet?.name || ''}</h2>\n <h3>${this.dataSet?.description || ''}</h3>\n ${this.buildEntryViews()}\n </form> `\n }\n\n private buildEntryViews() {\n const dataItems = this.dataSet?.dataItems.filter(item => item.active)\n\n return (dataItems || []).map(dataItem => {\n const { name, description, tag, type, quota = 1, options = {}, unit } = dataItem\n\n const samples = new Array(quota).fill(0)\n const value = this.value && this.value[tag]\n\n const elements = samples.map((_, idx) => {\n const v = value instanceof Array ? value[idx] : idx === 0 ? value : undefined\n\n switch (type) {\n case 'select':\n return html` <select .name=${tag} disabled>\n <option value=\"\"></option>\n ${(options.options || []).map(\n option => html`<option value=${option.value} ?selected=${option.value === v}>${option.text}</option>`\n )}\n </select>`\n break\n\n case 'boolean':\n return html` <input type=\"checkbox\" name=${tag} .checked=${v} disabled />`\n break\n\n case 'number':\n return html` <input type=\"number\" name=${tag} value=${v} disabled />`\n break\n\n case 'file':\n return html`<ox-input-file\n name=${tag}\n label=\"Attach Files\"\n accept=\"*/*\"\n multiple=\"true\"\n hide-filelist\n disabled\n ></ox-input-file>`\n\n case 'string':\n default:\n return html` <input type=\"text\" name=${tag} value=${v} disabled />`\n }\n })\n\n return html` <label .title=${description}>\n <div name>${name}${unit ? `(${unit})` : ''}</div>\n <div description><mwc-icon>info_outline</mwc-icon> ${description}</div>\n <div elements>${elements}</div>\n </label>`\n })\n }\n}\n"]}
|
@@ -1,82 +0,0 @@
|
|
1
|
-
"use strict";
|
2
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
3
|
-
exports.ActivityDataCollect = void 0;
|
4
|
-
const worklist_1 = require("@things-factory/worklist");
|
5
|
-
const create_data_sample_1 = require("../../controllers/create-data-sample");
|
6
|
-
async function callback(activityInstance, context) {
|
7
|
-
const { domain, tx } = context.state;
|
8
|
-
const { input, output, state } = activityInstance;
|
9
|
-
if (state == worklist_1.ActivityInstanceStatus.Ended) {
|
10
|
-
const activity = (await tx.getRepository(worklist_1.Activity).findOneBy({
|
11
|
-
domain: { id: domain.id },
|
12
|
-
name: 'Collect Data'
|
13
|
-
}));
|
14
|
-
/* collect-data 액티비티는 한명의 assignee(thread)만 수행하도록 한다. 따라서, output 중에서 샘플 한개만을 data로 취한다. */
|
15
|
-
const assignees = Object.keys(output);
|
16
|
-
const data = assignees.length > 0 && output[assignees[0]];
|
17
|
-
if (activity) {
|
18
|
-
const dataSample = {
|
19
|
-
dataSet: {
|
20
|
-
id: input.dataSetId
|
21
|
-
},
|
22
|
-
data
|
23
|
-
};
|
24
|
-
await (0, create_data_sample_1.createDataSample)(dataSample, context);
|
25
|
-
}
|
26
|
-
else {
|
27
|
-
console.error('Collect Data Activity not installed.');
|
28
|
-
}
|
29
|
-
}
|
30
|
-
}
|
31
|
-
exports.ActivityDataCollect = {
|
32
|
-
name: 'Collect Data',
|
33
|
-
description: 'Tasks assigned for data collection',
|
34
|
-
release: '1.0.0',
|
35
|
-
provider: 'hatiolab.com',
|
36
|
-
category: 'quality',
|
37
|
-
activityType: 'user',
|
38
|
-
searchKeys: [
|
39
|
-
{
|
40
|
-
name: 'dataSetName',
|
41
|
-
description: 'DataSet name',
|
42
|
-
inputKey: 'dataSetName',
|
43
|
-
tKey: 'data-set-name'
|
44
|
-
}
|
45
|
-
],
|
46
|
-
startable: true,
|
47
|
-
model: [
|
48
|
-
{
|
49
|
-
name: 'dataSetId',
|
50
|
-
description: 'DataSet Id.',
|
51
|
-
tag: 'dataSetId',
|
52
|
-
hidden: true,
|
53
|
-
mandatory: true,
|
54
|
-
inout: 'in',
|
55
|
-
type: 'string',
|
56
|
-
options: {},
|
57
|
-
unit: null,
|
58
|
-
quantifier: [1],
|
59
|
-
spec: {}
|
60
|
-
},
|
61
|
-
{
|
62
|
-
name: 'dataSetName',
|
63
|
-
description: 'DataSet name',
|
64
|
-
tag: 'dataSetName',
|
65
|
-
hidden: true,
|
66
|
-
mandatory: true,
|
67
|
-
inout: 'in',
|
68
|
-
type: 'string',
|
69
|
-
options: {},
|
70
|
-
unit: null,
|
71
|
-
quantifier: [1],
|
72
|
-
spec: {}
|
73
|
-
}
|
74
|
-
],
|
75
|
-
uiType: 'custom-element',
|
76
|
-
uiSource: 'data-collect-activity-view',
|
77
|
-
reportType: 'page',
|
78
|
-
reportSource: 'data-collect-activity-view',
|
79
|
-
thumbnail: '/assets/images/data-collect.png',
|
80
|
-
callback /* Called when there is a change in the lifecycle of a task (activity-instance). */
|
81
|
-
};
|
82
|
-
//# sourceMappingURL=activity-data-collect.js.map
|
@@ -1 +0,0 @@
|
|
1
|
-
{"version":3,"file":"activity-data-collect.js","sourceRoot":"","sources":["../../../server/controllers/activity-template/activity-data-collect.ts"],"names":[],"mappings":";;;AACA,uDAA6F;AAE7F,6EAAuE;AAEvE,KAAK,UAAU,QAAQ,CAAC,gBAAkC,EAAE,OAAwB;IAClF,MAAM,EAAE,MAAM,EAAE,EAAE,EAAE,GAAG,OAAO,CAAC,KAAK,CAAA;IACpC,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,KAAK,EAAE,GAAG,gBAAgB,CAAA;IAEjD,IAAI,KAAK,IAAI,iCAAsB,CAAC,KAAK,EAAE;QACzC,MAAM,QAAQ,GAAG,CAAC,MAAM,EAAE,CAAC,aAAa,CAAC,mBAAQ,CAAC,CAAC,SAAS,CAAC;YAC3D,MAAM,EAAE,EAAE,EAAE,EAAE,MAAM,CAAC,EAAE,EAAE;YACzB,IAAI,EAAE,cAAc;SACrB,CAAC,CAAa,CAAA;QAEf,2FAA2F;QAC3F,MAAM,SAAS,GAAG,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,CAAA;QACrC,MAAM,IAAI,GAAG,SAAS,CAAC,MAAM,GAAG,CAAC,IAAI,MAAM,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,CAAA;QAEzD,IAAI,QAAQ,EAAE;YACZ,MAAM,UAAU,GAAkB;gBAChC,OAAO,EAAE;oBACP,EAAE,EAAE,KAAK,CAAC,SAAS;iBACpB;gBACD,IAAI;aACL,CAAA;YAED,MAAM,IAAA,qCAAgB,EAAC,UAAU,EAAE,OAAO,CAAC,CAAA;SAC5C;aAAM;YACL,OAAO,CAAC,KAAK,CAAC,sCAAsC,CAAC,CAAA;SACtD;KACF;AACH,CAAC;AAEY,QAAA,mBAAmB,GAAG;IACjC,IAAI,EAAE,cAAc;IACpB,WAAW,EAAE,oCAAoC;IACjD,OAAO,EAAE,OAAO;IAChB,QAAQ,EAAE,cAAc;IACxB,QAAQ,EAAE,SAAS;IACnB,YAAY,EAAE,MAAM;IACpB,UAAU,EAAE;QACV;YACE,IAAI,EAAE,aAAa;YACnB,WAAW,EAAE,cAAc;YAC3B,QAAQ,EAAE,aAAa;YACvB,IAAI,EAAE,eAAe;SACtB;KACF;IACD,SAAS,EAAE,IAAI;IACf,KAAK,EAAE;QACL;YACE,IAAI,EAAE,WAAW;YACjB,WAAW,EAAE,aAAa;YAC1B,GAAG,EAAE,WAAW;YAChB,MAAM,EAAE,IAAI;YACZ,SAAS,EAAE,IAAI;YACf,KAAK,EAAE,IAAI;YACX,IAAI,EAAE,QAAQ;YACd,OAAO,EAAE,EAAE;YACX,IAAI,EAAE,IAAI;YACV,UAAU,EAAE,CAAC,CAAC,CAAC;YACf,IAAI,EAAE,EAAE;SACT;QACD;YACE,IAAI,EAAE,aAAa;YACnB,WAAW,EAAE,cAAc;YAC3B,GAAG,EAAE,aAAa;YAClB,MAAM,EAAE,IAAI;YACZ,SAAS,EAAE,IAAI;YACf,KAAK,EAAE,IAAI;YACX,IAAI,EAAE,QAAQ;YACd,OAAO,EAAE,EAAE;YACX,IAAI,EAAE,IAAI;YACV,UAAU,EAAE,CAAC,CAAC,CAAC;YACf,IAAI,EAAE,EAAE;SACT;KACF;IACD,MAAM,EAAE,gBAAgB;IACxB,QAAQ,EAAE,4BAA4B;IACtC,UAAU,EAAE,MAAM;IAClB,YAAY,EAAE,4BAA4B;IAC1C,SAAS,EAAE,iCAAiC;IAC5C,QAAQ,CAAC,mFAAmF;CAC7F,CAAA","sourcesContent":["import { Domain } from '@things-factory/shell'\nimport { Activity, ActivityInstance, ActivityInstanceStatus } from '@things-factory/worklist'\nimport { NewDataSample } from 'service/data-sample/data-sample-type'\nimport { createDataSample } from '../../controllers/create-data-sample'\n\nasync function callback(activityInstance: ActivityInstance, context: ResolverContext) {\n const { domain, tx } = context.state\n const { input, output, state } = activityInstance\n\n if (state == ActivityInstanceStatus.Ended) {\n const activity = (await tx.getRepository(Activity).findOneBy({\n domain: { id: domain.id },\n name: 'Collect Data'\n })) as Activity\n\n /* collect-data 액티비티는 한명의 assignee(thread)만 수행하도록 한다. 따라서, output 중에서 샘플 한개만을 data로 취한다. */\n const assignees = Object.keys(output)\n const data = assignees.length > 0 && output[assignees[0]]\n\n if (activity) {\n const dataSample: NewDataSample = {\n dataSet: {\n id: input.dataSetId\n },\n data\n }\n\n await createDataSample(dataSample, context)\n } else {\n console.error('Collect Data Activity not installed.')\n }\n }\n}\n\nexport const ActivityDataCollect = {\n name: 'Collect Data',\n description: 'Tasks assigned for data collection',\n release: '1.0.0',\n provider: 'hatiolab.com',\n category: 'quality',\n activityType: 'user',\n searchKeys: [\n {\n name: 'dataSetName',\n description: 'DataSet name',\n inputKey: 'dataSetName',\n tKey: 'data-set-name'\n }\n ],\n startable: true,\n model: [\n {\n name: 'dataSetId',\n description: 'DataSet Id.',\n tag: 'dataSetId',\n hidden: true,\n mandatory: true,\n inout: 'in',\n type: 'string',\n options: {},\n unit: null,\n quantifier: [1],\n spec: {}\n },\n {\n name: 'dataSetName',\n description: 'DataSet name',\n tag: 'dataSetName',\n hidden: true,\n mandatory: true,\n inout: 'in',\n type: 'string',\n options: {},\n unit: null,\n quantifier: [1],\n spec: {}\n }\n ],\n uiType: 'custom-element',\n uiSource: 'data-collect-activity-view',\n reportType: 'page',\n reportSource: 'data-collect-activity-view',\n thumbnail: '/assets/images/data-collect.png',\n callback /* Called when there is a change in the lifecycle of a task (activity-instance). */\n}\n"]}
|
@@ -1,100 +0,0 @@
|
|
1
|
-
"use strict";
|
2
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
3
|
-
exports.ActivityOocResolve = void 0;
|
4
|
-
const worklist_1 = require("@things-factory/worklist");
|
5
|
-
const data_ooc_1 = require("../../service/data-ooc/data-ooc");
|
6
|
-
async function callback(activityInstance, context) {
|
7
|
-
var _a;
|
8
|
-
const { tx, user, domain } = context.state;
|
9
|
-
const { id, input, output, state, terminatedAt } = activityInstance;
|
10
|
-
/* Resolve Activity가 완료되면, 해당 data-ooc 엔티티의 correctiveAction, correctorId, correctedAt 을 update한다. */
|
11
|
-
if (state == worklist_1.ActivityInstanceStatus.Ended) {
|
12
|
-
const activityThreads = await tx.getRepository(worklist_1.ActivityThread).find({
|
13
|
-
where: {
|
14
|
-
domain: { id: domain.id },
|
15
|
-
activityInstance: { id },
|
16
|
-
state: worklist_1.ActivityThreadStatus.Ended
|
17
|
-
},
|
18
|
-
relations: ['assignee']
|
19
|
-
});
|
20
|
-
const corrector = (_a = activityThreads[0]) === null || _a === void 0 ? void 0 : _a.assignee;
|
21
|
-
const { dataOocId } = input;
|
22
|
-
const correctiveAction = Object.values(output)
|
23
|
-
.map((o) => o.action)
|
24
|
-
.join('\n');
|
25
|
-
var dataOoc = await tx.getRepository(data_ooc_1.DataOoc).findOne({
|
26
|
-
where: {
|
27
|
-
domain: { id: domain.id },
|
28
|
-
id: dataOocId
|
29
|
-
},
|
30
|
-
relations: ['dataSet']
|
31
|
-
});
|
32
|
-
/* dataOoc Review 결과를 dataOoc 엔티티에 반영한다. */
|
33
|
-
dataOoc = await tx.getRepository(data_ooc_1.DataOoc).save(Object.assign(Object.assign({}, dataOoc), { correctedAt: terminatedAt, corrector: corrector, correctiveAction, updater: user, state: data_ooc_1.DataOocStatus.CORRECTED }));
|
34
|
-
}
|
35
|
-
}
|
36
|
-
exports.ActivityOocResolve = {
|
37
|
-
name: 'OOC Resolve',
|
38
|
-
description: 'Task to take remedial action based on Out Of Control data',
|
39
|
-
release: '1.0.0',
|
40
|
-
provider: 'hatiolab.com',
|
41
|
-
category: 'quality',
|
42
|
-
activityType: 'user',
|
43
|
-
searchKeys: [
|
44
|
-
{
|
45
|
-
name: 'dataOocId',
|
46
|
-
description: 'OOC Id.',
|
47
|
-
inputKey: 'dataOocId',
|
48
|
-
tKey: 'data-ooc-id'
|
49
|
-
}
|
50
|
-
],
|
51
|
-
startable: true,
|
52
|
-
model: [
|
53
|
-
{
|
54
|
-
name: 'dataOocId',
|
55
|
-
description: 'OOC id',
|
56
|
-
tag: 'dataOocId',
|
57
|
-
hidden: true,
|
58
|
-
mandatory: true,
|
59
|
-
inout: 'in',
|
60
|
-
type: 'string',
|
61
|
-
options: {},
|
62
|
-
unit: null,
|
63
|
-
quantifier: [1],
|
64
|
-
spec: {}
|
65
|
-
},
|
66
|
-
{
|
67
|
-
name: 'instruction',
|
68
|
-
description: 'Instructions for resolving OOC',
|
69
|
-
tag: 'instruction',
|
70
|
-
hidden: false,
|
71
|
-
mandatory: true,
|
72
|
-
inout: 'in',
|
73
|
-
type: 'textarea',
|
74
|
-
options: {},
|
75
|
-
unit: null,
|
76
|
-
quantifier: [1],
|
77
|
-
spec: {}
|
78
|
-
},
|
79
|
-
{
|
80
|
-
name: 'action',
|
81
|
-
description: 'Action Description',
|
82
|
-
tag: 'action',
|
83
|
-
hidden: false,
|
84
|
-
mandatory: true,
|
85
|
-
inout: 'out',
|
86
|
-
type: 'textarea',
|
87
|
-
options: {},
|
88
|
-
unit: null,
|
89
|
-
quantifier: [1],
|
90
|
-
spec: {}
|
91
|
-
}
|
92
|
-
],
|
93
|
-
uiType: 'custom-element',
|
94
|
-
uiSource: 'ooc-resolve-activity-view',
|
95
|
-
reportType: 'page',
|
96
|
-
reportSource: 'data-ooc-report-page',
|
97
|
-
thumbnail: '/assets/images/ooc.png',
|
98
|
-
callback /* Called when there is a change in the lifecycle of a task (activity-instance). */
|
99
|
-
};
|
100
|
-
//# sourceMappingURL=activity-ooc-resolve.js.map
|
@@ -1 +0,0 @@
|
|
1
|
-
{"version":3,"file":"activity-ooc-resolve.js","sourceRoot":"","sources":["../../../server/controllers/activity-template/activity-ooc-resolve.ts"],"names":[],"mappings":"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","sourcesContent":["import {\n ActivityInstance,\n ActivityInstanceStatus,\n ActivityThread,\n ActivityThreadStatus\n} from '@things-factory/worklist'\nimport { DataOoc, DataOocStatus } from '../../service/data-ooc/data-ooc'\n\nasync function callback(activityInstance: ActivityInstance, context: ResolverContext) {\n const { tx, user, domain } = context.state\n const { id, input, output, state, terminatedAt } = activityInstance\n\n /* Resolve Activity가 완료되면, 해당 data-ooc 엔티티의 correctiveAction, correctorId, correctedAt 을 update한다. */\n if (state == ActivityInstanceStatus.Ended) {\n const activityThreads = await tx.getRepository(ActivityThread).find({\n where: {\n domain: { id: domain.id },\n activityInstance: { id },\n state: ActivityThreadStatus.Ended\n },\n relations: ['assignee']\n })\n\n const corrector = activityThreads[0]?.assignee\n\n const { dataOocId } = input\n const correctiveAction = Object.values(output)\n .map((o: any) => o.action)\n .join('\\n')\n\n var dataOoc = await tx.getRepository(DataOoc).findOne({\n where: {\n domain: { id: domain.id },\n id: dataOocId\n },\n relations: ['dataSet']\n })\n\n /* dataOoc Review 결과를 dataOoc 엔티티에 반영한다. */\n dataOoc = await tx.getRepository(DataOoc).save({\n ...dataOoc,\n correctedAt: terminatedAt,\n corrector: corrector,\n correctiveAction,\n updater: user,\n state: DataOocStatus.CORRECTED\n })\n }\n}\n\nexport const ActivityOocResolve = {\n name: 'OOC Resolve',\n description: 'Task to take remedial action based on Out Of Control data',\n release: '1.0.0',\n provider: 'hatiolab.com',\n category: 'quality',\n activityType: 'user',\n searchKeys: [\n {\n name: 'dataOocId',\n description: 'OOC Id.',\n inputKey: 'dataOocId',\n tKey: 'data-ooc-id'\n }\n ],\n startable: true,\n model: [\n {\n name: 'dataOocId',\n description: 'OOC id',\n tag: 'dataOocId',\n hidden: true,\n mandatory: true,\n inout: 'in',\n type: 'string',\n options: {},\n unit: null,\n quantifier: [1],\n spec: {}\n },\n {\n name: 'instruction',\n description: 'Instructions for resolving OOC',\n tag: 'instruction',\n hidden: false,\n mandatory: true,\n inout: 'in',\n type: 'textarea',\n options: {},\n unit: null,\n quantifier: [1],\n spec: {}\n },\n {\n name: 'action',\n description: 'Action Description',\n tag: 'action',\n hidden: false,\n mandatory: true,\n inout: 'out',\n type: 'textarea',\n options: {},\n unit: null,\n quantifier: [1],\n spec: {}\n }\n ],\n uiType: 'custom-element',\n uiSource: 'ooc-resolve-activity-view',\n reportType: 'page',\n reportSource: 'data-ooc-report-page',\n thumbnail: '/assets/images/ooc.png',\n callback /* Called when there is a change in the lifecycle of a task (activity-instance). */\n}\n"]}
|
@@ -1,107 +0,0 @@
|
|
1
|
-
"use strict";
|
2
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
3
|
-
exports.ActivityOocReview = void 0;
|
4
|
-
const worklist_1 = require("@things-factory/worklist");
|
5
|
-
const post_1 = require("@things-factory/worklist/dist-server/controllers/activity-instance/post");
|
6
|
-
const data_ooc_1 = require("../../service/data-ooc/data-ooc");
|
7
|
-
async function callback(activityInstance, context) {
|
8
|
-
const { domain, user, tx } = context.state;
|
9
|
-
const { input, output, state, terminatedAt } = activityInstance;
|
10
|
-
if (state == worklist_1.ActivityInstanceStatus.Ended) {
|
11
|
-
const activity = (await tx.getRepository(worklist_1.Activity).findOneBy({
|
12
|
-
domain: { id: domain.id },
|
13
|
-
name: 'OOC Resolve'
|
14
|
-
}));
|
15
|
-
if (activity) {
|
16
|
-
const { dataOocId } = input;
|
17
|
-
const correctiveInstruction = Object.values(output)
|
18
|
-
.map((o) => o.instruction)
|
19
|
-
.join('\n');
|
20
|
-
var dataOoc = await tx.getRepository(data_ooc_1.DataOoc).findOne({
|
21
|
-
where: {
|
22
|
-
domain: { id: domain.id },
|
23
|
-
id: dataOocId
|
24
|
-
},
|
25
|
-
relations: ['dataSet']
|
26
|
-
});
|
27
|
-
const dataSet = dataOoc.dataSet;
|
28
|
-
const { assignees, approvalLine } = dataSet;
|
29
|
-
/* dataOoc Review 결과를 dataOoc 엔티티에 반영한다. */
|
30
|
-
dataOoc = await tx.getRepository(data_ooc_1.DataOoc).save(Object.assign(Object.assign({}, dataOoc), { reviewedAt: terminatedAt, reviewer: user, correctiveInstruction, state: data_ooc_1.DataOocStatus.REVIEWED }));
|
31
|
-
/* 해당 dataset의 작업 담당자(assignees)에게 OOC 해결을 위한 태스크를 지시한다. */
|
32
|
-
if (assignees && assignees instanceof Array && assignees.length > 0) {
|
33
|
-
const activityInstance = {
|
34
|
-
name: `[OOC 조치] ${dataSet.name}`,
|
35
|
-
activityId: activity.id,
|
36
|
-
description: `Data OOC occurred on '${dataSet.name}'`,
|
37
|
-
dueAt: new Date(terminatedAt.getTime() + 24 * 60 * 60 * 1000),
|
38
|
-
input: {
|
39
|
-
dataOocId,
|
40
|
-
instruction: correctiveInstruction
|
41
|
-
},
|
42
|
-
assignees,
|
43
|
-
approvalLine
|
44
|
-
};
|
45
|
-
await (0, post_1.post)(activityInstance, context);
|
46
|
-
}
|
47
|
-
else {
|
48
|
-
console.error(`Assignees are not set. So, Data OOC Resolve task for ${dataOoc.name}(${dataOoc.id}) could not be posted.`);
|
49
|
-
}
|
50
|
-
}
|
51
|
-
else {
|
52
|
-
console.error('OOC Resolve Activity not installed.');
|
53
|
-
}
|
54
|
-
}
|
55
|
-
}
|
56
|
-
exports.ActivityOocReview = {
|
57
|
-
name: 'OOC Review',
|
58
|
-
description: 'Task to take remedial action based on Out Of Control data',
|
59
|
-
release: '1.0.0',
|
60
|
-
provider: 'hatiolab.com',
|
61
|
-
category: 'quality',
|
62
|
-
activityType: 'user',
|
63
|
-
searchKeys: [
|
64
|
-
{
|
65
|
-
name: 'dataOocId',
|
66
|
-
description: 'OOC Id.',
|
67
|
-
inputKey: 'dataOocId',
|
68
|
-
tKey: 'data-ooc-id'
|
69
|
-
}
|
70
|
-
],
|
71
|
-
startable: true,
|
72
|
-
model: [
|
73
|
-
{
|
74
|
-
name: 'dataOocId',
|
75
|
-
description: 'OOC id',
|
76
|
-
tag: 'dataOocId',
|
77
|
-
hidden: true,
|
78
|
-
mandatory: true,
|
79
|
-
inout: 'in',
|
80
|
-
type: 'string',
|
81
|
-
options: {},
|
82
|
-
unit: null,
|
83
|
-
quantifier: [1],
|
84
|
-
spec: {}
|
85
|
-
},
|
86
|
-
{
|
87
|
-
name: 'Instruction',
|
88
|
-
description: 'Instructions for preventing OOC',
|
89
|
-
tag: 'instruction',
|
90
|
-
hidden: false,
|
91
|
-
mandatory: true,
|
92
|
-
inout: 'out',
|
93
|
-
type: 'textarea',
|
94
|
-
options: {},
|
95
|
-
unit: null,
|
96
|
-
quantifier: [1],
|
97
|
-
spec: {}
|
98
|
-
}
|
99
|
-
],
|
100
|
-
uiType: 'custom-element',
|
101
|
-
uiSource: 'ooc-review-activity-view',
|
102
|
-
reportType: 'page',
|
103
|
-
reportSource: 'data-ooc-report-page',
|
104
|
-
thumbnail: '/assets/images/ooc.png',
|
105
|
-
callback /* Called when there is a change in the lifecycle of a task (activity-instance). */
|
106
|
-
};
|
107
|
-
//# sourceMappingURL=activity-ooc-review.js.map
|
@@ -1 +0,0 @@
|
|
1
|
-
{"version":3,"file":"activity-ooc-review.js","sourceRoot":"","sources":["../../../server/controllers/activity-template/activity-ooc-review.ts"],"names":[],"mappings":"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","sourcesContent":["import { Activity, ActivityInstance, ActivityInstanceStatus } from '@things-factory/worklist'\nimport { post } from '@things-factory/worklist/dist-server/controllers/activity-instance/post'\nimport { DataOoc, DataOocStatus } from '../../service/data-ooc/data-ooc'\n\nasync function callback(activityInstance: ActivityInstance, context: ResolverContext) {\n const { domain, user, tx } = context.state\n const { input, output, state, terminatedAt } = activityInstance\n\n if (state == ActivityInstanceStatus.Ended) {\n const activity = (await tx.getRepository(Activity).findOneBy({\n domain: { id: domain.id },\n name: 'OOC Resolve'\n })) as Activity\n\n if (activity) {\n const { dataOocId } = input\n const correctiveInstruction = Object.values(output)\n .map((o: any) => o.instruction)\n .join('\\n')\n\n var dataOoc = await tx.getRepository(DataOoc).findOne({\n where: {\n domain: { id: domain.id },\n id: dataOocId\n },\n relations: ['dataSet']\n })\n\n const dataSet = dataOoc.dataSet\n const { assignees, approvalLine } = dataSet\n\n /* dataOoc Review 결과를 dataOoc 엔티티에 반영한다. */\n dataOoc = await tx.getRepository(DataOoc).save({\n ...dataOoc,\n reviewedAt: terminatedAt,\n reviewer: user,\n correctiveInstruction,\n state: DataOocStatus.REVIEWED\n })\n\n /* 해당 dataset의 작업 담당자(assignees)에게 OOC 해결을 위한 태스크를 지시한다. */\n if (assignees && assignees instanceof Array && assignees.length > 0) {\n const activityInstance = {\n name: `[OOC 조치] ${dataSet.name}`,\n activityId: activity.id,\n description: `Data OOC occurred on '${dataSet.name}'`,\n dueAt: new Date(terminatedAt.getTime() + 24 * 60 * 60 * 1000),\n input: {\n dataOocId,\n instruction: correctiveInstruction\n },\n assignees,\n approvalLine\n }\n\n await post(activityInstance, context)\n } else {\n console.error(\n `Assignees are not set. So, Data OOC Resolve task for ${dataOoc.name}(${dataOoc.id}) could not be posted.`\n )\n }\n } else {\n console.error('OOC Resolve Activity not installed.')\n }\n }\n}\n\nexport const ActivityOocReview = {\n name: 'OOC Review',\n description: 'Task to take remedial action based on Out Of Control data',\n release: '1.0.0',\n provider: 'hatiolab.com',\n category: 'quality',\n activityType: 'user',\n searchKeys: [\n {\n name: 'dataOocId',\n description: 'OOC Id.',\n inputKey: 'dataOocId',\n tKey: 'data-ooc-id'\n }\n ],\n startable: true,\n model: [\n {\n name: 'dataOocId',\n description: 'OOC id',\n tag: 'dataOocId',\n hidden: true,\n mandatory: true,\n inout: 'in',\n type: 'string',\n options: {},\n unit: null,\n quantifier: [1],\n spec: {}\n },\n {\n name: 'Instruction',\n description: 'Instructions for preventing OOC',\n tag: 'instruction',\n hidden: false,\n mandatory: true,\n inout: 'out',\n type: 'textarea',\n options: {},\n unit: null,\n quantifier: [1],\n spec: {}\n }\n ],\n uiType: 'custom-element',\n uiSource: 'ooc-review-activity-view',\n reportType: 'page',\n reportSource: 'data-ooc-report-page',\n thumbnail: '/assets/images/ooc.png',\n callback /* Called when there is a change in the lifecycle of a task (activity-instance). */\n}\n"]}
|
@@ -1,59 +0,0 @@
|
|
1
|
-
"use strict";
|
2
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
3
|
-
exports.ActivityOoc = void 0;
|
4
|
-
exports.ActivityOoc = {
|
5
|
-
name: 'OOC Review',
|
6
|
-
description: 'Task to take remedial action based on Out Of Control data',
|
7
|
-
release: '1.0.0',
|
8
|
-
provider: 'hatiolab.com',
|
9
|
-
category: 'quality',
|
10
|
-
activityType: 'user',
|
11
|
-
startable: true,
|
12
|
-
model: [
|
13
|
-
{
|
14
|
-
name: 'dataOocId',
|
15
|
-
description: 'OOC id',
|
16
|
-
tag: 'dataOocId',
|
17
|
-
hidden: true,
|
18
|
-
mandatory: true,
|
19
|
-
inout: 'in',
|
20
|
-
type: 'string',
|
21
|
-
options: {},
|
22
|
-
unit: null,
|
23
|
-
quantifier: [1],
|
24
|
-
spec: {}
|
25
|
-
},
|
26
|
-
{
|
27
|
-
name: 'Instruction',
|
28
|
-
description: 'Instructions for preventing OOC',
|
29
|
-
tag: 'instruction',
|
30
|
-
hidden: false,
|
31
|
-
mandatory: true,
|
32
|
-
inout: 'in',
|
33
|
-
type: 'textarea',
|
34
|
-
options: {},
|
35
|
-
unit: null,
|
36
|
-
quantifier: [1],
|
37
|
-
spec: {}
|
38
|
-
},
|
39
|
-
{
|
40
|
-
name: 'action',
|
41
|
-
description: 'Action Description',
|
42
|
-
tag: 'action',
|
43
|
-
hidden: false,
|
44
|
-
mandatory: true,
|
45
|
-
inout: 'out',
|
46
|
-
type: 'textarea',
|
47
|
-
options: {},
|
48
|
-
unit: null,
|
49
|
-
quantifier: [1],
|
50
|
-
spec: {}
|
51
|
-
}
|
52
|
-
],
|
53
|
-
uiType: 'custom-element',
|
54
|
-
uiSource: 'data-ooc-activity-view',
|
55
|
-
reportType: 'page',
|
56
|
-
reportSource: 'data-ooc-report-page',
|
57
|
-
thumbnail: '/assets/images/ooc.png'
|
58
|
-
};
|
59
|
-
//# sourceMappingURL=activity-ooc.js.map
|
@@ -1 +0,0 @@
|
|
1
|
-
{"version":3,"file":"activity-ooc.js","sourceRoot":"","sources":["../../../server/controllers/activity-template/activity-ooc.ts"],"names":[],"mappings":";;;AAAa,QAAA,WAAW,GAAG;IACzB,IAAI,EAAE,YAAY;IAClB,WAAW,EAAE,2DAA2D;IACxE,OAAO,EAAE,OAAO;IAChB,QAAQ,EAAE,cAAc;IACxB,QAAQ,EAAE,SAAS;IACnB,YAAY,EAAE,MAAM;IACpB,SAAS,EAAE,IAAI;IACf,KAAK,EAAE;QACL;YACE,IAAI,EAAE,WAAW;YACjB,WAAW,EAAE,QAAQ;YACrB,GAAG,EAAE,WAAW;YAChB,MAAM,EAAE,IAAI;YACZ,SAAS,EAAE,IAAI;YACf,KAAK,EAAE,IAAI;YACX,IAAI,EAAE,QAAQ;YACd,OAAO,EAAE,EAAE;YACX,IAAI,EAAE,IAAI;YACV,UAAU,EAAE,CAAC,CAAC,CAAC;YACf,IAAI,EAAE,EAAE;SACT;QACD;YACE,IAAI,EAAE,aAAa;YACnB,WAAW,EAAE,iCAAiC;YAC9C,GAAG,EAAE,aAAa;YAClB,MAAM,EAAE,KAAK;YACb,SAAS,EAAE,IAAI;YACf,KAAK,EAAE,IAAI;YACX,IAAI,EAAE,UAAU;YAChB,OAAO,EAAE,EAAE;YACX,IAAI,EAAE,IAAI;YACV,UAAU,EAAE,CAAC,CAAC,CAAC;YACf,IAAI,EAAE,EAAE;SACT;QACD;YACE,IAAI,EAAE,QAAQ;YACd,WAAW,EAAE,oBAAoB;YACjC,GAAG,EAAE,QAAQ;YACb,MAAM,EAAE,KAAK;YACb,SAAS,EAAE,IAAI;YACf,KAAK,EAAE,KAAK;YACZ,IAAI,EAAE,UAAU;YAChB,OAAO,EAAE,EAAE;YACX,IAAI,EAAE,IAAI;YACV,UAAU,EAAE,CAAC,CAAC,CAAC;YACf,IAAI,EAAE,EAAE;SACT;KACF;IACD,MAAM,EAAE,gBAAgB;IACxB,QAAQ,EAAE,wBAAwB;IAClC,UAAU,EAAE,MAAM;IAClB,YAAY,EAAE,sBAAsB;IACpC,SAAS,EAAE,wBAAwB;CACpC,CAAA","sourcesContent":["export const ActivityOoc = {\n name: 'OOC Review',\n description: 'Task to take remedial action based on Out Of Control data',\n release: '1.0.0',\n provider: 'hatiolab.com',\n category: 'quality',\n activityType: 'user',\n startable: true,\n model: [\n {\n name: 'dataOocId',\n description: 'OOC id',\n tag: 'dataOocId',\n hidden: true,\n mandatory: true,\n inout: 'in',\n type: 'string',\n options: {},\n unit: null,\n quantifier: [1],\n spec: {}\n },\n {\n name: 'Instruction',\n description: 'Instructions for preventing OOC',\n tag: 'instruction',\n hidden: false,\n mandatory: true,\n inout: 'in',\n type: 'textarea',\n options: {},\n unit: null,\n quantifier: [1],\n spec: {}\n },\n {\n name: 'action',\n description: 'Action Description',\n tag: 'action',\n hidden: false,\n mandatory: true,\n inout: 'out',\n type: 'textarea',\n options: {},\n unit: null,\n quantifier: [1],\n spec: {}\n }\n ],\n uiType: 'custom-element',\n uiSource: 'data-ooc-activity-view',\n reportType: 'page',\n reportSource: 'data-ooc-report-page',\n thumbnail: '/assets/images/ooc.png'\n}\n"]}
|