@things-factory/organization 8.0.0-beta.9 → 8.0.0

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.
Files changed (94) hide show
  1. package/client/bootstrap.ts +23 -0
  2. package/client/component/approval-line-brief.ts +119 -0
  3. package/client/component/approval-line-items-editor-popup.ts +91 -0
  4. package/client/component/approval-line-items-editor.ts +325 -0
  5. package/client/component/approval-line-selector.ts +235 -0
  6. package/client/component/approval-line-templates-manager.ts +229 -0
  7. package/client/component/approval-line-view.ts +122 -0
  8. package/client/component/assignees-editor-popup.ts +79 -0
  9. package/client/component/assignees-editor.ts +217 -0
  10. package/client/component/assignees-view.ts +55 -0
  11. package/client/component/department-selector.ts +151 -0
  12. package/client/component/department-view.ts +107 -0
  13. package/client/component/index.ts +16 -0
  14. package/client/component/recipients-editor-popup.ts +79 -0
  15. package/client/component/recipients-editor.ts +212 -0
  16. package/client/component/recipients-view.ts +55 -0
  17. package/client/grist-editor/grist-editor-approval-line.ts +70 -0
  18. package/client/grist-editor/grist-editor-assignees.ts +69 -0
  19. package/client/grist-editor/grist-editor-department-object.ts +78 -0
  20. package/client/grist-editor/grist-editor-recipients.ts +69 -0
  21. package/client/grist-editor/grist-renderer-approval-line.ts +13 -0
  22. package/client/grist-editor/grist-renderer-assignees.ts +13 -0
  23. package/client/grist-editor/grist-renderer-department-object.ts +13 -0
  24. package/client/grist-editor/grist-renderer-recipients.ts +13 -0
  25. package/client/index.ts +2 -0
  26. package/client/pages/approval-line/common-approval-line-templates-page.ts +382 -0
  27. package/client/pages/approval-line/my-approval-line-templates-page.ts +385 -0
  28. package/client/pages/department/department-importer.ts +87 -0
  29. package/client/pages/department/department-list-page.ts +450 -0
  30. package/client/pages/department/department-tree-page.ts +379 -0
  31. package/client/pages/employee/employee-importer.ts +87 -0
  32. package/client/pages/employee/employee-list-page.ts +772 -0
  33. package/client/pages/employee/employees-by-department.ts +519 -0
  34. package/client/route.ts +27 -0
  35. package/client/tsconfig.json +13 -0
  36. package/client/types/approval-line.ts +52 -0
  37. package/client/types/contact.ts +51 -0
  38. package/client/types/department.ts +29 -0
  39. package/client/types/employee.ts +50 -0
  40. package/client/types/index.ts +5 -0
  41. package/client/types/org-member.ts +27 -0
  42. package/dist-client/bootstrap.js +1 -8
  43. package/dist-client/bootstrap.js.map +1 -1
  44. package/dist-client/pages/employee/employee-list-page.js +3 -3
  45. package/dist-client/pages/employee/employee-list-page.js.map +1 -1
  46. package/dist-client/pages/employee/employees-by-department.js +2 -2
  47. package/dist-client/pages/employee/employees-by-department.js.map +1 -1
  48. package/dist-client/tsconfig.tsbuildinfo +1 -1
  49. package/dist-server/service/employee/employee-history.d.ts +2 -6
  50. package/dist-server/service/employee/employee-history.js +3 -23
  51. package/dist-server/service/employee/employee-history.js.map +1 -1
  52. package/dist-server/service/employee/employee-query.js +1 -1
  53. package/dist-server/service/employee/employee-query.js.map +1 -1
  54. package/dist-server/service/employee/employee-type.d.ts +5 -13
  55. package/dist-server/service/employee/employee-type.js +7 -39
  56. package/dist-server/service/employee/employee-type.js.map +1 -1
  57. package/dist-server/service/employee/employee.d.ts +2 -6
  58. package/dist-server/service/employee/employee.js +3 -23
  59. package/dist-server/service/employee/employee.js.map +1 -1
  60. package/dist-server/tsconfig.tsbuildinfo +1 -1
  61. package/package.json +12 -12
  62. package/server/controllers/register-employee-as-system-user.ts +136 -0
  63. package/server/index.ts +3 -0
  64. package/server/migrations/1723861013111-seed-organization-codes.ts +127 -0
  65. package/server/migrations/index.ts +9 -0
  66. package/server/routes.ts +26 -0
  67. package/server/service/approval-line/approval-line-item.ts +42 -0
  68. package/server/service/approval-line/approval-line-mutation.ts +394 -0
  69. package/server/service/approval-line/approval-line-query.ts +208 -0
  70. package/server/service/approval-line/approval-line-type.ts +63 -0
  71. package/server/service/approval-line/approval-line.ts +123 -0
  72. package/server/service/approval-line/index.ts +7 -0
  73. package/server/service/department/department-history.ts +141 -0
  74. package/server/service/department/department-mutation.ts +231 -0
  75. package/server/service/department/department-query.ts +131 -0
  76. package/server/service/department/department-type.ts +74 -0
  77. package/server/service/department/department.ts +116 -0
  78. package/server/service/department/event-subscriber.ts +17 -0
  79. package/server/service/department/index.ts +9 -0
  80. package/server/service/employee/employee-history.ts +173 -0
  81. package/server/service/employee/employee-mutation.ts +386 -0
  82. package/server/service/employee/employee-query.ts +172 -0
  83. package/server/service/employee/employee-type.ts +176 -0
  84. package/server/service/employee/employee.ts +177 -0
  85. package/server/service/employee/event-subscriber.ts +17 -0
  86. package/server/service/employee/index.ts +9 -0
  87. package/server/service/index.ts +39 -0
  88. package/server/tsconfig.json +10 -0
  89. package/dist-client/filters-form/filter-department-object.d.ts +0 -3
  90. package/dist-client/filters-form/filter-department-object.js +0 -8
  91. package/dist-client/filters-form/filter-department-object.js.map +0 -1
  92. package/dist-client/filters-form/ox-filter-department-object.d.ts +0 -15
  93. package/dist-client/filters-form/ox-filter-department-object.js +0 -130
  94. package/dist-client/filters-form/ox-filter-department-object.js.map +0 -1
