@things-factory/integration-ui 9.2.5 → 10.0.0-beta.10

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.
@@ -4,41 +4,33 @@ import './connection-importer.js'
4
4
  import gql from 'graphql-tag'
5
5
  import { css, html } from 'lit'
6
6
  import { customElement, property, query } from 'lit/decorators.js'
7
- import { connect } from 'pwa-helpers/connect-mixin'
8
-
9
7
  import { DataGrist } from '@operato/data-grist/ox-grist.js'
10
8
  import { client } from '@operato/graphql'
11
9
  import { HelpDecoratedRenderer } from '@operato/help/help-decorated-renderer.js'
12
10
  import { notify, openPopup } from '@operato/layout'
13
11
  import { i18next, localize } from '@operato/i18n'
14
- import { PageView, store } from '@operato/shell'
12
+ import { PageView } from '@operato/shell'
15
13
  import { CommonButtonStyles, CommonGristStyles, ScrollbarStyles } from '@operato/styles'
16
14
  import { isMobileDevice } from '@operato/utils'
17
15
  import { FetchOption } from '@operato/data-grist'
18
16
  import { p13n } from '@operato/p13n'
19
17
  import { PropertySpec } from '../types.js'
20
18
 
21
- async function copyToClipboard(text: string): Promise<void> {
22
- try {
23
- await navigator.clipboard.writeText(text)
24
- } catch (err) {
25
- // fallback: old way
19
+ async function copyToClipboard(text: string): Promise<void> { try { await navigator.clipboard.writeText(text)
20
+ } catch (err) { // fallback: old way
26
21
  const textArea = document.createElement('textarea')
27
22
  textArea.value = text
28
23
  document.body.appendChild(textArea)
29
24
  textArea.select()
30
25
  document.execCommand('copy')
31
26
  document.body.removeChild(textArea)
32
- }
27
+ }
33
28
  }
34
29
 
35
30
  function createActionInjector(
36
31
  connectionName: string
37
- ): (propName: string, propSpec: PropertySpec) => HTMLElement | null {
38
- return (propName: string, propSpec: PropertySpec): HTMLElement | null => {
39
- if (!propSpec.useDomainAttribute) {
40
- return null
41
- }
32
+ ): (propName: string, propSpec: PropertySpec) => HTMLElement | null { return (propName: string, propSpec: PropertySpec): HTMLElement | null => { if (!propSpec.useDomainAttribute) { return null
33
+ }
42
34
 
43
35
  const attributeName = `Connection::${connectionName}::${propName}`
44
36
 
@@ -48,41 +40,36 @@ function createActionInjector(
48
40
  'cursor: pointer; color: var(--md-sys-color-primary); font-size: 16px; --md-icon-size: 16px;'
49
41
  copyIcon.title = `Copy ${attributeName}`
50
42
 
51
- copyIcon.addEventListener('click', () => {
52
- copyToClipboard(attributeName)
43
+ copyIcon.addEventListener('click', () => { copyToClipboard(attributeName)
53
44
 
54
45
  // 복사 성공 피드백
55
46
  const originalText = copyIcon.textContent
56
47
  copyIcon.textContent = 'check'
57
48
  copyIcon.style.color = 'var(--md-sys-color-tertiary)'
58
49
 
59
- setTimeout(() => {
60
- copyIcon.textContent = originalText
50
+ setTimeout(() => { copyIcon.textContent = originalText
61
51
  copyIcon.style.color = 'var(--md-sys-color-primary)'
62
- }, 1000)
63
- })
52
+ }, 1000)
53
+ })
64
54
 
65
55
  return copyIcon
66
- }
56
+ }
67
57
  }
68
58
 
69
59
  @customElement('connection-page')
70
- export class Connection extends connect(store)(p13n(localize(i18next)(PageView))) {
71
- static styles = [
60
+ export class Connection extends p13n(localize(i18next)(PageView)) { static styles = [
72
61
  CommonGristStyles,
73
62
  ScrollbarStyles,
74
63
  css`
75
- :host {
76
- display: flex;
64
+ :host { display: flex;
77
65
  flex-direction: column;
78
66
 
79
67
  overflow: hidden;
80
- }
68
+ }
81
69
 
82
- ox-grist {
83
- overflow-y: auto;
70
+ ox-grist { overflow-y: auto;
84
71
  flex: 1;
85
- }
72
+ }
86
73
  `
87
74
  ]
88
75
 
@@ -92,47 +79,36 @@ export class Connection extends connect(store)(p13n(localize(i18next)(PageView))
92
79
 
93
80
  @query('ox-grist') grist!: DataGrist
94
81
 
95
- get context() {
96
- return {
97
- title: i18next.t('text.connection list'),
98
- search: {
99
- handler: search => {
100
- this.grist.searchText = search
101
- },
82
+ get context() { return { title: i18next.t('text.connection list'),
83
+ search: { handler: search => { this.grist.searchText = search
84
+ },
102
85
  value: this.grist?.searchText || ''
103
- },
86
+ },
104
87
  // 필터가 설정되면, 아래 코멘트 해제
105
- // filter: {
106
- // handler: () => {
107
- // const display = this.headroom.style.display
88
+ // filter: { // handler: () => { // const display = this.headroom.style.display
108
89
  // this.headroom.style.display = display !== 'none' ? 'none' : 'flex'
109
- // }
90
+ // }
110
91
  // },
111
92
  help: 'integration/ui/connection',
112
93
  actions: [
113
- {
114
- title: i18next.t('button.save'),
94
+ { title: i18next.t('button.save'),
115
95
  action: this._updateConnectionManager.bind(this),
116
96
  ...CommonButtonStyles.save
117
- },
118
- {
119
- title: i18next.t('button.delete'),
97
+ },
98
+ { title: i18next.t('button.delete'),
120
99
  action: this._deleteConnections.bind(this),
121
100
  ...CommonButtonStyles.delete
122
- }
101
+ }
123
102
  ],
124
- exportable: {
125
- name: i18next.t('text.connection list'),
103
+ exportable: { name: i18next.t('text.connection list'),
126
104
  data: this.exportHandler.bind(this)
127
- },
128
- importable: {
129
- handler: this.importHandler.bind(this)
130
- }
131
- }
132
- }
133
-
134
- render() {
135
- return html`
105
+ },
106
+ importable: { handler: this.importHandler.bind(this)
107
+ }
108
+ }
109
+ }
110
+
111
+ render() { return html`
136
112
  <ox-grist
137
113
  .mode=${isMobileDevice() ? 'LIST' : 'GRID'}
138
114
  .config=${this.gristConfig}
@@ -142,18 +118,15 @@ export class Connection extends connect(store)(p13n(localize(i18next)(PageView))
142
118
  <ox-grist-personalizer slot="setting"></ox-grist-personalizer>
143
119
  </ox-grist>
144
120
  `
145
- }
121
+ }
146
122
 
147
- async pageInitialized() {
148
- this.fetchConnectors()
123
+ async pageInitialized() { this.fetchConnectors()
149
124
 
150
- this.gristConfig = {
151
- list: { fields: ['name', 'description', 'type', 'active'] },
125
+ this.gristConfig = { list: { fields: ['name', 'description', 'type', 'active'] },
152
126
  columns: [
153
127
  { type: 'gutter', gutterName: 'sequence' },
154
128
  { type: 'gutter', gutterName: 'row-selector', multiple: true },
155
- {
156
- type: 'gutter',
129
+ { type: 'gutter',
157
130
  gutterName: 'button',
158
131
  name: 'state',
159
132
  icon: record => (!record ? 'link' : !record.id ? '' : record.state == 'CONNECTED' ? 'link_off' : 'link'),
@@ -167,338 +140,261 @@ export class Connection extends connect(store)(p13n(localize(i18next)(PageView))
167
140
  ? i18next.t('button.disconnect')
168
141
  : i18next.t('button.connect'),
169
142
  width: 80,
170
- handlers: {
171
- click: (columns, data, column, record, rowIndex) => {
172
- if (!record || !record.name || record.__dirty__ == '+') {
173
- return
174
- }
175
- if (record.state == 'CONNECTED') {
176
- this.disconnect(record)
177
- } else {
178
- this.connect(record)
179
- }
180
- }
181
- }
182
- },
183
- {
184
- type: 'object',
143
+ handlers: { click: (columns, data, column, record, rowIndex) => { if (!record || !record.name || record.__dirty__ == '+') { return
144
+ }
145
+ if (record.state == 'CONNECTED') { this.disconnect(record)
146
+ } else { this.connect(record)
147
+ }
148
+ }
149
+ }
150
+ },
151
+ { type: 'object',
185
152
  name: 'domain',
186
153
  hidden: true
187
- },
188
- {
189
- type: 'string',
154
+ },
155
+ { type: 'string',
190
156
  name: 'name',
191
157
  label: true,
192
158
  header: i18next.t('field.name'),
193
- record: {
194
- editable: true,
159
+ record: { editable: true,
195
160
  mandatory: true
196
- },
161
+ },
197
162
  filter: 'search',
198
163
  sortable: true,
199
164
  width: 150,
200
- validation: function (after, before, record, column) {
201
- /* connected 상태에서는 이름을 바꿀 수 없다. */
202
- if (record.state == 'CONNECTED') {
203
- notify({
204
- level: 'warn',
165
+ validation: function (after, before, record, column) { /* connected 상태에서는 이름을 바꿀 수 없다. */
166
+ if (record.state == 'CONNECTED') { notify({ level: 'warn',
205
167
  message: 'connection name cannot be changed during connected.'
206
- })
168
+ })
207
169
  return false
208
- }
170
+ }
209
171
  return true
210
- }
211
- },
212
- {
213
- type: 'string',
172
+ }
173
+ },
174
+ { type: 'string',
214
175
  name: 'description',
215
176
  label: true,
216
177
  header: i18next.t('field.description'),
217
- record: {
218
- editable: true
219
- },
178
+ record: { editable: true
179
+ },
220
180
  filter: 'search',
221
181
  width: 200
222
- },
223
- {
224
- type: 'checkbox',
182
+ },
183
+ { type: 'checkbox',
225
184
  name: 'active',
226
185
  label: true,
227
186
  header: i18next.t('field.startup-connect'),
228
- record: {
229
- editable: true,
187
+ record: { editable: true,
230
188
  align: 'center'
231
- },
189
+ },
232
190
  sortable: true,
233
191
  width: 60
234
- },
235
- {
236
- type: 'checkbox',
192
+ },
193
+ { type: 'checkbox',
237
194
  name: 'onDemand',
238
195
  label: true,
239
196
  header: i18next.t('field.on-demand'),
240
- record: {
241
- editable: true
242
- },
197
+ record: { editable: true
198
+ },
243
199
  width: 120
244
- },
245
- {
246
- type: 'connector',
200
+ },
201
+ { type: 'connector',
247
202
  name: 'type',
248
203
  label: true,
249
204
  header: i18next.t('field.type'),
250
- record: {
251
- renderer: HelpDecoratedRenderer,
205
+ record: { renderer: HelpDecoratedRenderer,
252
206
  editable: true,
253
207
  help: value => this.connectors?.[value]?.help,
254
208
  mandatory: true
255
- },
209
+ },
256
210
  filter: 'search',
257
211
  sortable: true,
258
212
  width: 200
259
- },
260
- {
261
- type: 'string',
213
+ },
214
+ { type: 'string',
262
215
  name: 'endpoint',
263
216
  header: i18next.t('field.endpoint'),
264
- record: {
265
- editable: true,
217
+ record: { editable: true,
266
218
  mandatory: true
267
- },
219
+ },
268
220
  filter: 'search',
269
221
  sortable: true,
270
222
  width: 280
271
- },
272
- {
273
- type: 'parameters',
223
+ },
224
+ { type: 'parameters',
274
225
  name: 'params',
275
226
  header: i18next.t('field.params'),
276
- record: {
277
- editable: true,
278
- options: async (value, column, record, row, field) => {
279
- const { name, help, parameterSpec: spec } = record.type ? this.connectors?.[record.type] : ({} as any)
227
+ record: { editable: true,
228
+ options: async (value, column, record, row, field) => { const { name, help, parameterSpec: spec } = record.type ? this.connectors?.[record.type] : ({} as any)
280
229
  const context = this.grist
281
230
 
282
- return {
283
- name,
231
+ return { name,
284
232
  help,
285
233
  spec,
286
234
  context,
287
235
  objectified: true,
288
236
  actionInjector: createActionInjector(record.name)
289
- }
290
- },
237
+ }
238
+ },
291
239
  renderer: 'json5'
292
- },
240
+ },
293
241
  width: 100
294
- },
295
- {
296
- type: 'resource-object',
242
+ },
243
+ { type: 'resource-object',
297
244
  name: 'edge',
298
245
  header: i18next.t('field.edge-server'),
299
- record: {
300
- editable: true,
301
- options: {
302
- queryName: 'edges'
303
- }
304
- },
246
+ record: { editable: true,
247
+ options: { queryName: 'edges'
248
+ }
249
+ },
305
250
  sortable: true,
306
251
  width: 120
307
- },
308
- {
309
- type: 'resource-object',
252
+ },
253
+ { type: 'resource-object',
310
254
  name: 'updater',
311
255
  header: i18next.t('field.updater'),
312
- record: {
313
- editable: false
314
- },
256
+ record: { editable: false
257
+ },
315
258
  sortable: true,
316
259
  width: 120
317
- },
318
- {
319
- type: 'datetime',
260
+ },
261
+ { type: 'datetime',
320
262
  name: 'updatedAt',
321
263
  header: i18next.t('field.updated_at'),
322
- record: {
323
- editable: false
324
- },
264
+ record: { editable: false
265
+ },
325
266
  sortable: true,
326
267
  width: 180
327
- }
268
+ }
328
269
  ],
329
- rows: {
330
- selectable: {
331
- multiple: true
332
- }
333
- },
270
+ rows: { selectable: { multiple: true
271
+ }
272
+ },
334
273
  sorters: [
335
- {
336
- name: 'name'
337
- }
274
+ { name: 'name'
275
+ }
338
276
  ]
339
- }
340
- }
341
-
342
- async fetchHandler({ page, limit, sortings = [], filters = [] }: FetchOption) {
343
- const response = await client.query({
344
- query: gql`
345
- query ($filters: [Filter!], $pagination: Pagination, $sortings: [Sorting!]) {
346
- responses: connections(filters: $filters, pagination: $pagination, sortings: $sortings) {
347
- items {
348
- id
349
- domain {
350
- id
277
+ }
278
+ }
279
+
280
+ async fetchHandler({ page, limit, sortings = [], filters = [] }: FetchOption) { const response = await client.query({ query: gql`
281
+ query ($filters: [Filter!], $pagination: Pagination, $sortings: [Sorting!]) { responses: connections(filters: $filters, pagination: $pagination, sortings: $sortings) { items { id
282
+ domain { id
351
283
  name
352
284
  description
353
- }
285
+ }
354
286
  name
355
287
  description
356
288
  type
357
- edge {
358
- id
289
+ edge { id
359
290
  name
360
- }
291
+ }
361
292
  endpoint
362
293
  active
363
294
  onDemand
364
295
  state
365
296
  params
366
- updater {
367
- id
297
+ updater { id
368
298
  name
369
299
  description
370
- }
300
+ }
371
301
  updatedAt
372
- }
302
+ }
373
303
  total
374
- }
375
- }
304
+ }
305
+ }
376
306
  `,
377
- variables: {
378
- filters,
307
+ variables: { filters,
379
308
  pagination: { page, limit },
380
309
  sortings
381
- }
382
- })
310
+ }
311
+ })
383
312
 
384
- return {
385
- total: response.data.responses.total || 0,
313
+ return { total: response.data.responses.total || 0,
386
314
  records: response.data.responses.items || []
387
- }
388
- }
389
-
390
- async fetchConnectors() {
391
- const response = await client.query({
392
- query: gql`
393
- query {
394
- connectors {
395
- items {
396
- name
315
+ }
316
+ }
317
+
318
+ async fetchConnectors() { const response = await client.query({ query: gql`
319
+ query { connectors { items { name
397
320
  help
398
- parameterSpec {
399
- type
321
+ parameterSpec { type
400
322
  name
401
323
  label
402
324
  placeholder
403
325
  property
404
326
  styles
405
327
  useDomainAttribute
406
- }
407
- }
408
- }
409
- }
328
+ }
329
+ }
330
+ }
331
+ }
410
332
  `
411
- })
333
+ })
412
334
 
413
- if (!response.errors) {
414
- this.connectors = response.data.connectors.items.reduce((connectors, connector) => {
415
- connectors[connector.name] = connector
335
+ if (!response.errors) { this.connectors = response.data.connectors.items.reduce((connectors, connector) => { connectors[connector.name] = connector
416
336
  return connectors
417
- }, {})
418
- } else {
419
- console.error('fetch connectors error')
420
- }
421
- }
422
-
423
- async _deleteConnections(name) {
424
- if (
337
+ }, {})
338
+ } else { console.error('fetch connectors error')
339
+ }
340
+ }
341
+
342
+ async _deleteConnections(name) { if (
425
343
  confirm(
426
- i18next.t('text.sure_to_x', {
427
- x: i18next.t('text.delete')
428
- })
344
+ i18next.t('text.sure_to_x', { x: i18next.t('text.delete')
345
+ })
429
346
  )
430
- ) {
431
- const names = this.grist.selected.map(record => record.name)
432
- if (names && names.length > 0) {
433
- const response = await client.mutate({
434
- mutation: gql`
435
- mutation ($names: [String!]!) {
436
- deleteConnections(names: $names)
437
- }
347
+ ) { const names = this.grist.selected.map(record => record.name)
348
+ if (names && names.length > 0) { const response = await client.mutate({ mutation: gql`
349
+ mutation ($names: [String!]!) { deleteConnections(names: $names)
350
+ }
438
351
  `,
439
- variables: {
440
- names
441
- }
442
- })
443
-
444
- if (!response.errors) {
445
- this.grist.fetch()
446
-
447
- notify({
448
- message: i18next.t('text.info_x_successfully', {
449
- x: i18next.t('text.delete')
450
- })
451
- })
452
- }
453
- }
454
- }
455
- }
456
-
457
- async _updateConnectionManager() {
458
- var patches = this.grist.dirtyRecords
459
-
460
- if (patches && patches.length) {
461
- patches = patches.map(connection => {
462
- let patchField: any = connection.id ? { id: connection.id } : {}
352
+ variables: { names
353
+ }
354
+ })
355
+
356
+ if (!response.errors) { this.grist.fetch()
357
+
358
+ notify({ message: i18next.t('text.info_x_successfully', { x: i18next.t('text.delete')
359
+ })
360
+ })
361
+ }
362
+ }
363
+ }
364
+ }
365
+
366
+ async _updateConnectionManager() { var patches = this.grist.dirtyRecords
367
+
368
+ if (patches && patches.length) { patches = patches.map(connection => { let patchField: any = connection.id ? { id: connection.id } : {}
463
369
  const dirtyFields = connection.__dirtyfields__
464
- for (let key in dirtyFields) {
465
- patchField[key] = dirtyFields[key].after
466
- }
370
+ for (let key in dirtyFields) { patchField[key] = dirtyFields[key].after
371
+ }
467
372
  patchField.cuFlag = connection.__dirty__
468
373
 
469
374
  return patchField
470
- })
375
+ })
471
376
 
472
- const response = await client.mutate({
473
- mutation: gql`
474
- mutation ($patches: [ConnectionPatch!]!) {
475
- updateMultipleConnection(patches: $patches) {
476
- name
477
- }
478
- }
377
+ const response = await client.mutate({ mutation: gql`
378
+ mutation ($patches: [ConnectionPatch!]!) { updateMultipleConnection(patches: $patches) { name
379
+ }
380
+ }
479
381
  `,
480
- variables: {
481
- patches
482
- }
483
- })
382
+ variables: { patches
383
+ }
384
+ })
484
385
 
485
386
  if (!response.errors) this.grist.fetch()
486
- }
487
- }
488
-
489
- async connect(record) {
490
- var response = await client.mutate({
491
- mutation: gql`
492
- mutation ($name: String!) {
493
- connectConnection(name: $name) {
494
- state
495
- }
496
- }
387
+ }
388
+ }
389
+
390
+ async connect(record) { var response = await client.mutate({ mutation: gql`
391
+ mutation ($name: String!) { connectConnection(name: $name) { state
392
+ }
393
+ }
497
394
  `,
498
- variables: {
499
- name: record.name
500
- }
501
- })
395
+ variables: { name: record.name
396
+ }
397
+ })
502
398
 
503
399
  var state = response.data.connectConnection.state
504
400
 
@@ -506,25 +402,19 @@ export class Connection extends connect(store)(p13n(localize(i18next)(PageView))
506
402
 
507
403
  this.grist.refresh()
508
404
 
509
- notify({
510
- level: 'info',
405
+ notify({ level: 'info',
511
406
  message: `${state == 'CONNECTED' ? 'success' : 'fail'} to connect : ${record.name}`
512
- })
513
- }
514
-
515
- async disconnect(record) {
516
- var response = await client.mutate({
517
- mutation: gql`
518
- mutation ($name: String!) {
519
- disconnectConnection(name: $name) {
520
- state
521
- }
522
- }
407
+ })
408
+ }
409
+
410
+ async disconnect(record) { var response = await client.mutate({ mutation: gql`
411
+ mutation ($name: String!) { disconnectConnection(name: $name) { state
412
+ }
413
+ }
523
414
  `,
524
- variables: {
525
- name: record.name
526
- }
527
- })
415
+ variables: { name: record.name
416
+ }
417
+ })
528
418
 
529
419
  var state = response.data.disconnectConnection.state
530
420
 
@@ -532,42 +422,35 @@ export class Connection extends connect(store)(p13n(localize(i18next)(PageView))
532
422
 
533
423
  this.grist.refresh()
534
424
 
535
- notify({
536
- level: 'info',
425
+ notify({ level: 'info',
537
426
  message: `${state == 'CONNECTED' ? 'fail' : 'success'} to disconnect : ${record.name}`
538
- })
539
- }
427
+ })
428
+ }
540
429
 
541
- async exportHandler() {
542
- const exportTargets = this.grist.selected.length ? this.grist.selected : this.grist.dirtyData.records
430
+ async exportHandler() { const exportTargets = this.grist.selected.length ? this.grist.selected : this.grist.dirtyData.records
543
431
  const targetFieldSet = new Set(['id', 'name', 'type', 'description', 'endpoint', 'params'])
544
432
 
545
- return exportTargets.map(connection => {
546
- let tempObj = {}
547
- for (const field of targetFieldSet) {
548
- tempObj[field] = connection[field]
549
- }
433
+ return exportTargets.map(connection => { let tempObj = {}
434
+ for (const field of targetFieldSet) { tempObj[field] = connection[field]
435
+ }
550
436
 
551
437
  return tempObj
552
- })
553
- }
438
+ })
439
+ }
554
440
 
555
- async importHandler(records) {
556
- openPopup(
441
+ async importHandler(records) { openPopup(
557
442
  html`
558
443
  <connection-importer
559
444
  .connections=${records}
560
- @imported=${() => {
561
- history.back()
445
+ @imported=${() => { history.back()
562
446
  this.grist.fetch()
563
- }}
447
+ }}
564
448
  ></connection-importer>
565
449
  `,
566
- {
567
- backdrop: true,
450
+ { backdrop: true,
568
451
  size: 'large',
569
452
  title: i18next.t('title.import connection')
570
- }
453
+ }
571
454
  )
572
- }
455
+ }
573
456
  }