@operato/attachment 0.2.52

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.
@@ -0,0 +1,489 @@
1
+ import { __decorate } from "tslib";
2
+ // import './attachment-creation-card'
3
+ import '@operato/data-grist';
4
+ import gql from 'graphql-tag';
5
+ import i18next from 'i18next';
6
+ import { css, html, LitElement } from 'lit';
7
+ import { customElement, property, query, state } from 'lit/decorators.js';
8
+ import { buildArgs, client } from '@operato/graphql';
9
+ import { ScrollbarStyles, TooltipStyles } from '@operato/styles';
10
+ const FETCH_ATTACHMENT_LIST_GQL = (listParam) => {
11
+ return gql `
12
+ {
13
+ attachments(${buildArgs(listParam)}) {
14
+ items {
15
+ id
16
+ name
17
+ description
18
+ mimetype
19
+ encoding
20
+ category
21
+ fullpath
22
+ path
23
+ }
24
+ total
25
+ }
26
+ }
27
+ `;
28
+ };
29
+ const DELETE_ATTACHMENT_GQL = gql `
30
+ mutation DeleteAttachment($id: String!) {
31
+ deleteAttachment(id: $id)
32
+ }
33
+ `;
34
+ const CREATE_ATTACHMENTS_GQL = gql `
35
+ mutation ($attachments: [NewAttachment!]!) {
36
+ createAttachments(attachments: $attachments) {
37
+ id
38
+ name
39
+ description
40
+ mimetype
41
+ encoding
42
+ category
43
+ path
44
+ createdAt
45
+ updatedAt
46
+ }
47
+ }
48
+ `;
49
+ let OxAttachmentList = class OxAttachmentList extends LitElement {
50
+ constructor() {
51
+ super(...arguments);
52
+ this.categories = ['audio', 'video', 'image', 'text', 'application'];
53
+ this.mode = 'CARD';
54
+ this.category = '';
55
+ this.creatable = false;
56
+ this._total = 0;
57
+ this._page = 1;
58
+ }
59
+ render() {
60
+ const mode = this.mode || 'CARD';
61
+ return html `
62
+ <ox-grist .config=${this.gristConfig} .mode=${mode} auto-fetch .fetchHandler=${this.fetchHandler.bind(this)}>
63
+ <div slot="headroom" id="headroom">
64
+ <div id="filters">
65
+ <mwc-icon>search</mwc-icon>
66
+ <input type="text" />
67
+
68
+ <select
69
+ @change=${(e) => {
70
+ var _a;
71
+ this.category = (_a = e.currentTarget) === null || _a === void 0 ? void 0 : _a.value;
72
+ this.requestUpdate();
73
+ }}
74
+ >
75
+ <option value="">--${i18next.t('text.please choose a category')}--</option>
76
+ ${this.categories.map(category => html ` <option value=${category} ?selected=${this.category == category}>${category}</option> `)}
77
+ </select>
78
+ </div>
79
+
80
+ <div id="modes">
81
+ <mwc-icon @click=${() => (this.mode = 'GRID')} ?active=${mode == 'GRID'}>grid_on</mwc-icon>
82
+ <mwc-icon @click=${() => (this.mode = 'LIST')} ?active=${mode == 'LIST'}>format_list_bulleted</mwc-icon>
83
+ <mwc-icon @click=${() => (this.mode = 'CARD')} ?active=${mode == 'CARD'}>apps</mwc-icon>
84
+ </div>
85
+
86
+ <!-- ${this.creatable
87
+ ? html `
88
+ <attachment-creation-card
89
+ class="card create"
90
+ .categories=${this.categories}
91
+ .defaultCategory=${this.category}
92
+ @create-attachment=${(e) => this.onCreateAttachment(e)}
93
+ @file-drop=${(e) => this.onAttachmentDropped(e)}
94
+ ></attachment-creation-card>
95
+ `
96
+ : undefined} -->
97
+ </div>
98
+ </ox-grist>
99
+ `;
100
+ }
101
+ async fetchHandler({ page, limit, sorters = [] }) {
102
+ const { items: records, total } = await this.getAttachments({ page, limit, sorters });
103
+ return {
104
+ total,
105
+ records
106
+ };
107
+ }
108
+ get gristConfig() {
109
+ return {
110
+ list: {
111
+ thumbnail: function (record, rowIndex) {
112
+ return record.category == 'image'
113
+ ? html ` <img src=${record.fullpath} style="width: 100%; height: 100%;" /> `
114
+ : record.category == 'video'
115
+ ? html ` <video src=${record.fullpath} style="width: 100%; height: 100%;" controls></video> `
116
+ : html `
117
+ <div style="width: 100%; height: 100%;" etc>
118
+ <mwc-icon outlined>insert_drive_file</mwc-icon>
119
+ <span>${record.path.substr(record.path.lastIndexOf('.'))}</span>
120
+ </div>
121
+ `;
122
+ },
123
+ fields: ['name'],
124
+ details: ['updatedAt']
125
+ },
126
+ columns: [
127
+ {
128
+ type: 'gutter',
129
+ gutterName: 'dirty'
130
+ },
131
+ {
132
+ type: 'gutter',
133
+ gutterName: 'sequence'
134
+ },
135
+ {
136
+ type: 'gutter',
137
+ gutterName: 'button',
138
+ icon: 'open_in_new',
139
+ handlers: {
140
+ click: (columns, data, column, record, rowIndex) => {
141
+ window.open(record.fullpath, '_blank');
142
+ }
143
+ }
144
+ },
145
+ {
146
+ type: 'gutter',
147
+ gutterName: 'button',
148
+ icon: 'link',
149
+ handlers: {
150
+ click: async (columns, data, column, record, rowIndex) => {
151
+ var { protocol, hostname, port } = location;
152
+ await navigator.clipboard.writeText(`${protocol}//${hostname}:${port}${record.fullpath}`);
153
+ // TODO how to access clicked target
154
+ // this.setAttribute('data-tooltip', 'url copied!')
155
+ // await sleep(2000)
156
+ // this.removeAttribute('data-tooltip')
157
+ }
158
+ }
159
+ },
160
+ {
161
+ type: 'gutter',
162
+ gutterName: 'button',
163
+ icon: 'delete',
164
+ handlers: {
165
+ click: async (columns, data, column, record, rowIndex) => {
166
+ await this.deleteAttachment(record.id);
167
+ this.refreshAttachments();
168
+ }
169
+ }
170
+ },
171
+ {
172
+ type: 'gutter',
173
+ gutterName: 'button',
174
+ icon: 'save_alt',
175
+ handlers: {
176
+ click: (columns, data, column, record, rowIndex) => {
177
+ const element = document.createElement('a');
178
+ element.setAttribute('href', record.fullpath);
179
+ element.setAttribute('download', record.name);
180
+ document.body.appendChild(element);
181
+ element.click();
182
+ }
183
+ }
184
+ },
185
+ {
186
+ type: 'string',
187
+ name: 'id',
188
+ hidden: true
189
+ },
190
+ {
191
+ type: 'string',
192
+ name: 'name',
193
+ header: 'name',
194
+ record: {
195
+ editable: true,
196
+ align: 'left'
197
+ },
198
+ width: 200,
199
+ sortable: true
200
+ },
201
+ {
202
+ type: 'string',
203
+ name: 'description',
204
+ header: 'description',
205
+ record: {
206
+ editable: true,
207
+ align: 'left'
208
+ },
209
+ width: 200,
210
+ handlers: {
211
+ dblclick: (columns, data, column, record, rowIndex) => {
212
+ alert(`${column.name} ${record[column.name]}, row : ${rowIndex}`);
213
+ }
214
+ }
215
+ },
216
+ {
217
+ type: 'datetime',
218
+ name: 'updatedAt',
219
+ header: 'updated at',
220
+ record: {
221
+ editable: true
222
+ },
223
+ sortable: true,
224
+ width: 180
225
+ },
226
+ {
227
+ type: 'datetime',
228
+ name: 'createdAt',
229
+ header: 'created at',
230
+ record: {
231
+ editable: true
232
+ },
233
+ sortable: true,
234
+ width: 180
235
+ }
236
+ ],
237
+ rows: {
238
+ selectable: {
239
+ multiple: true
240
+ },
241
+ handlers: {},
242
+ classifier: function (record, rowIndex) { }
243
+ },
244
+ sorters: [
245
+ {
246
+ name: 'name',
247
+ desc: false
248
+ }
249
+ ],
250
+ pagination: {
251
+ pages: [20, 30, 50, 100, 200]
252
+ }
253
+ };
254
+ }
255
+ async firstUpdated() {
256
+ this.refreshAttachments();
257
+ }
258
+ updated(changes) {
259
+ if (changes.has('category')) {
260
+ this.refreshAttachments();
261
+ }
262
+ }
263
+ onClickSelect(attachment) {
264
+ this.dispatchEvent(new CustomEvent('attachment-selected', {
265
+ composed: true,
266
+ bubbles: true,
267
+ detail: {
268
+ attachment
269
+ }
270
+ }));
271
+ }
272
+ async onAttachmentDropped(e) {
273
+ var files = e.detail;
274
+ await this.createAttachments('', files);
275
+ this.refreshAttachments();
276
+ }
277
+ async onCreateAttachment(e) {
278
+ var { category, files } = e.detail;
279
+ files = Array.from(files);
280
+ await this.createAttachments(category, files);
281
+ this.refreshAttachments();
282
+ }
283
+ async onDeleteAttachment(id) {
284
+ await this.deleteAttachment(id);
285
+ this.refreshAttachments();
286
+ }
287
+ async refreshAttachments() {
288
+ this.grist.fetch();
289
+ // var attachments = await this.getAttachments()
290
+ // this.attachments = [...attachments]
291
+ // var creationCard = this.shadowRoot.querySelector('attachment-creation-card')
292
+ // if (creationCard) {
293
+ // creationCard.reset()
294
+ // }
295
+ }
296
+ async appendAttachments() {
297
+ // var attachments = await this.getAttachments({ page: this._page + 1 })
298
+ // this.attachments = [...this.attachments, ...attachments]
299
+ }
300
+ async getAttachments({ page = 1, limit = 30, sorters = [] } = {}) {
301
+ var _a;
302
+ var filters = [];
303
+ var sortings = [];
304
+ var pagination = {
305
+ limit,
306
+ page
307
+ };
308
+ if (this.category)
309
+ filters.push({
310
+ name: 'category',
311
+ operator: 'eq',
312
+ value: this.category
313
+ });
314
+ var params = {
315
+ filters,
316
+ sortings,
317
+ pagination
318
+ };
319
+ var attachmentListResponse = await client.query({
320
+ query: FETCH_ATTACHMENT_LIST_GQL(params)
321
+ });
322
+ if (!attachmentListResponse || !attachmentListResponse.data) {
323
+ return {};
324
+ }
325
+ return ((_a = attachmentListResponse === null || attachmentListResponse === void 0 ? void 0 : attachmentListResponse.data) === null || _a === void 0 ? void 0 : _a.attachments) || {};
326
+ }
327
+ async createAttachments(category, files) {
328
+ /*
329
+ ref. https://github.com/jaydenseric/graphql-multipart-request-spec#client
330
+ - TODO support multiple file upload
331
+ */
332
+ await client.mutate({
333
+ mutation: CREATE_ATTACHMENTS_GQL,
334
+ variables: {
335
+ attachments: files.map(file => {
336
+ return { category, file };
337
+ })
338
+ },
339
+ context: {
340
+ hasUpload: true
341
+ }
342
+ });
343
+ }
344
+ async deleteAttachment(id) {
345
+ const response = await client.mutate({
346
+ mutation: DELETE_ATTACHMENT_GQL,
347
+ variables: {
348
+ id
349
+ }
350
+ });
351
+ return response.data;
352
+ }
353
+ };
354
+ OxAttachmentList.styles = [
355
+ ScrollbarStyles,
356
+ TooltipStyles,
357
+ css `
358
+ :host {
359
+ display: flex;
360
+
361
+ width: 100%;
362
+
363
+ --grid-record-emphasized-background-color: red;
364
+ --grid-record-emphasized-color: yellow;
365
+ }
366
+
367
+ ox-grist {
368
+ flex: 1;
369
+ overflow-y: auto;
370
+
371
+ --grid-record-emphasized-background-color: red;
372
+ --grid-record-emphasized-color: yellow;
373
+ }
374
+
375
+ #headroom {
376
+ display: flex;
377
+ flex-direction: row;
378
+ align-items: center;
379
+ padding: var(--padding-default) var(--padding-wide);
380
+ border-top: 2px solid rgba(0, 0, 0, 0.2);
381
+ background-color: var(--theme-white-color);
382
+ box-shadow: var(--box-shadow);
383
+ }
384
+
385
+ #filters {
386
+ flex: 1;
387
+ --mdc-icon-size: 20px;
388
+ }
389
+ #mode {
390
+ width: 100px;
391
+ }
392
+ #add {
393
+ width: 50px;
394
+ text-align: right;
395
+ }
396
+
397
+ #modes > * {
398
+ padding: var(--padding-narrow);
399
+ font-size: 1em;
400
+ opacity: 0.5;
401
+ color: var(--primary-text-color);
402
+ cursor: pointer;
403
+ }
404
+
405
+ #modes > mwc-icon[active] {
406
+ border-radius: 9px;
407
+ background-color: rgba(var(--primary-color-rgb), 0.05);
408
+ opacity: 1;
409
+ color: var(--secondary-text-color);
410
+ cursor: default;
411
+ }
412
+ #modes > mwc-icon:hover {
413
+ opacity: 1;
414
+ color: var(--secondary-text-color);
415
+ }
416
+
417
+ #add button {
418
+ background-color: var(--status-success-color);
419
+ border: 0;
420
+ border-radius: 50%;
421
+ padding: 5px;
422
+ width: 36px;
423
+ height: 36px;
424
+ cursor: pointer;
425
+ }
426
+ #add button:hover {
427
+ background-color: var(--focus-background-color);
428
+ box-shadow: var(--box-shadow);
429
+ }
430
+ #add button mwc-icon {
431
+ font-size: 2em;
432
+ color: var(--theme-white-color);
433
+ }
434
+
435
+ #filters {
436
+ position: relative;
437
+ }
438
+ #filters [type='text'] {
439
+ background-color: transparent;
440
+ border: 0;
441
+ border-bottom: var(--border-dark-color);
442
+ padding: var(--padding-narrow) var(--padding-narrow) 7px 25px;
443
+ font-size: var(--fontsize-large);
444
+ }
445
+ #filters [type='text']:focus {
446
+ outline: none;
447
+ }
448
+ #filters mwc-icon {
449
+ position: absolute;
450
+ top: 3px;
451
+ color: var(--secondary-color);
452
+ }
453
+ #filters * {
454
+ margin-right: var(--margin-default);
455
+ }
456
+
457
+ @media only screen and (max-width: 460px) {
458
+ #modes {
459
+ display: none;
460
+ }
461
+ }
462
+ `
463
+ ];
464
+ __decorate([
465
+ property({ type: Array })
466
+ ], OxAttachmentList.prototype, "categories", void 0);
467
+ __decorate([
468
+ property({ type: String })
469
+ ], OxAttachmentList.prototype, "mode", void 0);
470
+ __decorate([
471
+ property({ type: String })
472
+ ], OxAttachmentList.prototype, "category", void 0);
473
+ __decorate([
474
+ property({ type: Boolean })
475
+ ], OxAttachmentList.prototype, "creatable", void 0);
476
+ __decorate([
477
+ state()
478
+ ], OxAttachmentList.prototype, "_total", void 0);
479
+ __decorate([
480
+ state()
481
+ ], OxAttachmentList.prototype, "_page", void 0);
482
+ __decorate([
483
+ query('ox-grist')
484
+ ], OxAttachmentList.prototype, "grist", void 0);
485
+ OxAttachmentList = __decorate([
486
+ customElement('ox-attachment-list')
487
+ ], OxAttachmentList);
488
+ export { OxAttachmentList };
489
+ //# sourceMappingURL=ox-attachment-list.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ox-attachment-list.js","sourceRoot":"","sources":["../../src/ox-attachment-list.ts"],"names":[],"mappings":"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","sourcesContent":["// import './attachment-creation-card'\nimport '@operato/data-grist'\n\nimport gql from 'graphql-tag'\nimport i18next from 'i18next'\nimport { css, html, LitElement, PropertyValues } from 'lit'\nimport { customElement, property, query, state } from 'lit/decorators.js'\n\nimport { DataGrist, QueryFilter } from '@operato/data-grist'\nimport {\n ColumnConfig,\n GristData,\n GristRecord,\n PaginationConfig,\n SortersConfig\n} from '@operato/data-grist/dist/src/types'\nimport { buildArgs, client } from '@operato/graphql'\nimport { ScrollbarStyles, TooltipStyles } from '@operato/styles'\n\nconst FETCH_ATTACHMENT_LIST_GQL = (listParam: any) => {\n return gql`\n {\n attachments(${buildArgs(listParam)}) {\n items {\n id\n name\n description\n mimetype\n encoding\n category\n fullpath\n path\n }\n total\n }\n }\n`\n}\n\nconst DELETE_ATTACHMENT_GQL = gql`\n mutation DeleteAttachment($id: String!) {\n deleteAttachment(id: $id)\n }\n`\n\nconst CREATE_ATTACHMENTS_GQL = gql`\n mutation ($attachments: [NewAttachment!]!) {\n createAttachments(attachments: $attachments) {\n id\n name\n description\n mimetype\n encoding\n category\n path\n createdAt\n updatedAt\n }\n }\n`\n\n@customElement('ox-attachment-list')\nexport class OxAttachmentList extends LitElement {\n static styles = [\n ScrollbarStyles,\n TooltipStyles,\n css`\n :host {\n display: flex;\n\n width: 100%;\n\n --grid-record-emphasized-background-color: red;\n --grid-record-emphasized-color: yellow;\n }\n\n ox-grist {\n flex: 1;\n overflow-y: auto;\n\n --grid-record-emphasized-background-color: red;\n --grid-record-emphasized-color: yellow;\n }\n\n #headroom {\n display: flex;\n flex-direction: row;\n align-items: center;\n padding: var(--padding-default) var(--padding-wide);\n border-top: 2px solid rgba(0, 0, 0, 0.2);\n background-color: var(--theme-white-color);\n box-shadow: var(--box-shadow);\n }\n\n #filters {\n flex: 1;\n --mdc-icon-size: 20px;\n }\n #mode {\n width: 100px;\n }\n #add {\n width: 50px;\n text-align: right;\n }\n\n #modes > * {\n padding: var(--padding-narrow);\n font-size: 1em;\n opacity: 0.5;\n color: var(--primary-text-color);\n cursor: pointer;\n }\n\n #modes > mwc-icon[active] {\n border-radius: 9px;\n background-color: rgba(var(--primary-color-rgb), 0.05);\n opacity: 1;\n color: var(--secondary-text-color);\n cursor: default;\n }\n #modes > mwc-icon:hover {\n opacity: 1;\n color: var(--secondary-text-color);\n }\n\n #add button {\n background-color: var(--status-success-color);\n border: 0;\n border-radius: 50%;\n padding: 5px;\n width: 36px;\n height: 36px;\n cursor: pointer;\n }\n #add button:hover {\n background-color: var(--focus-background-color);\n box-shadow: var(--box-shadow);\n }\n #add button mwc-icon {\n font-size: 2em;\n color: var(--theme-white-color);\n }\n\n #filters {\n position: relative;\n }\n #filters [type='text'] {\n background-color: transparent;\n border: 0;\n border-bottom: var(--border-dark-color);\n padding: var(--padding-narrow) var(--padding-narrow) 7px 25px;\n font-size: var(--fontsize-large);\n }\n #filters [type='text']:focus {\n outline: none;\n }\n #filters mwc-icon {\n position: absolute;\n top: 3px;\n color: var(--secondary-color);\n }\n #filters * {\n margin-right: var(--margin-default);\n }\n\n @media only screen and (max-width: 460px) {\n #modes {\n display: none;\n }\n }\n `\n ]\n\n @property({ type: Array }) categories: any[] = ['audio', 'video', 'image', 'text', 'application']\n @property({ type: String }) mode: 'GRID' | 'LIST' | 'CARD' = 'CARD'\n @property({ type: String }) category: string = ''\n @property({ type: Boolean }) creatable: boolean = false\n\n @state() private _total: number = 0\n @state() private _page: number = 1\n\n @query('ox-grist') private grist!: DataGrist\n\n render() {\n const mode = this.mode || 'CARD'\n\n return html`\n <ox-grist .config=${this.gristConfig} .mode=${mode} auto-fetch .fetchHandler=${this.fetchHandler.bind(this)}>\n <div slot=\"headroom\" id=\"headroom\">\n <div id=\"filters\">\n <mwc-icon>search</mwc-icon>\n <input type=\"text\" />\n\n <select\n @change=${(e: Event) => {\n this.category = (e.currentTarget as HTMLInputElement)?.value\n this.requestUpdate()\n }}\n >\n <option value=\"\">--${i18next.t('text.please choose a category')}--</option>\n ${this.categories.map(\n category =>\n html` <option value=${category} ?selected=${this.category == category}>${category}</option> `\n )}\n </select>\n </div>\n\n <div id=\"modes\">\n <mwc-icon @click=${() => (this.mode = 'GRID')} ?active=${mode == 'GRID'}>grid_on</mwc-icon>\n <mwc-icon @click=${() => (this.mode = 'LIST')} ?active=${mode == 'LIST'}>format_list_bulleted</mwc-icon>\n <mwc-icon @click=${() => (this.mode = 'CARD')} ?active=${mode == 'CARD'}>apps</mwc-icon>\n </div>\n\n <!-- ${this.creatable\n ? html`\n <attachment-creation-card\n class=\"card create\"\n .categories=${this.categories}\n .defaultCategory=${this.category}\n @create-attachment=${(e: CustomEvent) => this.onCreateAttachment(e)}\n @file-drop=${(e: CustomEvent) => this.onAttachmentDropped(e)}\n ></attachment-creation-card>\n `\n : undefined} -->\n </div>\n </ox-grist>\n `\n }\n\n async fetchHandler({ page, limit, sorters = [] }: { page: number; limit: number; sorters: SortersConfig }) {\n const { items: records, total } = await this.getAttachments({ page, limit, sorters })\n\n return {\n total,\n records\n }\n }\n\n get gristConfig() {\n return {\n list: {\n thumbnail: function (record: GristRecord, rowIndex: number) {\n return record.category == 'image'\n ? html` <img src=${record.fullpath} style=\"width: 100%; height: 100%;\" /> `\n : record.category == 'video'\n ? html` <video src=${record.fullpath} style=\"width: 100%; height: 100%;\" controls></video> `\n : html`\n <div style=\"width: 100%; height: 100%;\" etc>\n <mwc-icon outlined>insert_drive_file</mwc-icon>\n <span>${record.path.substr(record.path.lastIndexOf('.'))}</span>\n </div>\n `\n },\n fields: ['name'],\n details: ['updatedAt']\n },\n columns: [\n {\n type: 'gutter',\n gutterName: 'dirty'\n },\n {\n type: 'gutter',\n gutterName: 'sequence'\n },\n {\n type: 'gutter',\n gutterName: 'button',\n icon: 'open_in_new',\n handlers: {\n click: (\n columns: ColumnConfig[],\n data: GristData,\n column: ColumnConfig,\n record: GristRecord,\n rowIndex: number\n ): void => {\n window.open(record.fullpath, '_blank')\n }\n }\n },\n {\n type: 'gutter',\n gutterName: 'button',\n icon: 'link',\n handlers: {\n click: async (\n columns: ColumnConfig[],\n data: GristData,\n column: ColumnConfig,\n record: GristRecord,\n rowIndex: number\n ): Promise<void> => {\n var { protocol, hostname, port } = location\n await navigator.clipboard.writeText(`${protocol}//${hostname}:${port}${record.fullpath}`)\n\n // TODO how to access clicked target\n // this.setAttribute('data-tooltip', 'url copied!')\n // await sleep(2000)\n // this.removeAttribute('data-tooltip')\n }\n }\n },\n {\n type: 'gutter',\n gutterName: 'button',\n icon: 'delete',\n handlers: {\n click: async (\n columns: ColumnConfig[],\n data: GristData,\n column: ColumnConfig,\n record: GristRecord,\n rowIndex: number\n ): Promise<void> => {\n await this.deleteAttachment(record.id!)\n this.refreshAttachments()\n }\n }\n },\n {\n type: 'gutter',\n gutterName: 'button',\n icon: 'save_alt',\n handlers: {\n click: (\n columns: ColumnConfig[],\n data: GristData,\n column: ColumnConfig,\n record: GristRecord,\n rowIndex: number\n ): void => {\n const element = document.createElement('a')\n element.setAttribute('href', record.fullpath)\n element.setAttribute('download', record.name!)\n document.body.appendChild(element)\n element.click()\n }\n }\n },\n {\n type: 'string',\n name: 'id',\n hidden: true\n },\n {\n type: 'string',\n name: 'name',\n header: 'name',\n record: {\n editable: true,\n align: 'left'\n },\n width: 200,\n sortable: true\n },\n {\n type: 'string',\n name: 'description',\n header: 'description',\n record: {\n editable: true,\n align: 'left'\n },\n width: 200,\n handlers: {\n dblclick: (\n columns: ColumnConfig[],\n data: GristData,\n column: ColumnConfig,\n record: GristRecord,\n rowIndex: number\n ): void => {\n alert(`${column.name} ${record[column.name]}, row : ${rowIndex}`)\n }\n }\n },\n {\n type: 'datetime',\n name: 'updatedAt',\n header: 'updated at',\n record: {\n editable: true\n },\n sortable: true,\n width: 180\n },\n {\n type: 'datetime',\n name: 'createdAt',\n header: 'created at',\n record: {\n editable: true\n },\n sortable: true,\n width: 180\n }\n ],\n rows: {\n selectable: {\n multiple: true\n },\n handlers: {},\n classifier: function (\n record: GristRecord,\n rowIndex: number\n ): { emphasized?: boolean | string | string[]; [key: string]: any } | void {}\n },\n sorters: [\n {\n name: 'name',\n desc: false\n }\n ],\n pagination: {\n pages: [20, 30, 50, 100, 200]\n }\n }\n }\n\n async firstUpdated() {\n this.refreshAttachments()\n }\n\n updated(changes: PropertyValues<this>) {\n if (changes.has('category')) {\n this.refreshAttachments()\n }\n }\n\n onClickSelect(attachment: any) {\n this.dispatchEvent(\n new CustomEvent('attachment-selected', {\n composed: true,\n bubbles: true,\n detail: {\n attachment\n }\n })\n )\n }\n\n async onAttachmentDropped(e: CustomEvent) {\n var files = e.detail\n\n await this.createAttachments('', files)\n this.refreshAttachments()\n }\n\n async onCreateAttachment(e: CustomEvent) {\n var { category, files } = e.detail\n\n files = Array.from(files)\n\n await this.createAttachments(category, files)\n this.refreshAttachments()\n }\n\n async onDeleteAttachment(id: string) {\n await this.deleteAttachment(id)\n\n this.refreshAttachments()\n }\n\n async refreshAttachments() {\n this.grist.fetch()\n // var attachments = await this.getAttachments()\n // this.attachments = [...attachments]\n\n // var creationCard = this.shadowRoot.querySelector('attachment-creation-card')\n // if (creationCard) {\n // creationCard.reset()\n // }\n }\n\n async appendAttachments() {\n // var attachments = await this.getAttachments({ page: this._page + 1 })\n // this.attachments = [...this.attachments, ...attachments]\n }\n\n async getAttachments({\n page = 1,\n limit = 30,\n sorters = []\n }: { page?: number; limit?: number; sorters?: SortersConfig } = {}) {\n var filters: QueryFilter[] = []\n var sortings: SortersConfig = []\n var pagination: PaginationConfig = {\n limit,\n page\n }\n\n if (this.category)\n filters.push({\n name: 'category',\n operator: 'eq',\n value: this.category\n })\n\n var params = {\n filters,\n sortings,\n pagination\n }\n\n var attachmentListResponse = await client.query({\n query: FETCH_ATTACHMENT_LIST_GQL(params)\n })\n\n if (!attachmentListResponse || !attachmentListResponse.data) {\n return {}\n }\n\n return attachmentListResponse?.data?.attachments || {}\n }\n\n async createAttachments(category: string, files: File[]) {\n /*\n ref. https://github.com/jaydenseric/graphql-multipart-request-spec#client\n - TODO support multiple file upload\n */\n\n await client.mutate({\n mutation: CREATE_ATTACHMENTS_GQL,\n variables: {\n attachments: files.map(file => {\n return { category, file }\n })\n },\n context: {\n hasUpload: true\n }\n })\n }\n\n async deleteAttachment(id: string) {\n const response = await client.mutate({\n mutation: DELETE_ATTACHMENT_GQL,\n variables: {\n id\n }\n })\n\n return response.data\n }\n}\n"]}