@@ -0,0 +1,23 @@
1
+ import { registerEditor, registerRenderer } from '@operato/data-grist'
2
+
3
+ import { GristRendererDepartmentObject } from './grist-editor/grist-renderer-department-object'
4
+ import { GristEditorDepartmentObject } from './grist-editor/grist-editor-department-object'
5
+ import { GristEditorAssignees } from './grist-editor/grist-editor-assignees'
6
+ import { GristRendererAssignees } from './grist-editor/grist-renderer-assignees'
7
+ import { GristEditorRecipients } from './grist-editor/grist-editor-recipients'
8
+ import { GristRendererRecipients } from './grist-editor/grist-renderer-recipients'
9
+ import { GristEditorApprovalLine } from './grist-editor/grist-editor-approval-line'
10
+ import { GristRendererApprovalLine } from './grist-editor/grist-renderer-approval-line'
11
+
12
+ export default function bootstrap() {
13
+ /* register grist renderer/editor for id */
14
+ registerEditor('department-object', GristEditorDepartmentObject)
15
+ registerEditor('approval-line', GristEditorApprovalLine)
16
+ registerEditor('assignees', GristEditorAssignees)
17
+ registerEditor('recipients', GristEditorRecipients)
18
+
19
+ registerRenderer('department-object', GristRendererDepartmentObject)
20
+ registerRenderer('approval-line', GristRendererApprovalLine)
21
+ registerRenderer('assignees', GristRendererAssignees)
22
+ registerRenderer('recipients', GristRendererRecipients)
23
+ }
@@ -0,0 +1,119 @@
1
+ import { css, html, LitElement, TemplateResult } from 'lit'
2
+ import { customElement, property, query } from 'lit/decorators.js'
3
+
4
+ import { i18next, localize } from '@operato/i18n'
5
+ import { ApprovalLineItem } from '../types/approval-line'
6
+ import { OrgMemberTargetType } from '../types/org-member'
7
+
8
+ @customElement('approval-line-brief')
9
+ export class ApprovalLineBrief extends localize(i18next)(LitElement) {
10
+ static styles = [
11
+ css`
12
+ :host {
13
+ display: block;
14
+ }
15
+
16
+ ol {
17
+ list-style: none;
18
+ margin: 0;
19
+ padding: 0;
20
+ display: flex;
21
+ }
22
+
23
+ li {
24
+ position: relative;
25
+ width: 85px;
26
+ text-align: center;
27
+ color: rgba(255, 255, 255, 0.7);
28
+ }
29
+
30
+ li div {
31
+ text-align: center;
32
+ white-space: nowrap;
33
+ overflow: hidden;
34
+ text-overflow: ellipsis;
35
+ }
36
+
37
+ span:before {
38
+ content: '';
39
+ height: 2px;
40
+ width: 70px;
41
+ display: block;
42
+ position: absolute;
43
+ margin-left: -70px;
44
+ margin-top: 6px;
45
+ background-color: rgba(0, 0, 0, 0.4);
46
+ }
47
+
48
+ span {
49
+ display: block;
50
+ width: 15px;
51
+ height: 15px;
52
+ margin: auto;
53
+ background-color: rgba(0, 0, 0, 0.4);
54
+ border-radius: 50%;
55
+ color: var(--md-sys-color-on-primary);
56
+ line-height: 1.2;
57
+ }
58
+
59
+ [past] span {
60
+ background-color: var(--md-sys-color-surface);
61
+ color: var(--md-sys-color-on-surface);
62
+ }
63
+
64
+ [current] span {
65
+ background-color: #84d600;
66
+ color: var(--md-sys-color-on-primary);
67
+ }
68
+
69
+ [current] {
70
+ font-weight: bold;
71
+ color: var(--md-sys-color-on-primary);
72
+ }
73
+
74
+ [past] span:before,
75
+ [current] span:before {
76
+ background-color: rgba(255, 255, 255, 0.9);
77
+ }
78
+
79
+ li:first-child span:before {
80
+ display: none;
81
+ }
82
+ `
83
+ ]
84
+
85
+ @property({ type: Array }) model: ApprovalLineItem[] = []
86
+ @property({ type: Number }) current: number = -1
87
+
88
+ render() {
89
+ const items = this.model || []
90
+ const current = this.current
91
+
92
+ return html`
93
+ <ol>
94
+ ${this.model
95
+ ? html` <li approver ?current=${this.current <= 0} ?past=${this.current > 0}><span>1</span>ME</li> `
96
+ : html``}
97
+ ${items.map((item, order) => this.renderItem(item, order + 1))}
98
+ </ol>
99
+ `
100
+ }
101
+
102
+ renderItem(item: ApprovalLineItem, order: number): TemplateResult {
103
+ const { type, approver } = item
104
+ const { name } = approver || {
105
+ name: [OrgMemberTargetType.Myself, OrgMemberTargetType.MySupervisor, OrgMemberTargetType.MyDepartment].includes(
106
+ type!
107
+ )
108
+ ? i18next.t(`label.${type}`)
109
+ : ''
110
+ }
111
+
112
+ return html`
113
+ <li approver ?current=${this.current == order} ?past=${this.current > order} title=${name || ''}>
114
+ <span>${order + 1}</span>
115
+ <div>${name}</div>
116
+ </li>
117
+ `
118
+ }
119
+ }
@@ -0,0 +1,91 @@
1
+ import '@material/web/icon/icon.js'
2
+ import { css, html, LitElement } from 'lit'
3
+ import { customElement, property, query, state } from 'lit/decorators.js'
4
+
5
+ import { i18next, localize } from '@operato/i18n'
6
+ import { CommonHeaderStyles } from '@operato/styles'
7
+ import { closePopup } from '@operato/popup'
8
+ import { OxPrompt } from '@operato/popup/ox-prompt.js'
9
+
10
+ import { ApprovalLineItemsEditor } from './approval-line-items-editor'
11
+ import { ApprovalLineItem } from '../types/approval-line'
12
+
13
+ /**
14
+ * 결재선의 각 결재자 리스트를 편집한다.
15
+ */
16
+ @customElement('approval-line-items-editor-popup')
17
+ export class ApprovalLineItemsEditorPopup extends localize(i18next)(LitElement) {
18
+ static styles = [
19
+ CommonHeaderStyles,
20
+ css`
21
+ :host {
22
+ display: flex;
23
+ flex-direction: column;
24
+
25
+ background-color: var(--md-sys-color-surface);
26
+ }
27
+
28
+ approval-line-items-editor {
29
+ flex: 1;
30
+ }
31
+ `
32
+ ]
33
+
34
+ @property({ type: Array }) value?: ApprovalLineItem[]
35
+
36
+ @property({ type: Object }) confirmCallback?: (value?: ApprovalLineItem[] | null) => void
37
+ @query('approval-line-items-editor') editor!: ApprovalLineItemsEditor
38
+
39
+ /* this.value는 (원인불명으로) 값이 Reset되므로, 변화값을 유지하도록 별도로 changedValue를 사용함 */
40
+ private changedValue?: ApprovalLineItem[] = this.value
41
+
42
+ render() {
43
+ return html`
44
+ <approval-line-items-editor
45
+ .value=${this.value}
46
+ @change=${(e: CustomEvent) => {
47
+ this.changedValue = [...e.detail]
48
+ }}
49
+ ></approval-line-items-editor>
50
+
51
+ <div class="footer">
52
+ <button @click=${this.onEmpty.bind(this)}>
53
+ <md-icon>check_box_outline_blank</md-icon>${i18next.t('button.empty')}
54
+ </button>
55
+
56
+ <div filler></div>
57
+
58
+ <button @click=${this.onCancel.bind(this)}><md-icon>cancel</md-icon>${i18next.t('button.cancel')}</button>
59
+ <button @click=${this.onConfirm.bind(this)} done><md-icon>done</md-icon>${i18next.t('button.confirm')}</button>
60
+ </div>
61
+ `
62
+ }
63
+
64
+ firstUpdated() {
65
+ this.changedValue = this.value
66
+ }
67
+
68
+ async onEmpty() {
69
+ const reaction = await OxPrompt.open({
70
+ title: i18next.t('text.are_you_sure'),
71
+ text: i18next.t('prompt.sure to empty approval line ?'),
72
+ confirmButton: { text: i18next.t('button.confirm') },
73
+ cancelButton: { text: i18next.t('button.cancel') }
74
+ })
75
+
76
+ if (reaction) {
77
+ this.confirmCallback && this.confirmCallback(null)
78
+ closePopup(this)
79
+ }
80
+ }
81
+
82
+ onCancel() {
83
+ closePopup(this)
84
+ }
85
+
86
+ onConfirm() {
87
+ this.confirmCallback && this.confirmCallback(this.changedValue)
88
+
89
+ closePopup(this)
90
+ }
91
+ }
@@ -0,0 +1,325 @@
1
+ import './approval-line-view'
2
+ import './approval-line-selector'
3
+
4
+ import { css, html, LitElement } from 'lit'
5
+ import { customElement, property, query, state } from 'lit/decorators.js'
6
+
7
+ import { i18next, localize } from '@operato/i18n'
8
+ import { DataGrist, FetchOption, getEditor, getRenderer } from '@operato/data-grist'
9
+ import { isMobileDevice } from '@operato/utils'
10
+ import { ButtonContainerStyles, CommonHeaderStyles } from '@operato/styles'
11
+ import { openPopup, PopupHandle } from '@operato/layout'
12
+
13
+ import { ApprovalLineView } from './approval-line-view'
14
+ import { ApprovalLine, ApprovalLineItem } from '../types/approval-line'
15
+
16
+ /**
17
+ * 결재선의 각 결재자 리스트를 편집한다.
18
+ */
19
+ @customElement('approval-line-items-editor')
20
+ export class ApprovalLineItemsEditor extends localize(i18next)(LitElement) {
21
+ static styles = [
22
+ CommonHeaderStyles,
23
+ ButtonContainerStyles,
24
+ css`
25
+ :host {
26
+ display: flex;
27
+ flex-direction: column;
28
+
29
+ background-color: var(--md-sys-color-surface);
30
+ }
31
+
32
+ approval-line-view {
33
+ min-height: 100px;
34
+ }
35
+
36
+ ox-grist {
37
+ flex: 1;
38
+ }
39
+
40
+ .header {
41
+ grid-template-areas: 'filters actions';
42
+ }
43
+ `
44
+ ]
45
+
46
+ @property({ type: Array }) value?: ApprovalLineItem[]
47
+
48
+ @state() gristConfig?: any
49
+
50
+ @query('ox-grist') grist?: DataGrist
51
+ @query('approval-line-view') view?: ApprovalLineView
52
+
53
+ private popup?: PopupHandle
54
+
55
+ render() {
56
+ return html`
57
+ <approval-line-view .model=${this.value}></approval-line-view>
58
+ <ox-grist
59
+ .mode=${isMobileDevice() ? 'CARD' : 'GRID'}
60
+ .config=${this.gristConfig}
61
+ .fetchHandler=${this.fetchHandler.bind(this)}
62
+ @record-change=${e => {
63
+ this.value = ((this.grist as any)?._data.records || [])
64
+ .map(v => {
65
+ return { type: v.type, approver: v.approver }
66
+ })
67
+ .filter(v => v.type)
68
+
69
+ this.dispatchEvent(
70
+ new CustomEvent('change', {
71
+ bubbles: true,
72
+ composed: true,
73
+ detail: this.value
74
+ })
75
+ )
76
+ }}
77
+ >
78
+ <div slot="headroom" class="header">
79
+ <div class="actions">
80
+ <button @click=${this.openSelector.bind(this)}>
81
+ <md-icon>content_copy</md-icon>${i18next.t('button.copy from')}
82
+ </button>
83
+
84
+ <button danger @click=${() => this.deleteDataItems()}>
85
+ <md-icon>delete</md-icon>${i18next.t('button.delete')}
86
+ </button>
87
+ </div>
88
+ </div>
89
+ </ox-grist>
90
+ `
91
+ }
92
+
93
+ async firstUpdated() {
94
+ this.gristConfig = {
95
+ list: {
96
+ fields: ['type', 'approver']
97
+ },
98
+ columns: [
99
+ { type: 'gutter', gutterName: 'row-selector', multiple: true },
100
+ { type: 'gutter', gutterName: 'sequence' },
101
+ {
102
+ type: 'gutter',
103
+ gutterName: 'button',
104
+ icon: 'arrow_upward',
105
+ handlers: {
106
+ click: 'move-up'
107
+ }
108
+ },
109
+ {
110
+ type: 'gutter',
111
+ gutterName: 'button',
112
+ icon: 'arrow_downward',
113
+ handlers: {
114
+ click: 'move-down'
115
+ }
116
+ },
117
+ {
118
+ type: 'select',
119
+ name: 'type',
120
+ header: i18next.t('field.type'),
121
+ record: {
122
+ editable: true,
123
+ options: ['', 'Employee', 'Department', 'Role', 'MyDepartment', 'MySupervisor', 'Myself']
124
+ },
125
+ width: 140
126
+ },
127
+ {
128
+ type: 'resource-object',
129
+ name: 'approver',
130
+ header: i18next.t('field.approver'),
131
+ record: {
132
+ editable: true,
133
+ editor: function (value, column, record, rowIndex, field) {
134
+ var options = {}
135
+ switch (record.type) {
136
+ case 'Employee':
137
+ options = {
138
+ title: i18next.t('title.employee list'),
139
+ pagination: { pages: [50, 100, 200] },
140
+ basicArgs: { filters: [{ name: 'active', operator: 'eq', value: 'true' }] },
141
+ queryName: 'employees',
142
+ columns: [
143
+ { name: 'id', hidden: true },
144
+ {
145
+ name: 'controlNo',
146
+ width: 120,
147
+ header: { renderer: () => i18next.t('field.control-no') },
148
+ filter: 'search',
149
+ sortable: true
150
+ },
151
+ {
152
+ name: 'name',
153
+ width: 120,
154
+ header: { renderer: () => i18next.t('field.name') },
155
+ filter: 'search',
156
+ sortable: true
157
+ },
158
+ {
159
+ name: 'alias',
160
+ width: 150,
161
+ header: { renderer: () => i18next.t('label.alias') },
162
+ filter: 'search',
163
+ sortable: true
164
+ },
165
+ {
166
+ type: 'code',
167
+ name: 'type',
168
+ width: 110,
169
+ header: { renderer: () => i18next.t('label.type') },
170
+ record: {
171
+ editable: false,
172
+ codeName: 'EMPLOYEE_TYPE'
173
+ }
174
+ },
175
+ {
176
+ type: 'code',
177
+ name: 'jobPosition',
178
+ width: 110,
179
+ header: { renderer: () => i18next.t('label.job-position') },
180
+ record: {
181
+ editable: false,
182
+ codeName: 'JOB_POSITION'
183
+ }
184
+ },
185
+ {
186
+ type: 'code',
187
+ name: 'jobResponsibility',
188
+ width: 200,
189
+ header: { renderer: () => i18next.t('label.job-responsibility') },
190
+ record: {
191
+ editable: false,
192
+ codeName: 'JOB_RESPONSIBILITY'
193
+ }
194
+ },
195
+ {
196
+ type: 'date',
197
+ name: 'hiredOn',
198
+ header: { renderer: () => i18next.t('field.hired-on') },
199
+ width: 100
200
+ }
201
+ ],
202
+ list: { fields: ['controlNo', 'name', 'alias', 'hiredOn'] },
203
+ valueField: 'id',
204
+ nameField: 'name',
205
+ descriptionField: 'controlNo'
206
+ }
207
+ break
208
+ case 'Department':
209
+ options = {
210
+ title: i18next.t('title.department list'),
211
+ queryName: 'departments',
212
+ columns: [
213
+ { name: 'id', hidden: true },
214
+ {
215
+ name: 'controlNo',
216
+ header: { renderer: () => i18next.t('field.control-no') },
217
+ filter: 'search'
218
+ },
219
+ { name: 'name', header: { renderer: () => i18next.t('field.name') }, filter: 'search' }
220
+ ],
221
+ list: { fields: ['name', 'control-no'] },
222
+ valueField: 'id',
223
+ nameField: 'name',
224
+ descriptionField: 'controlNo'
225
+ }
226
+ break
227
+ case 'Role':
228
+ options = {
229
+ title: i18next.t('title.lookup role'),
230
+ queryName: 'roles'
231
+ }
232
+ break
233
+ default:
234
+ return null
235
+ }
236
+
237
+ var dynamicRecord = { ...column.record, options }
238
+
239
+ return getEditor(column.type)(value, { ...column, record: dynamicRecord }, record, rowIndex, field)
240
+ },
241
+ renderer: function (value, column, record, rowIndex, field) {
242
+ var options = {}
243
+ switch (record.type) {
244
+ case 'Employee':
245
+ options = {
246
+ valueField: 'id',
247
+ nameField: 'name',
248
+ descriptionField: 'controlNo'
249
+ }
250
+ break
251
+ case 'Department':
252
+ case 'Role':
253
+ default:
254
+ break
255
+ }
256
+
257
+ var dynamicRecord = { ...column.record, options }
258
+
259
+ return getRenderer(column.type)(value, { ...column, record: dynamicRecord }, record, rowIndex, field)
260
+ }
261
+ },
262
+ width: 180
263
+ }
264
+ ],
265
+ rows: {
266
+ selectable: {
267
+ multiple: true
268
+ }
269
+ },
270
+ pagination: {
271
+ infinite: true
272
+ },
273
+ sorters: []
274
+ }
275
+ }
276
+
277
+ fetchHandler({ filters, page, limit, sortings = [] }: FetchOption) {
278
+ const value = [...(this.value || [])]
279
+ this.value = value
280
+
281
+ return {
282
+ total: value.length,
283
+ records: value
284
+ }
285
+ }
286
+
287
+ async deleteDataItems() {
288
+ this.grist?.deleteSelectedRecords(false)
289
+ }
290
+
291
+ openSelector() {
292
+ if (this.popup) {
293
+ delete this.popup
294
+ }
295
+
296
+ const confirmCallback = async (selected?: ApprovalLine) => {
297
+ this.value = [...(selected?.model || [])]
298
+
299
+ this.grist!.fetch()
300
+
301
+ this.dispatchEvent(
302
+ new CustomEvent('change', {
303
+ bubbles: true,
304
+ composed: true,
305
+ detail: this.value
306
+ })
307
+ )
308
+ }
309
+
310
+ this.popup = openPopup(
311
+ html` <approval-line-selector .confirmCallback=${confirmCallback.bind(this)}></approval-line-selector> `,
312
+ {
313
+ backdrop: true,
314
+ size: 'large',
315
+ search: {
316
+ placeholder: i18next.t('title.approval-line template list'),
317
+ handler: (instance: any, value: any) => {
318
+ /* instance: template instance */
319
+ instance.searchText(value)
320
+ }
321
+ }
322
+ }
323
+ )
324
+ }
325
+ }