terrier-engine 4.51.1 → 4.51.3
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/data-dive/dives/dive-editor.ts +59 -50
- package/package.json +2 -2
- package/terrier/glyps.ts +2 -2
- package/terrier/plugins/load-on-scroll-plugin.ts +24 -46
- package/terrier/tabs.ts +48 -31
|
@@ -1,26 +1,25 @@
|
|
|
1
|
-
import Schema, {SchemaDef} from "../../terrier/schema"
|
|
2
|
-
import {PartTag} from "tuff-core/parts"
|
|
1
|
+
import Schema, { SchemaDef } from "../../terrier/schema"
|
|
2
|
+
import { PartTag } from "tuff-core/parts"
|
|
3
3
|
import Dives from "./dives"
|
|
4
|
-
import Queries, {Query, QueryModelPicker} from "../queries/queries"
|
|
4
|
+
import Queries, { Query, QueryModelPicker } from "../queries/queries"
|
|
5
5
|
import QueryEditor from "../queries/query-editor"
|
|
6
|
-
import {Logger} from "tuff-core/logging"
|
|
6
|
+
import { Logger } from "tuff-core/logging"
|
|
7
7
|
import QueryForm from "../queries/query-form"
|
|
8
|
-
import {TabContainerPart} from "../../terrier/tabs"
|
|
8
|
+
import { TabContainerPart } from "../../terrier/tabs"
|
|
9
9
|
import ContentPart from "../../terrier/parts/content-part"
|
|
10
|
-
import {ModalPart} from "../../terrier/modals"
|
|
11
|
-
import {DdDive} from "../gen/models"
|
|
10
|
+
import { ModalPart } from "../../terrier/modals"
|
|
11
|
+
import { DdDive } from "../gen/models"
|
|
12
12
|
import Ids from "../../terrier/ids"
|
|
13
13
|
import Db from "../dd-db"
|
|
14
14
|
import DdSession from "../dd-session"
|
|
15
|
-
import {DiveRunModal} from "./dive-runs"
|
|
15
|
+
import { DiveRunModal } from "./dive-runs"
|
|
16
16
|
import Nav from "tuff-core/nav"
|
|
17
17
|
import Messages from "tuff-core/messages"
|
|
18
|
-
import
|
|
19
|
-
import {FormFields} from "tuff-core/forms"
|
|
18
|
+
import { FormFields } from "tuff-core/forms"
|
|
20
19
|
import Fragments from "../../terrier/fragments"
|
|
21
|
-
import {DiveDeliveryPanel} from "./dive-delivery"
|
|
20
|
+
import { DiveDeliveryPanel } from "./dive-delivery"
|
|
22
21
|
import DivePlotList from "../plots/dive-plot-list"
|
|
23
|
-
import {DivePage} from "./dive-page"
|
|
22
|
+
import { DivePage } from "./dive-page"
|
|
24
23
|
|
|
25
24
|
const log = new Logger("DiveEditor")
|
|
26
25
|
|
|
@@ -49,11 +48,13 @@ export default class DiveEditor extends ContentPart<DiveEditorState> {
|
|
|
49
48
|
|
|
50
49
|
static readonly diveChangedKey = Messages.untypedKey()
|
|
51
50
|
|
|
52
|
-
queries = new
|
|
51
|
+
queries = new Map<string, Query>()
|
|
52
|
+
// Array of map keys to give the queries a sort order.
|
|
53
|
+
queryOrder = new Array<string>()
|
|
53
54
|
|
|
54
55
|
async init() {
|
|
55
|
-
this.queryTabs = this.makePart(TabContainerPart, {side: 'top'})
|
|
56
|
-
this.settingsTabs = this.makePart(TabContainerPart, {side: 'top'})
|
|
56
|
+
this.queryTabs = this.makePart(TabContainerPart, { side: 'top', reorderable: true })
|
|
57
|
+
this.settingsTabs = this.makePart(TabContainerPart, { side: 'top' })
|
|
57
58
|
|
|
58
59
|
this.queryTabs.addBeforeAction({
|
|
59
60
|
title: 'Queries:',
|
|
@@ -63,40 +64,48 @@ export default class DiveEditor extends ContentPart<DiveEditorState> {
|
|
|
63
64
|
title: "Add Another Query",
|
|
64
65
|
classes: ['dd-hint', 'arrow-right', 'glyp-hint'],
|
|
65
66
|
tooltip: "Each query represents a separate tab in the resulting spreadsheet",
|
|
66
|
-
click: {key: this.newQueryKey}
|
|
67
|
+
click: { key: this.newQueryKey }
|
|
67
68
|
})
|
|
68
69
|
this.queryTabs.addAfterAction({
|
|
69
70
|
icon: 'glyp-copy',
|
|
70
71
|
classes: ['duplicate-query'],
|
|
71
72
|
tooltip: "Duplicate this query",
|
|
72
|
-
click: {key: this.duplicateQueryKey}
|
|
73
|
+
click: { key: this.duplicateQueryKey }
|
|
73
74
|
})
|
|
74
75
|
this.queryTabs.addAfterAction({
|
|
75
76
|
icon: 'glyp-plus_outline',
|
|
76
77
|
classes: ['new-query'],
|
|
77
78
|
tooltip: "Add a new query to this Dive",
|
|
78
|
-
click: {key: this.newQueryKey}
|
|
79
|
+
click: { key: this.newQueryKey }
|
|
79
80
|
})
|
|
80
81
|
|
|
81
|
-
this.queries =
|
|
82
|
-
for (const query of this.queries) {
|
|
82
|
+
this.queries = new Map()
|
|
83
|
+
for (const query of this.state.dive.query_data?.queries || []) {
|
|
84
|
+
this.queries.set(query.id, query)
|
|
85
|
+
this.queryOrder.push(query.id)
|
|
83
86
|
this.addQueryTab(query)
|
|
84
87
|
}
|
|
85
88
|
|
|
86
89
|
this.listenMessage(QueryForm.settingsChangedKey, m => {
|
|
87
90
|
const query = m.data
|
|
88
91
|
log.info(`Query settings changed`, query)
|
|
89
|
-
this.queryTabs.updateTab({key: query.id, title: query.name})
|
|
92
|
+
this.queryTabs.updateTab({ key: query.id, title: query.name })
|
|
93
|
+
})
|
|
94
|
+
|
|
95
|
+
// Reorder queries in the list when the tab sort order is updated.
|
|
96
|
+
this.listenMessage(this.queryTabs.tabsModifiedKey, m => {
|
|
97
|
+
const { newOrder } = m.data
|
|
98
|
+
this.queryOrder = newOrder
|
|
90
99
|
})
|
|
91
100
|
|
|
92
101
|
this.onClick(this.newQueryKey, _ => {
|
|
93
|
-
this.app.showModal(NewQueryModal, {editor: this as DiveEditor, schema: this.state.schema})
|
|
102
|
+
this.app.showModal(NewQueryModal, { editor: this as DiveEditor, schema: this.state.schema })
|
|
94
103
|
})
|
|
95
104
|
|
|
96
105
|
this.onClick(this.duplicateQueryKey, _ => {
|
|
97
106
|
const id = this.queryTabs.currentTagKey
|
|
98
107
|
if (id?.length) {
|
|
99
|
-
const query = this.queries.
|
|
108
|
+
const query = this.queries.get(id)
|
|
100
109
|
if (query) {
|
|
101
110
|
this.app.showModal(DuplicateQueryModal, {
|
|
102
111
|
editor: this as DiveEditor,
|
|
@@ -114,7 +123,7 @@ export default class DiveEditor extends ContentPart<DiveEditorState> {
|
|
|
114
123
|
})
|
|
115
124
|
|
|
116
125
|
this.onClick(DiveEditor.deleteQueryKey, m => {
|
|
117
|
-
this.app.confirm({title: "Delete Query", icon: 'glyp-delete', body: "Are you sure you want to delete this query?"}, () => {
|
|
126
|
+
this.app.confirm({ title: "Delete Query", icon: 'glyp-delete', body: "Are you sure you want to delete this query?" }, () => {
|
|
118
127
|
this.deleteQuery(m.data.id)
|
|
119
128
|
})
|
|
120
129
|
})
|
|
@@ -137,7 +146,7 @@ export default class DiveEditor extends ContentPart<DiveEditorState> {
|
|
|
137
146
|
* @param query
|
|
138
147
|
*/
|
|
139
148
|
addQuery(query: Query) {
|
|
140
|
-
this.queries.
|
|
149
|
+
this.queries.set(query.id, query)
|
|
141
150
|
this.addQueryTab(query)
|
|
142
151
|
}
|
|
143
152
|
|
|
@@ -146,16 +155,17 @@ export default class DiveEditor extends ContentPart<DiveEditorState> {
|
|
|
146
155
|
* @param query
|
|
147
156
|
*/
|
|
148
157
|
private addQueryTab(query: Query) {
|
|
149
|
-
const state = {...this.state, query}
|
|
150
|
-
this.queryTabs.upsertTab({key: query.id, title: query.name}, QueryEditor, state)
|
|
158
|
+
const state = { ...this.state, query }
|
|
159
|
+
this.queryTabs.upsertTab({ key: query.id, title: query.name }, QueryEditor, state)
|
|
151
160
|
}
|
|
152
161
|
|
|
153
162
|
deleteQuery(id: string) {
|
|
154
163
|
log.info(`Deleting query ${id}`)
|
|
155
|
-
if (
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
164
|
+
if (!this.queries.has(id)) return
|
|
165
|
+
|
|
166
|
+
this.queries.delete(id)
|
|
167
|
+
this.queryTabs.removeTab(id)
|
|
168
|
+
this.dirty()
|
|
159
169
|
}
|
|
160
170
|
|
|
161
171
|
get parentClasses(): Array<string> {
|
|
@@ -178,7 +188,7 @@ export default class DiveEditor extends ContentPart<DiveEditorState> {
|
|
|
178
188
|
|
|
179
189
|
return {
|
|
180
190
|
...this.state.dive,
|
|
181
|
-
query_data: {queries}
|
|
191
|
+
query_data: { queries: this.queryOrder.map(id => queries.get(id)!) }
|
|
182
192
|
}
|
|
183
193
|
}
|
|
184
194
|
|
|
@@ -189,7 +199,7 @@ export default class DiveEditor extends ContentPart<DiveEditorState> {
|
|
|
189
199
|
// Editor Page
|
|
190
200
|
////////////////////////////////////////////////////////////////////////////////
|
|
191
201
|
|
|
192
|
-
export class DiveEditorPage extends DivePage<{id: string}> {
|
|
202
|
+
export class DiveEditorPage extends DivePage<{ id: string }> {
|
|
193
203
|
|
|
194
204
|
editor!: DiveEditor
|
|
195
205
|
session!: DdSession
|
|
@@ -205,7 +215,7 @@ export class DiveEditorPage extends DivePage<{id: string}> {
|
|
|
205
215
|
const schema = await Schema.get()
|
|
206
216
|
this.session = await DdSession.get()
|
|
207
217
|
const dive = await Dives.get(this.state.id)
|
|
208
|
-
this.editor = this.makePart(DiveEditor, {schema, dive, session: this.session})
|
|
218
|
+
this.editor = this.makePart(DiveEditor, { schema, dive, session: this.session })
|
|
209
219
|
|
|
210
220
|
this.mainContentWidth = 'wide'
|
|
211
221
|
|
|
@@ -240,20 +250,20 @@ export class DiveEditorPage extends DivePage<{id: string}> {
|
|
|
240
250
|
title: 'Discard',
|
|
241
251
|
icon: 'glyp-cancelled',
|
|
242
252
|
classes: ['discard-dive-action'],
|
|
243
|
-
click: {key: this.discardKey}
|
|
253
|
+
click: { key: this.discardKey }
|
|
244
254
|
}, 'tertiary')
|
|
245
255
|
|
|
246
256
|
this.addAction({
|
|
247
257
|
title: 'Save',
|
|
248
258
|
icon: 'glyp-complete',
|
|
249
259
|
classes: ['save-dive-action'],
|
|
250
|
-
click: {key: this.saveKey}
|
|
260
|
+
click: { key: this.saveKey }
|
|
251
261
|
}, 'tertiary')
|
|
252
262
|
|
|
253
263
|
this.addAction({
|
|
254
264
|
title: 'Run',
|
|
255
265
|
icon: 'glyp-play',
|
|
256
|
-
click: {key: this.runKey}
|
|
266
|
+
click: { key: this.runKey }
|
|
257
267
|
}, 'tertiary')
|
|
258
268
|
|
|
259
269
|
this.onClick(this.discardKey, _ => {
|
|
@@ -275,7 +285,7 @@ export class DiveEditorPage extends DivePage<{id: string}> {
|
|
|
275
285
|
this.listenMessage(DiveEditor.diveChangedKey, _ => {
|
|
276
286
|
log.info("Dive changed")
|
|
277
287
|
this.element?.classList.add('changed')
|
|
278
|
-
}, {attach: 'passive'})
|
|
288
|
+
}, { attach: 'passive' })
|
|
279
289
|
|
|
280
290
|
this.dirty()
|
|
281
291
|
}
|
|
@@ -303,7 +313,7 @@ export class DiveEditorPage extends DivePage<{id: string}> {
|
|
|
303
313
|
|
|
304
314
|
async run() {
|
|
305
315
|
const dive = await this.editor.serialize()
|
|
306
|
-
this.app.showModal(DiveRunModal, {dive})
|
|
316
|
+
this.app.showModal(DiveRunModal, { dive })
|
|
307
317
|
}
|
|
308
318
|
}
|
|
309
319
|
|
|
@@ -324,8 +334,8 @@ class NewQueryModal extends ModalPart<NewQueryState> {
|
|
|
324
334
|
modelPicker!: QueryModelPicker
|
|
325
335
|
|
|
326
336
|
async init() {
|
|
327
|
-
this.settingsForm = this.makePart(QueryForm, {query: {id: 'new', name: '', notes: ''}})
|
|
328
|
-
this.modelPicker = this.makePart(QueryModelPicker, {schema: this.state.schema})
|
|
337
|
+
this.settingsForm = this.makePart(QueryForm, { query: { id: 'new', name: '', notes: '' } })
|
|
338
|
+
this.modelPicker = this.makePart(QueryModelPicker, { schema: this.state.schema })
|
|
329
339
|
|
|
330
340
|
this.setIcon('glyp-data_dive_query')
|
|
331
341
|
this.setTitle("New Query")
|
|
@@ -333,7 +343,7 @@ class NewQueryModal extends ModalPart<NewQueryState> {
|
|
|
333
343
|
this.addAction({
|
|
334
344
|
title: "Add",
|
|
335
345
|
icon: 'glyp-plus',
|
|
336
|
-
click: {key: this.addKey}
|
|
346
|
+
click: { key: this.addKey }
|
|
337
347
|
})
|
|
338
348
|
|
|
339
349
|
this.onClick(this.addKey, async _ => {
|
|
@@ -361,16 +371,16 @@ class NewQueryModal extends ModalPart<NewQueryState> {
|
|
|
361
371
|
log.info(`Saving new query`)
|
|
362
372
|
const settings = await this.settingsForm.fields.serialize()
|
|
363
373
|
if (!settings.name?.length) {
|
|
364
|
-
this.showToast("Please enter a query name", {color: 'alert'})
|
|
374
|
+
this.showToast("Please enter a query name", { color: 'alert' })
|
|
365
375
|
this.dirty()
|
|
366
376
|
return
|
|
367
377
|
}
|
|
368
378
|
const model = this.modelPicker.model
|
|
369
379
|
if (!model) {
|
|
370
|
-
this.showToast("Please select a model", {color: 'alert'})
|
|
380
|
+
this.showToast("Please select a model", { color: 'alert' })
|
|
371
381
|
return
|
|
372
382
|
}
|
|
373
|
-
const query = {...settings, id: Ids.makeUuid(), from: {model: model.name}}
|
|
383
|
+
const query = { ...settings, id: Ids.makeUuid(), from: { model: model.name } }
|
|
374
384
|
this.state.editor.addQuery(query)
|
|
375
385
|
this.state.editor.queryTabs.showTab(query.id)
|
|
376
386
|
this.pop()
|
|
@@ -398,13 +408,13 @@ class DuplicateQueryModal extends ModalPart<DuplicateQueryState> {
|
|
|
398
408
|
this.setIcon('glyp-data_dive_query')
|
|
399
409
|
this.setTitle("Duplicate Query")
|
|
400
410
|
|
|
401
|
-
const newQuery = {...this.state.query, name: `${this.state.query.name} Copy`}
|
|
411
|
+
const newQuery = { ...this.state.query, name: `${this.state.query.name} Copy` }
|
|
402
412
|
this.fields = new FormFields<Query>(this, newQuery)
|
|
403
413
|
|
|
404
414
|
this.addAction({
|
|
405
415
|
title: "Duplicate",
|
|
406
416
|
icon: 'glyp-checkmark',
|
|
407
|
-
click: {key: this.dupKey}
|
|
417
|
+
click: { key: this.dupKey }
|
|
408
418
|
})
|
|
409
419
|
|
|
410
420
|
this.onClick(this.dupKey, async _ => {
|
|
@@ -414,7 +424,7 @@ class DuplicateQueryModal extends ModalPart<DuplicateQueryState> {
|
|
|
414
424
|
|
|
415
425
|
async save() {
|
|
416
426
|
const newName = this.fields.data.name
|
|
417
|
-
const query = {...Queries.duplicate(this.state.query), name: newName}
|
|
427
|
+
const query = { ...Queries.duplicate(this.state.query), name: newName }
|
|
418
428
|
this.state.editor.addQuery(query)
|
|
419
429
|
this.state.editor.queryTabs.showTab(query.id)
|
|
420
430
|
this.pop()
|
|
@@ -428,5 +438,4 @@ class DuplicateQueryModal extends ModalPart<DuplicateQueryState> {
|
|
|
428
438
|
this.fields.textInput(col, 'name')
|
|
429
439
|
})
|
|
430
440
|
}
|
|
431
|
-
}
|
|
432
|
-
|
|
441
|
+
}
|
package/package.json
CHANGED
package/terrier/glyps.ts
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
// This file was automatically generated by glyps:compile on
|
|
1
|
+
// This file was automatically generated by glyps:compile on 05/19/25 1:37 PM, DO NOT MANUALLY EDIT!
|
|
2
2
|
|
|
3
3
|
import Strings from "tuff-core/strings"
|
|
4
4
|
|
|
5
|
-
const names = ['glyp-abacus', 'glyp-account', 'glyp-accounts_payable', 'glyp-accounts_receivable', 'glyp-action_log', 'glyp-activate', 'glyp-activate_user', 'glyp-active', 'glyp-activity_high', 'glyp-activity_low', 'glyp-activity_medium', 'glyp-activity_none', 'glyp-address1', 'glyp-adjustment', 'glyp-admin', 'glyp-administration', 'glyp-affinity', 'glyp-agency', 'glyp-air_freshener', 'glyp-alert', 'glyp-align_horizontal', 'glyp-align_vertical', 'glyp-anchor', 'glyp-android_phone', 'glyp-android_tablet', 'glyp-annotation', 'glyp-announcement', 'glyp-app_update', 'glyp-append_selection', 'glyp-appointment', 'glyp-appointment_setup', 'glyp-archive', 'glyp-arrow_down', 'glyp-arrow_left', 'glyp-arrow_right', 'glyp-arrow_transfer', 'glyp-arrow_up', 'glyp-ascending', 'glyp-assign', 'glyp-assign_all', 'glyp-attachment', 'glyp-audit', 'glyp-audit_analyzer', 'glyp-audits', 'glyp-autopay', 'glyp-availability', 'glyp-background_batch', 'glyp-background_job', 'glyp-background_style', 'glyp-bait_for_demolition', 'glyp-bar_chart', 'glyp-barcode', 'glyp-bat_exclusion', 'glyp-bed_bug_fumigation', 'glyp-begin_service', 'glyp-belongs_to', 'glyp-billing', 'glyp-billing_office', 'glyp-billing_terms', 'glyp-billto', 'glyp-bioremediation', 'glyp-bird_exclusion', 'glyp-black_light', 'glyp-bookmark', 'glyp-branch', 'glyp-branch_bats', 'glyp-branch_birds', 'glyp-branch_general', 'glyp-branch_irrigation', 'glyp-branch_landscape', 'glyp-branch_multi_housing', 'glyp-branch_office', 'glyp-branch_orders', 'glyp-branch_residential', 'glyp-branch_sales', 'glyp-branch_termites', 'glyp-branch_weeds', 'glyp-branch_wildlife', 'glyp-build', 'glyp-business', 'glyp-business_cert', 'glyp-business_cert_type', 'glyp-calculate', 'glyp-calendar', 'glyp-calendar_branch', 'glyp-calendar_map', 'glyp-calendar_rolling', 'glyp-calendar_share', 'glyp-calendar_snap', 'glyp-calendar_style', 'glyp-california', 'glyp-call', 'glyp-callback', 'glyp-camera', 'glyp-canada', 'glyp-cancellation', 'glyp-cancelled', 'glyp-card_american_express', 'glyp-card_discover', 'glyp-card_mastercard', 'glyp-card_visa', 'glyp-catalog', 'glyp-category', 'glyp-caught', 'glyp-cellulose_debris', 'glyp-cert', 'glyp-cert_timeline', 'glyp-cert_type', 'glyp-certificate', 'glyp-certified_summary', 'glyp-certs', 'glyp-ceu', 'glyp-check_all', 'glyp-check_in', 'glyp-check_in_service', 'glyp-checked', 'glyp-checked_check_all', 'glyp-checked_empty', 'glyp-checkmark', 'glyp-checkmark_filled', 'glyp-checkout', 'glyp-chemical', 'glyp-chemical_authorization', 'glyp-chemical_backpack_sprayer', 'glyp-chemical_biological_controls', 'glyp-chemical_disinfectant', 'glyp-chemical_fertilizer', 'glyp-chemical_flying_insect_bait', 'glyp-chemical_fumigants', 'glyp-chemical_insect_aerosol', 'glyp-chemical_insect_bait', 'glyp-chemical_insect_dust', 'glyp-chemical_insect_granules', 'glyp-chemical_insect_spray', 'glyp-chemical_label', 'glyp-chemical_mole_bait', 'glyp-chemical_pest_bird_control', 'glyp-chemical_pheromone_products', 'glyp-chemical_power_sprayer', 'glyp-chemical_rodent_attractant', 'glyp-chemical_rodenticide_block', 'glyp-chemical_rodenticide_non_block', 'glyp-chemical_sds', 'glyp-chemical_tree_products', 'glyp-chemical_weed_control', 'glyp-chemical_wildlife_repellents', 'glyp-chemical_wildlife_toxicants', 'glyp-chevron_down', 'glyp-chevron_left', 'glyp-chevron_right', 'glyp-chevron_up', 'glyp-circle', 'glyp-city', 'glyp-click', 'glyp-client_actions', 'glyp-client_pest_sightings', 'glyp-client_required', 'glyp-clipboard', 'glyp-close', 'glyp-close_empty', 'glyp-cloud', 'glyp-clyp_environment', 'glyp-clyp_settings', 'glyp-clypboard', 'glyp-clypedia', 'glyp-clypmart', 'glyp-code', 'glyp-code_details', 'glyp-collections', 'glyp-color', 'glyp-columns', 'glyp-comment', 'glyp-comment_filled', 'glyp-comments', 'glyp-commission_origin', 'glyp-commissions', 'glyp-compact', 'glyp-company_setup', 'glyp-compass', 'glyp-complete', 'glyp-complete_certificate', 'glyp-complete_enrollment', 'glyp-compressed', 'glyp-condition_appliance_machinery', 'glyp-condition_customer', 'glyp-condition_device', 'glyp-condition_door_window', 'glyp-condition_dumpster', 'glyp-condition_entry_point', 'glyp-condition_evidence', 'glyp-condition_exclusion', 'glyp-condition_exterior', 'glyp-condition_interior', 'glyp-condition_plumbing', 'glyp-condition_prep_storage', 'glyp-condition_rodent_evidence', 'glyp-condition_rodent_exclusion', 'glyp-condition_roof_ceiling', 'glyp-condition_structure', 'glyp-condition_supplies', 'glyp-condition_termites', 'glyp-condition_ventilation', 'glyp-condition_wall_floor', 'glyp-condition_wildlife', 'glyp-conditions', 'glyp-consolidate', 'glyp-construction', 'glyp-continuing_ed', 'glyp-contract', 'glyp-contract_cancellation', 'glyp-contract_overview', 'glyp-conversation', 'glyp-copesan', 'glyp-copy', 'glyp-county', 'glyp-credit_memo', 'glyp-credit_non_revenue', 'glyp-credit_production', 'glyp-credit_prospect', 'glyp-credit_sales_bonus', 'glyp-crew', 'glyp-cumulative', 'glyp-curriculum', 'glyp-cursor', 'glyp-custom_form', 'glyp-customer', 'glyp-customer_service', 'glyp-damage', 'glyp-dashboard', 'glyp-data_dive', 'glyp-data_dive_query', 'glyp-data_dives', 'glyp-database', 'glyp-deactivate_user', 'glyp-dead_animal_removal', 'glyp-default', 'glyp-delete', 'glyp-demo_mode', 'glyp-descending', 'glyp-design', 'glyp-desktop', 'glyp-detail_report', 'glyp-developer', 'glyp-device', 'glyp-device_sync', 'glyp-differential', 'glyp-disable', 'glyp-disabled_filled', 'glyp-distribute_horizontal', 'glyp-distribute_vertical', 'glyp-division', 'glyp-document', 'glyp-documentation', 'glyp-documents', 'glyp-download', 'glyp-driving', 'glyp-duplicate', 'glyp-duplicate_location', 'glyp-duration', 'glyp-earth_to_wood', 'glyp-edit', 'glyp-email', 'glyp-employment', 'glyp-entertainment_public_venues', 'glyp-equipment_bear_trap', 'glyp-equipment_flying_insect_bait_station', 'glyp-equipment_flying_insect_light_trap', 'glyp-equipment_insect_monitor', 'glyp-equipment_lethal_animal_trap', 'glyp-equipment_live_animal_trap', 'glyp-equipment_live_rodent_trap', 'glyp-equipment_maintenance', 'glyp-equipment_map_viewer', 'glyp-equipment_maps', 'glyp-equipment_mosquito_trap', 'glyp-equipment_other', 'glyp-equipment_pheromone_trap', 'glyp-equipment_pick_up', 'glyp-equipment_rodent_bait', 'glyp-equipment_rodent_trap', 'glyp-equipment_termite_bait_station', 'glyp-equipment_termite_monitor', 'glyp-escape', 'glyp-exam', 'glyp-exams', 'glyp-exclusion', 'glyp-existing_location', 'glyp-expand', 'glyp-expired', 'glyp-expiring', 'glyp-exterior', 'glyp-extras', 'glyp-facebook', 'glyp-family', 'glyp-farm', 'glyp-farm_grain_seed', 'glyp-fast_and_frequent', 'glyp-favorite', 'glyp-features', 'glyp-feedback', 'glyp-field_guide', 'glyp-field_training', 'glyp-file_blank', 'glyp-file_html', 'glyp-file_image', 'glyp-file_pdf', 'glyp-file_printable', 'glyp-file_spreadsheet', 'glyp-file_text', 'glyp-filter', 'glyp-finance', 'glyp-finding', 'glyp-fogging', 'glyp-folder', 'glyp-followup', 'glyp-food_bev_pharma', 'glyp-formula', 'glyp-fuel', 'glyp-fumigation', 'glyp-function', 'glyp-function_aggregate', 'glyp-function_time', 'glyp-gain_loss', 'glyp-generate_invoices', 'glyp-generate_orders', 'glyp-geo', 'glyp-geo_heat_map', 'glyp-geoboard', 'glyp-google', 'glyp-google_calendar', 'glyp-government', 'glyp-grain_seed', 'glyp-grid', 'glyp-grouped', 'glyp-grouping_combine', 'glyp-grouping_separate', 'glyp-guide', 'glyp-has_many', 'glyp-health_care', 'glyp-heat_map', 'glyp-heat_treatment', 'glyp-help', 'glyp-hidden', 'glyp-hint', 'glyp-home', 'glyp-honeybee_removal', 'glyp-housing', 'glyp-icon', 'glyp-identifier', 'glyp-image', 'glyp-images', 'glyp-import', 'glyp-import_certs', 'glyp-import_data', 'glyp-import_users', 'glyp-in_progress', 'glyp-inbox', 'glyp-incomplete_certificate', 'glyp-industrial', 'glyp-info', 'glyp-information_technology', 'glyp-inspect_map', 'glyp-inspections', 'glyp-insulation', 'glyp-interior', 'glyp-invoice', 'glyp-invoice_charge', 'glyp-invoice_credit', 'glyp-invoice_paid', 'glyp-invoice_review', 'glyp-ipad', 'glyp-iphone', 'glyp-irrigation_install', 'glyp-irrigation_maintenance', 'glyp-items', 'glyp-job', 'glyp-job_plan', 'glyp-job_plan_history', 'glyp-job_plan_run', 'glyp-job_plan_scheduled', 'glyp-job_plan_single_click', 'glyp-job_plan_step_by_step', 'glyp-join', 'glyp-join_inner', 'glyp-join_left', 'glyp-jump', 'glyp-justice', 'glyp-k9_inspection', 'glyp-key', 'glyp-label_bottom', 'glyp-label_left', 'glyp-label_right', 'glyp-label_top', 'glyp-labor', 'glyp-landscape', 'glyp-landscape_maintenance', 'glyp-laptop', 'glyp-lead', 'glyp-lead_listing', 'glyp-lead_source', 'glyp-leads_report', 'glyp-learning_hub', 'glyp-ledger', 'glyp-legal', 'glyp-license', 'glyp-lifetime', 'glyp-limit', 'glyp-line_cap_arrow', 'glyp-line_cap_bar', 'glyp-line_cap_circle', 'glyp-line_cap_none', 'glyp-line_caps', 'glyp-line_style', 'glyp-link', 'glyp-list', 'glyp-location', 'glyp-location_charge', 'glyp-location_credit', 'glyp-location_import', 'glyp-location_kind', 'glyp-location_message', 'glyp-location_origin', 'glyp-location_seed', 'glyp-location_tags', 'glyp-locations', 'glyp-locked', 'glyp-lodging', 'glyp-log_in', 'glyp-log_out', 'glyp-log_report', 'glyp-logbook', 'glyp-logbook_documents', 'glyp-lot_number', 'glyp-lycensed_simulator', 'glyp-manager', 'glyp-manual', 'glyp-map', 'glyp-markdown', 'glyp-market', 'glyp-materials', 'glyp-mattress_encasement', 'glyp-merge', 'glyp-message_billing', 'glyp-message_collections', 'glyp-message_complaint', 'glyp-message_misc', 'glyp-message_technician', 'glyp-messages', 'glyp-minus_outline', 'glyp-misc', 'glyp-miscellaneous', 'glyp-missing', 'glyp-moisture', 'glyp-move_order', 'glyp-mowing', 'glyp-multi_housing', 'glyp-multi_tech_order', 'glyp-mute', 'glyp-navicon', 'glyp-neighborhood', 'glyp-new_location', 'glyp-new_ticket', 'glyp-no_charge', 'glyp-no_service', 'glyp-note', 'glyp-note_access', 'glyp-note_billing', 'glyp-note_collection', 'glyp-note_complaint', 'glyp-note_directions', 'glyp-note_focused', 'glyp-note_office', 'glyp-note_preservice', 'glyp-note_sales', 'glyp-note_service', 'glyp-notification', 'glyp-nuke', 'glyp-number', 'glyp-occupant', 'glyp-office', 'glyp-office_government', 'glyp-office_training', 'glyp-offline_mode', 'glyp-on_demand', 'glyp-on_demand_order', 'glyp-online_mode', 'glyp-open', 'glyp-open_invoice', 'glyp-operations', 'glyp-options', 'glyp-order_actions', 'glyp-order_approved', 'glyp-order_batch', 'glyp-order_editor', 'glyp-order_pending', 'glyp-order_series', 'glyp-order_unapproved', 'glyp-org', 'glyp-org_feature', 'glyp-org_settings', 'glyp-org_structure', 'glyp-org_unit', 'glyp-org_unit_settings', 'glyp-orgs', 'glyp-origin', 'glyp-origin_client', 'glyp-origin_tech', 'glyp-outbox', 'glyp-outlier', 'glyp-outlook', 'glyp-overlap', 'glyp-password', 'glyp-past_due', 'glyp-pause', 'glyp-paused', 'glyp-pay_brackets', 'glyp-payment', 'glyp-payment_ach', 'glyp-payment_application_apply', 'glyp-payment_application_correction', 'glyp-payment_application_initial', 'glyp-payment_application_refund', 'glyp-payment_application_transfer', 'glyp-payment_application_unapply', 'glyp-payment_application_unapply_all', 'glyp-payment_applications', 'glyp-payment_batch', 'glyp-payment_cash', 'glyp-payment_check', 'glyp-payment_coupon', 'glyp-payment_credit', 'glyp-payment_discount', 'glyp-payment_eft', 'glyp-payment_finance_charge', 'glyp-payments', 'glyp-payroll', 'glyp-pdf', 'glyp-pending', 'glyp-periodic', 'glyp-periodic_assessment', 'glyp-permission', 'glyp-pest', 'glyp-pest_ants', 'glyp-pest_bats', 'glyp-pest_bed_bugs', 'glyp-pest_birds', 'glyp-pest_crawling_insects', 'glyp-pest_dermestids', 'glyp-pest_fall_invaders', 'glyp-pest_flying_insects', 'glyp-pest_moles', 'glyp-pest_mosquitoes', 'glyp-pest_nuisance_animals', 'glyp-pest_occasional_invaders', 'glyp-pest_ornamental', 'glyp-pest_ornamental_diseases', 'glyp-pest_roaches', 'glyp-pest_rodents', 'glyp-pest_scorpions', 'glyp-pest_snakes', 'glyp-pest_spiders', 'glyp-pest_stinging_insects', 'glyp-pest_stored_product_pests', 'glyp-pest_ticks_and_fleas', 'glyp-pest_viruses_and_bacteria', 'glyp-pest_weeds', 'glyp-pest_wood_destroyers', 'glyp-phone', 'glyp-pick_date', 'glyp-pick_list', 'glyp-platform_android', 'glyp-platform_ios', 'glyp-platform_macos', 'glyp-platform_windows', 'glyp-play', 'glyp-plus', 'glyp-plus_filled', 'glyp-plus_outline', 'glyp-portal', 'glyp-price_increase', 'glyp-price_increase_alt', 'glyp-pricing', 'glyp-pricing_table', 'glyp-print', 'glyp-privacy', 'glyp-product_sale', 'glyp-production', 'glyp-professional_consultation', 'glyp-profile', 'glyp-program', 'glyp-program_elements', 'glyp-program_initiation', 'glyp-program_order', 'glyp-program_review', 'glyp-promo', 'glyp-proposal', 'glyp-protection', 'glyp-purchase_order', 'glyp-quality', 'glyp-query', 'glyp-radio_checked', 'glyp-radio_empty', 'glyp-reassign', 'glyp-receipt', 'glyp-recent', 'glyp-reciprocity', 'glyp-recommendation', 'glyp-record_details', 'glyp-recurring_revenue', 'glyp-redo', 'glyp-refresh', 'glyp-refund', 'glyp-region', 'glyp-released', 'glyp-remove', 'glyp-renew', 'glyp-renewal', 'glyp-report', 'glyp-required_input', 'glyp-reschedule', 'glyp-restaurant_bar', 'glyp-revenue', 'glyp-review', 'glyp-rfid', 'glyp-ride_along', 'glyp-rodent_exclusion', 'glyp-role_admin', 'glyp-role_customer', 'glyp-role_super', 'glyp-role_tech', 'glyp-roster', 'glyp-route_change', 'glyp-route_optimization', 'glyp-rows', 'glyp-ruby', 'glyp-ruler', 'glyp-sales', 'glyp-sales_contest', 'glyp-sales_pipeline', 'glyp-sales_tax', 'glyp-sales_tax_exemption', 'glyp-schedule_lock', 'glyp-schedule_lock_afternoon', 'glyp-schedule_lock_day', 'glyp-schedule_lock_exact', 'glyp-schedule_lock_four_hour', 'glyp-schedule_lock_morning', 'glyp-schedule_lock_none', 'glyp-schedule_lock_two_day', 'glyp-schedule_lock_two_hour', 'glyp-schedule_lock_week', 'glyp-schedule_tyoe_every', 'glyp-schedule_type_every', 'glyp-schedule_type_none', 'glyp-schedule_type_on_demand', 'glyp-schedule_type_schedule', 'glyp-scheduled', 'glyp-scheduling', 'glyp-school_church', 'glyp-scope', 'glyp-scoreboard', 'glyp-scrape', 'glyp-script', 'glyp-search', 'glyp-seeding', 'glyp-segment', 'glyp-send', 'glyp-sent', 'glyp-sentricon', 'glyp-service_agreement', 'glyp-service_digest', 'glyp-service_form', 'glyp-service_form_new', 'glyp-service_form_settings', 'glyp-service_form_template', 'glyp-service_miscellaneous', 'glyp-service_reminder', 'glyp-service_report', 'glyp-service_request', 'glyp-services', 'glyp-settings', 'glyp-setup', 'glyp-signature', 'glyp-simulator', 'glyp-site_map', 'glyp-site_map_annotation', 'glyp-site_map_chemical', 'glyp-site_map_edit_details', 'glyp-site_map_edit_geo', 'glyp-site_map_equipment', 'glyp-site_map_exterior', 'glyp-site_map_foundation', 'glyp-site_map_icon', 'glyp-site_map_interior', 'glyp-site_map_label', 'glyp-site_map_perimeter', 'glyp-site_map_settings_left', 'glyp-site_map_settings_right', 'glyp-site_map_template', 'glyp-skill', 'glyp-skip', 'glyp-slope', 'glyp-smart_traps', 'glyp-sms', 'glyp-snow_removal', 'glyp-sort', 'glyp-special', 'glyp-split', 'glyp-spp_scorecard', 'glyp-square_edge', 'glyp-start_sheet', 'glyp-start_time', 'glyp-state_ak', 'glyp-state_al', 'glyp-state_ar', 'glyp-state_az', 'glyp-state_ca', 'glyp-state_co', 'glyp-state_ct', 'glyp-state_dc', 'glyp-state_de', 'glyp-state_fl', 'glyp-state_ga', 'glyp-state_hi', 'glyp-state_ia', 'glyp-state_id', 'glyp-state_il', 'glyp-state_in', 'glyp-state_ks', 'glyp-state_ky', 'glyp-state_la', 'glyp-state_ma', 'glyp-state_mb', 'glyp-state_md', 'glyp-state_me', 'glyp-state_mi', 'glyp-state_mn', 'glyp-state_mo', 'glyp-state_ms', 'glyp-state_mt', 'glyp-state_nc', 'glyp-state_nd', 'glyp-state_ne', 'glyp-state_nh', 'glyp-state_nj', 'glyp-state_nm', 'glyp-state_nv', 'glyp-state_ny', 'glyp-state_oh', 'glyp-state_ok', 'glyp-state_or', 'glyp-state_pa', 'glyp-state_ri', 'glyp-state_sc', 'glyp-state_sd', 'glyp-state_tn', 'glyp-state_tx', 'glyp-state_ut', 'glyp-state_va', 'glyp-state_vt', 'glyp-state_wa', 'glyp-state_wi', 'glyp-state_wv', 'glyp-state_wy', 'glyp-statement', 'glyp-states', 'glyp-steps', 'glyp-sticky', 'glyp-stop_time', 'glyp-store_material', 'glyp-store_order', 'glyp-store_order_back_order', 'glyp-store_order_cancelled', 'glyp-store_order_complete', 'glyp-store_order_pending', 'glyp-store_order_pending_return', 'glyp-store_order_pre_order', 'glyp-store_order_returned', 'glyp-stores', 'glyp-styling', 'glyp-subscribe', 'glyp-subscription', 'glyp-supplemental', 'glyp-support', 'glyp-sync', 'glyp-sync_down', 'glyp-sync_up', 'glyp-table', 'glyp-tablet', 'glyp-tablets', 'glyp-tag', 'glyp-tag_manager', 'glyp-tags', 'glyp-task_runs', 'glyp-taxability', 'glyp-tech_cert', 'glyp-tech_cert_type', 'glyp-tech_pest_sightings', 'glyp-technician', 'glyp-technician_approach', 'glyp-template', 'glyp-termite_fumigation', 'glyp-terrier', 'glyp-terrier_hub', 'glyp-terrier_sync', 'glyp-territory', 'glyp-text', 'glyp-thermometer', 'glyp-third_party', 'glyp-third_party_billing', 'glyp-threshold', 'glyp-ticket', 'glyp-ticket_type', 'glyp-tickets', 'glyp-tidy', 'glyp-time', 'glyp-time_entry', 'glyp-timeline', 'glyp-timer', 'glyp-toolbox', 'glyp-tqi', 'glyp-tracker', 'glyp-tracking', 'glyp-training_course', 'glyp-treatment_split', 'glyp-trends', 'glyp-trial', 'glyp-trip_charge', 'glyp-ui_type', 'glyp-unarchive', 'glyp-unassign', 'glyp-unassign_all', 'glyp-unchecked', 'glyp-undo', 'glyp-unfavorite', 'glyp-unit_sweep', 'glyp-unit_tag', 'glyp-university', 'glyp-unlocked', 'glyp-unmute', 'glyp-unscheduled', 'glyp-update_check_positions', 'glyp-upload', 'glyp-user', 'glyp-user_credit', 'glyp-user_tags', 'glyp-users', 'glyp-utility', 'glyp-vacation', 'glyp-vacuum', 'glyp-variant', 'glyp-vendor', 'glyp-versions', 'glyp-video', 'glyp-visible', 'glyp-warehouse', 'glyp-wdi', 'glyp-wdi_az', 'glyp-wdi_ca', 'glyp-wdi_npma', 'glyp-wdi_nv', 'glyp-wdo', 'glyp-web_dusting', 'glyp-website', 'glyp-wildlife', 'glyp-wildlife_exclusion', 'glyp-winter_check', 'glyp-wizard', 'glyp-work', 'glyp-work_class', 'glyp-work_code', 'glyp-work_order', 'glyp-work_production', 'glyp-work_progress', 'glyp-work_yield', 'glyp-year', 'glyp-yield', 'glyp-zip_code', 'glyp-zone_adjacent', 'glyp-zone_check', 'glyp-zone_production', 'glyp-zone_remote', 'glyp-zoom', 'glyp-zoom_fit'] as const
|
|
5
|
+
const names = ['glyp-abacus', 'glyp-account', 'glyp-accounts_payable', 'glyp-accounts_receivable', 'glyp-action_log', 'glyp-activate', 'glyp-activate_user', 'glyp-active', 'glyp-activity_high', 'glyp-activity_low', 'glyp-activity_medium', 'glyp-activity_none', 'glyp-address1', 'glyp-adjustment', 'glyp-admin', 'glyp-administration', 'glyp-affinity', 'glyp-agency', 'glyp-air_freshener', 'glyp-alert', 'glyp-align_horizontal', 'glyp-align_vertical', 'glyp-anchor', 'glyp-android_phone', 'glyp-android_tablet', 'glyp-annotation', 'glyp-announcement', 'glyp-app_update', 'glyp-append_selection', 'glyp-appointment', 'glyp-appointment_setup', 'glyp-archive', 'glyp-arrow_down', 'glyp-arrow_left', 'glyp-arrow_right', 'glyp-arrow_transfer', 'glyp-arrow_up', 'glyp-ascending', 'glyp-assign', 'glyp-assign_all', 'glyp-attachment', 'glyp-audit', 'glyp-audit_analyzer', 'glyp-audits', 'glyp-autopay', 'glyp-autopay_bank_account', 'glyp-availability', 'glyp-background_batch', 'glyp-background_job', 'glyp-background_style', 'glyp-bait_for_demolition', 'glyp-bar_chart', 'glyp-barcode', 'glyp-bat_exclusion', 'glyp-bed_bug_fumigation', 'glyp-begin_service', 'glyp-belongs_to', 'glyp-billing', 'glyp-billing_office', 'glyp-billing_terms', 'glyp-billto', 'glyp-bioremediation', 'glyp-bird_exclusion', 'glyp-black_light', 'glyp-bookmark', 'glyp-branch', 'glyp-branch_bats', 'glyp-branch_birds', 'glyp-branch_general', 'glyp-branch_irrigation', 'glyp-branch_landscape', 'glyp-branch_multi_housing', 'glyp-branch_office', 'glyp-branch_orders', 'glyp-branch_residential', 'glyp-branch_sales', 'glyp-branch_termites', 'glyp-branch_weeds', 'glyp-branch_wildlife', 'glyp-build', 'glyp-business', 'glyp-business_cert', 'glyp-business_cert_type', 'glyp-calculate', 'glyp-calendar', 'glyp-calendar_branch', 'glyp-calendar_map', 'glyp-calendar_rolling', 'glyp-calendar_share', 'glyp-calendar_snap', 'glyp-calendar_style', 'glyp-california', 'glyp-call', 'glyp-callback', 'glyp-camera', 'glyp-canada', 'glyp-cancellation', 'glyp-cancelled', 'glyp-card_american_express', 'glyp-card_discover', 'glyp-card_mastercard', 'glyp-card_visa', 'glyp-catalog', 'glyp-category', 'glyp-caught', 'glyp-cellulose_debris', 'glyp-cert', 'glyp-cert_timeline', 'glyp-cert_type', 'glyp-certificate', 'glyp-certified_summary', 'glyp-certs', 'glyp-ceu', 'glyp-check_all', 'glyp-check_in', 'glyp-check_in_service', 'glyp-checked', 'glyp-checked_check_all', 'glyp-checked_empty', 'glyp-checkmark', 'glyp-checkmark_filled', 'glyp-checkout', 'glyp-chemical', 'glyp-chemical_authorization', 'glyp-chemical_backpack_sprayer', 'glyp-chemical_biological_controls', 'glyp-chemical_disinfectant', 'glyp-chemical_fertilizer', 'glyp-chemical_flying_insect_bait', 'glyp-chemical_fumigants', 'glyp-chemical_insect_aerosol', 'glyp-chemical_insect_bait', 'glyp-chemical_insect_dust', 'glyp-chemical_insect_granules', 'glyp-chemical_insect_spray', 'glyp-chemical_label', 'glyp-chemical_mole_bait', 'glyp-chemical_pest_bird_control', 'glyp-chemical_pheromone_products', 'glyp-chemical_power_sprayer', 'glyp-chemical_rodent_attractant', 'glyp-chemical_rodenticide_block', 'glyp-chemical_rodenticide_non_block', 'glyp-chemical_sds', 'glyp-chemical_tree_products', 'glyp-chemical_weed_control', 'glyp-chemical_wildlife_repellents', 'glyp-chemical_wildlife_toxicants', 'glyp-chevron_down', 'glyp-chevron_left', 'glyp-chevron_right', 'glyp-chevron_up', 'glyp-circle', 'glyp-city', 'glyp-click', 'glyp-client_actions', 'glyp-client_pest_sightings', 'glyp-client_required', 'glyp-clipboard', 'glyp-close', 'glyp-close_empty', 'glyp-cloud', 'glyp-clyp_environment', 'glyp-clyp_settings', 'glyp-clypboard', 'glyp-clypedia', 'glyp-clypmart', 'glyp-code', 'glyp-code_details', 'glyp-collections', 'glyp-color', 'glyp-columns', 'glyp-comment', 'glyp-comment_filled', 'glyp-comments', 'glyp-commission_origin', 'glyp-commissions', 'glyp-compact', 'glyp-company_setup', 'glyp-compass', 'glyp-complete', 'glyp-complete_certificate', 'glyp-complete_enrollment', 'glyp-compressed', 'glyp-condition_appliance_machinery', 'glyp-condition_customer', 'glyp-condition_device', 'glyp-condition_door_window', 'glyp-condition_dumpster', 'glyp-condition_entry_point', 'glyp-condition_evidence', 'glyp-condition_exclusion', 'glyp-condition_exterior', 'glyp-condition_interior', 'glyp-condition_plumbing', 'glyp-condition_prep_storage', 'glyp-condition_rodent_evidence', 'glyp-condition_rodent_exclusion', 'glyp-condition_roof_ceiling', 'glyp-condition_structure', 'glyp-condition_supplies', 'glyp-condition_termites', 'glyp-condition_ventilation', 'glyp-condition_wall_floor', 'glyp-condition_wildlife', 'glyp-conditions', 'glyp-consolidate', 'glyp-construction', 'glyp-continuing_ed', 'glyp-contract', 'glyp-contract_cancellation', 'glyp-contract_overview', 'glyp-conversation', 'glyp-copesan', 'glyp-copy', 'glyp-county', 'glyp-credit_memo', 'glyp-credit_non_revenue', 'glyp-credit_production', 'glyp-credit_prospect', 'glyp-credit_sales_bonus', 'glyp-crew', 'glyp-cumulative', 'glyp-curriculum', 'glyp-cursor', 'glyp-custom_form', 'glyp-customer', 'glyp-customer_service', 'glyp-damage', 'glyp-dashboard', 'glyp-data_dive', 'glyp-data_dive_query', 'glyp-data_dives', 'glyp-database', 'glyp-deactivate_user', 'glyp-dead_animal_removal', 'glyp-default', 'glyp-delete', 'glyp-demo_mode', 'glyp-descending', 'glyp-design', 'glyp-desktop', 'glyp-detail_report', 'glyp-developer', 'glyp-device', 'glyp-device_sync', 'glyp-differential', 'glyp-disable', 'glyp-disabled_filled', 'glyp-distribute_horizontal', 'glyp-distribute_vertical', 'glyp-division', 'glyp-document', 'glyp-documentation', 'glyp-documents', 'glyp-download', 'glyp-driving', 'glyp-duplicate', 'glyp-duplicate_location', 'glyp-duration', 'glyp-earth_to_wood', 'glyp-edit', 'glyp-email', 'glyp-employment', 'glyp-entertainment_public_venues', 'glyp-equipment_bear_trap', 'glyp-equipment_flying_insect_bait_station', 'glyp-equipment_flying_insect_light_trap', 'glyp-equipment_insect_monitor', 'glyp-equipment_lethal_animal_trap', 'glyp-equipment_live_animal_trap', 'glyp-equipment_live_rodent_trap', 'glyp-equipment_maintenance', 'glyp-equipment_map_viewer', 'glyp-equipment_maps', 'glyp-equipment_mosquito_trap', 'glyp-equipment_other', 'glyp-equipment_pheromone_trap', 'glyp-equipment_pick_up', 'glyp-equipment_rodent_bait', 'glyp-equipment_rodent_trap', 'glyp-equipment_termite_bait_station', 'glyp-equipment_termite_monitor', 'glyp-escape', 'glyp-exam', 'glyp-exams', 'glyp-exclusion', 'glyp-existing_location', 'glyp-expand', 'glyp-expired', 'glyp-expiring', 'glyp-exterior', 'glyp-extras', 'glyp-facebook', 'glyp-family', 'glyp-farm', 'glyp-farm_grain_seed', 'glyp-fast_and_frequent', 'glyp-favorite', 'glyp-features', 'glyp-feedback', 'glyp-field_guide', 'glyp-field_training', 'glyp-file_blank', 'glyp-file_html', 'glyp-file_image', 'glyp-file_pdf', 'glyp-file_printable', 'glyp-file_spreadsheet', 'glyp-file_text', 'glyp-filter', 'glyp-finance', 'glyp-finding', 'glyp-fogging', 'glyp-folder', 'glyp-followup', 'glyp-food_bev_pharma', 'glyp-formula', 'glyp-fuel', 'glyp-fumigation', 'glyp-function', 'glyp-function_aggregate', 'glyp-function_time', 'glyp-gain_loss', 'glyp-generate_invoices', 'glyp-generate_orders', 'glyp-geo', 'glyp-geo_heat_map', 'glyp-geoboard', 'glyp-google', 'glyp-google_calendar', 'glyp-government', 'glyp-grain_seed', 'glyp-grid', 'glyp-grouped', 'glyp-grouping_combine', 'glyp-grouping_separate', 'glyp-guide', 'glyp-has_many', 'glyp-health_care', 'glyp-heat_map', 'glyp-heat_treatment', 'glyp-help', 'glyp-hidden', 'glyp-hint', 'glyp-home', 'glyp-honeybee_removal', 'glyp-housing', 'glyp-icon', 'glyp-identifier', 'glyp-image', 'glyp-images', 'glyp-import', 'glyp-import_certs', 'glyp-import_data', 'glyp-import_users', 'glyp-in_progress', 'glyp-inbox', 'glyp-incomplete_certificate', 'glyp-industrial', 'glyp-info', 'glyp-information_technology', 'glyp-inspect_map', 'glyp-inspections', 'glyp-insulation', 'glyp-integrations', 'glyp-interior', 'glyp-invoice', 'glyp-invoice_charge', 'glyp-invoice_credit', 'glyp-invoice_paid', 'glyp-invoice_review', 'glyp-ipad', 'glyp-iphone', 'glyp-irrigation_install', 'glyp-irrigation_maintenance', 'glyp-items', 'glyp-job', 'glyp-job_plan', 'glyp-job_plan_history', 'glyp-job_plan_run', 'glyp-job_plan_scheduled', 'glyp-job_plan_single_click', 'glyp-job_plan_step_by_step', 'glyp-join', 'glyp-join_inner', 'glyp-join_left', 'glyp-jump', 'glyp-justice', 'glyp-k9_inspection', 'glyp-key', 'glyp-label_bottom', 'glyp-label_left', 'glyp-label_right', 'glyp-label_top', 'glyp-labor', 'glyp-landscape', 'glyp-landscape_maintenance', 'glyp-laptop', 'glyp-lead', 'glyp-lead_listing', 'glyp-lead_source', 'glyp-leads_report', 'glyp-learning_hub', 'glyp-ledger', 'glyp-legal', 'glyp-license', 'glyp-lifetime', 'glyp-limit', 'glyp-line_cap_arrow', 'glyp-line_cap_bar', 'glyp-line_cap_circle', 'glyp-line_cap_none', 'glyp-line_caps', 'glyp-line_style', 'glyp-link', 'glyp-list', 'glyp-location', 'glyp-location_charge', 'glyp-location_credit', 'glyp-location_import', 'glyp-location_integration', 'glyp-location_kind', 'glyp-location_message', 'glyp-location_origin', 'glyp-location_seed', 'glyp-location_tags', 'glyp-locations', 'glyp-locked', 'glyp-lodging', 'glyp-log_in', 'glyp-log_out', 'glyp-log_report', 'glyp-logbook', 'glyp-logbook_documents', 'glyp-lot_number', 'glyp-lycensed_simulator', 'glyp-manager', 'glyp-manual', 'glyp-map', 'glyp-markdown', 'glyp-market', 'glyp-materials', 'glyp-mattress_encasement', 'glyp-merge', 'glyp-message_billing', 'glyp-message_collections', 'glyp-message_complaint', 'glyp-message_misc', 'glyp-message_technician', 'glyp-messages', 'glyp-minus_outline', 'glyp-misc', 'glyp-miscellaneous', 'glyp-missing', 'glyp-moisture', 'glyp-move_order', 'glyp-mowing', 'glyp-multi_housing', 'glyp-multi_tech_order', 'glyp-mute', 'glyp-navicon', 'glyp-neighborhood', 'glyp-new_location', 'glyp-new_ticket', 'glyp-no_charge', 'glyp-no_service', 'glyp-note', 'glyp-note_access', 'glyp-note_billing', 'glyp-note_collection', 'glyp-note_complaint', 'glyp-note_directions', 'glyp-note_focused', 'glyp-note_office', 'glyp-note_preservice', 'glyp-note_sales', 'glyp-note_service', 'glyp-notification', 'glyp-nuke', 'glyp-number', 'glyp-occupant', 'glyp-office', 'glyp-office_government', 'glyp-office_training', 'glyp-offline_mode', 'glyp-on_demand', 'glyp-on_demand_order', 'glyp-online_mode', 'glyp-open', 'glyp-open_invoice', 'glyp-operations', 'glyp-options', 'glyp-order_actions', 'glyp-order_approved', 'glyp-order_batch', 'glyp-order_editor', 'glyp-order_pending', 'glyp-order_series', 'glyp-order_unapproved', 'glyp-org', 'glyp-org_feature', 'glyp-org_settings', 'glyp-org_structure', 'glyp-org_unit', 'glyp-org_unit_settings', 'glyp-orgs', 'glyp-origin', 'glyp-origin_client', 'glyp-origin_tech', 'glyp-outbox', 'glyp-outlier', 'glyp-outlook', 'glyp-overlap', 'glyp-password', 'glyp-past_due', 'glyp-pause', 'glyp-paused', 'glyp-pay_brackets', 'glyp-payment', 'glyp-payment_ach', 'glyp-payment_application_apply', 'glyp-payment_application_correction', 'glyp-payment_application_initial', 'glyp-payment_application_refund', 'glyp-payment_application_transfer', 'glyp-payment_application_unapply', 'glyp-payment_application_unapply_all', 'glyp-payment_applications', 'glyp-payment_batch', 'glyp-payment_cash', 'glyp-payment_check', 'glyp-payment_coupon', 'glyp-payment_credit', 'glyp-payment_discount', 'glyp-payment_eft', 'glyp-payment_finance_charge', 'glyp-payments', 'glyp-payroll', 'glyp-pdf', 'glyp-pending', 'glyp-periodic', 'glyp-periodic_assessment', 'glyp-permission', 'glyp-pest', 'glyp-pest_ants', 'glyp-pest_bats', 'glyp-pest_bed_bugs', 'glyp-pest_birds', 'glyp-pest_crawling_insects', 'glyp-pest_dermestids', 'glyp-pest_fall_invaders', 'glyp-pest_flying_insects', 'glyp-pest_moles', 'glyp-pest_mosquitoes', 'glyp-pest_nuisance_animals', 'glyp-pest_occasional_invaders', 'glyp-pest_ornamental', 'glyp-pest_ornamental_diseases', 'glyp-pest_roaches', 'glyp-pest_rodents', 'glyp-pest_scorpions', 'glyp-pest_snakes', 'glyp-pest_spiders', 'glyp-pest_stinging_insects', 'glyp-pest_stored_product_pests', 'glyp-pest_ticks_and_fleas', 'glyp-pest_viruses_and_bacteria', 'glyp-pest_weeds', 'glyp-pest_wood_destroyers', 'glyp-phone', 'glyp-pick_date', 'glyp-pick_list', 'glyp-platform_android', 'glyp-platform_ios', 'glyp-platform_macos', 'glyp-platform_windows', 'glyp-play', 'glyp-plus', 'glyp-plus_filled', 'glyp-plus_outline', 'glyp-portal', 'glyp-price_increase', 'glyp-price_increase_alt', 'glyp-pricing', 'glyp-pricing_table', 'glyp-print', 'glyp-privacy', 'glyp-product_sale', 'glyp-production', 'glyp-professional_consultation', 'glyp-profile', 'glyp-program', 'glyp-program_elements', 'glyp-program_initiation', 'glyp-program_order', 'glyp-program_review', 'glyp-promo', 'glyp-proposal', 'glyp-protection', 'glyp-purchase_order', 'glyp-quality', 'glyp-query', 'glyp-radio_checked', 'glyp-radio_empty', 'glyp-reassign', 'glyp-receipt', 'glyp-recent', 'glyp-reciprocity', 'glyp-recommendation', 'glyp-record_details', 'glyp-recurring_revenue', 'glyp-redo', 'glyp-refresh', 'glyp-refund', 'glyp-region', 'glyp-released', 'glyp-remove', 'glyp-renew', 'glyp-renewal', 'glyp-report', 'glyp-required_input', 'glyp-reschedule', 'glyp-restaurant_bar', 'glyp-revenue', 'glyp-review', 'glyp-rfid', 'glyp-ride_along', 'glyp-rodent_exclusion', 'glyp-role_admin', 'glyp-role_customer', 'glyp-role_super', 'glyp-role_tech', 'glyp-roster', 'glyp-route_change', 'glyp-route_optimization', 'glyp-rows', 'glyp-ruby', 'glyp-ruler', 'glyp-sales', 'glyp-sales_contest', 'glyp-sales_pipeline', 'glyp-sales_tax', 'glyp-sales_tax_exemption', 'glyp-schedule_lock', 'glyp-schedule_lock_afternoon', 'glyp-schedule_lock_day', 'glyp-schedule_lock_exact', 'glyp-schedule_lock_four_hour', 'glyp-schedule_lock_morning', 'glyp-schedule_lock_none', 'glyp-schedule_lock_two_day', 'glyp-schedule_lock_two_hour', 'glyp-schedule_lock_week', 'glyp-schedule_tyoe_every', 'glyp-schedule_type_every', 'glyp-schedule_type_none', 'glyp-schedule_type_on_demand', 'glyp-schedule_type_schedule', 'glyp-scheduled', 'glyp-scheduling', 'glyp-scheduling_comment', 'glyp-school_church', 'glyp-scope', 'glyp-scoreboard', 'glyp-scrape', 'glyp-script', 'glyp-search', 'glyp-seeding', 'glyp-segment', 'glyp-send', 'glyp-sent', 'glyp-sentricon', 'glyp-service_agreement', 'glyp-service_digest', 'glyp-service_form', 'glyp-service_form_new', 'glyp-service_form_settings', 'glyp-service_form_template', 'glyp-service_miscellaneous', 'glyp-service_reminder', 'glyp-service_report', 'glyp-service_request', 'glyp-services', 'glyp-settings', 'glyp-setup', 'glyp-signature', 'glyp-simulator', 'glyp-site_map', 'glyp-site_map_annotation', 'glyp-site_map_chemical', 'glyp-site_map_edit_details', 'glyp-site_map_edit_geo', 'glyp-site_map_equipment', 'glyp-site_map_exterior', 'glyp-site_map_foundation', 'glyp-site_map_icon', 'glyp-site_map_interior', 'glyp-site_map_label', 'glyp-site_map_perimeter', 'glyp-site_map_settings_left', 'glyp-site_map_settings_right', 'glyp-site_map_template', 'glyp-skill', 'glyp-skip', 'glyp-slope', 'glyp-smart_traps', 'glyp-sms', 'glyp-snow_removal', 'glyp-sort', 'glyp-special', 'glyp-split', 'glyp-spp_scorecard', 'glyp-square_edge', 'glyp-start_sheet', 'glyp-start_time', 'glyp-state_ak', 'glyp-state_al', 'glyp-state_ar', 'glyp-state_az', 'glyp-state_ca', 'glyp-state_co', 'glyp-state_ct', 'glyp-state_dc', 'glyp-state_de', 'glyp-state_fl', 'glyp-state_ga', 'glyp-state_hi', 'glyp-state_ia', 'glyp-state_id', 'glyp-state_il', 'glyp-state_in', 'glyp-state_ks', 'glyp-state_ky', 'glyp-state_la', 'glyp-state_ma', 'glyp-state_mb', 'glyp-state_md', 'glyp-state_me', 'glyp-state_mi', 'glyp-state_mn', 'glyp-state_mo', 'glyp-state_ms', 'glyp-state_mt', 'glyp-state_nc', 'glyp-state_nd', 'glyp-state_ne', 'glyp-state_nh', 'glyp-state_nj', 'glyp-state_nm', 'glyp-state_nv', 'glyp-state_ny', 'glyp-state_oh', 'glyp-state_ok', 'glyp-state_or', 'glyp-state_pa', 'glyp-state_ri', 'glyp-state_sc', 'glyp-state_sd', 'glyp-state_tn', 'glyp-state_tx', 'glyp-state_ut', 'glyp-state_va', 'glyp-state_vt', 'glyp-state_wa', 'glyp-state_wi', 'glyp-state_wv', 'glyp-state_wy', 'glyp-statement', 'glyp-states', 'glyp-steps', 'glyp-sticky', 'glyp-stop_time', 'glyp-store_material', 'glyp-store_order', 'glyp-store_order_back_order', 'glyp-store_order_cancelled', 'glyp-store_order_complete', 'glyp-store_order_pending', 'glyp-store_order_pending_return', 'glyp-store_order_pre_order', 'glyp-store_order_returned', 'glyp-stores', 'glyp-styling', 'glyp-subscribe', 'glyp-subscription', 'glyp-supplemental', 'glyp-support', 'glyp-sync', 'glyp-sync_down', 'glyp-sync_up', 'glyp-table', 'glyp-tablet', 'glyp-tablets', 'glyp-tactacam', 'glyp-tag', 'glyp-tag_manager', 'glyp-tags', 'glyp-task_runs', 'glyp-taxability', 'glyp-tech_cert', 'glyp-tech_cert_type', 'glyp-tech_pest_sightings', 'glyp-technician', 'glyp-technician_approach', 'glyp-template', 'glyp-termite_fumigation', 'glyp-terrier', 'glyp-terrier_hub', 'glyp-terrier_sync', 'glyp-territory', 'glyp-text', 'glyp-thermometer', 'glyp-third_party', 'glyp-third_party_billing', 'glyp-threshold', 'glyp-ticket', 'glyp-ticket_type', 'glyp-tickets', 'glyp-tidy', 'glyp-time', 'glyp-time_entry', 'glyp-timeline', 'glyp-timer', 'glyp-toolbox', 'glyp-tqi', 'glyp-tracker', 'glyp-tracking', 'glyp-training_course', 'glyp-treatment_split', 'glyp-trends', 'glyp-trial', 'glyp-trip_charge', 'glyp-ui_type', 'glyp-unarchive', 'glyp-unassign', 'glyp-unassign_all', 'glyp-unchecked', 'glyp-undo', 'glyp-unfavorite', 'glyp-unit_sweep', 'glyp-unit_tag', 'glyp-university', 'glyp-unlocked', 'glyp-unmute', 'glyp-unscheduled', 'glyp-update_check_positions', 'glyp-upload', 'glyp-user', 'glyp-user_credit', 'glyp-user_tags', 'glyp-users', 'glyp-utility', 'glyp-vacation', 'glyp-vacuum', 'glyp-variant', 'glyp-vendor', 'glyp-versions', 'glyp-video', 'glyp-visible', 'glyp-warehouse', 'glyp-wdi', 'glyp-wdi_az', 'glyp-wdi_ca', 'glyp-wdi_npma', 'glyp-wdi_nv', 'glyp-wdo', 'glyp-web_dusting', 'glyp-website', 'glyp-wildlife', 'glyp-wildlife_exclusion', 'glyp-winter_check', 'glyp-wizard', 'glyp-work', 'glyp-work_class', 'glyp-work_code', 'glyp-work_order', 'glyp-work_production', 'glyp-work_progress', 'glyp-work_yield', 'glyp-year', 'glyp-yield', 'glyp-zip_code', 'glyp-zone_adjacent', 'glyp-zone_check', 'glyp-zone_production', 'glyp-zone_remote', 'glyp-zoom', 'glyp-zoom_fit'] as const
|
|
6
6
|
|
|
7
7
|
/**
|
|
8
8
|
* Format a glyp name so that it's suitable to show to the user.
|
|
@@ -6,7 +6,12 @@ const log = new Logger('LoadOnScrollPlugin')
|
|
|
6
6
|
|
|
7
7
|
type MarginUnit = '%' | 'px'
|
|
8
8
|
type MarginLength = `${number}${MarginUnit}`
|
|
9
|
-
type MarginString = `${MarginLength} ${MarginLength} ${MarginLength} ${MarginLength}`
|
|
9
|
+
type MarginString = MarginLength | `${MarginLength} ${MarginLength}` | `${MarginLength} ${MarginLength} ${MarginLength} ${MarginLength}`
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* Define the behavior of the load on scroll functionality.
|
|
13
|
+
* For information about the intersect parameters, see https://developer.mozilla.org/en-US/docs/Web/API/Intersection_Observer_API
|
|
14
|
+
*/
|
|
10
15
|
export type LoadOnScrollOptions<TState> = {
|
|
11
16
|
// The name of the collection to load on scroll
|
|
12
17
|
collectionName: string
|
|
@@ -14,15 +19,14 @@ export type LoadOnScrollOptions<TState> = {
|
|
|
14
19
|
collectionPartType: PartConstructor<Part<TState>, TState>
|
|
15
20
|
// Called to load the next state. If undefined is returned, no more states will be loaded
|
|
16
21
|
loadNextStates: (existingStates: TState[]) => Promise<TState[] | undefined>
|
|
22
|
+
// The root element whose viewport is scrolling. If not provided, the document viewport is used.
|
|
23
|
+
// Usually not required, but if using intersectThreshold on a scrollable element, might be necessary.
|
|
24
|
+
intersectRootSelector: string
|
|
17
25
|
// Percentage of the last item in the collection that must be visible before the next state is loaded.
|
|
18
|
-
// If not provided, a default value of 25% is used. Must be between 0 and 1
|
|
19
|
-
// See: https://developer.mozilla.org/en-US/docs/Web/API/Intersection_Observer_API#threshold
|
|
26
|
+
// If not provided, a default value of 25% is used. Must be between 0 and 1.
|
|
20
27
|
intersectThreshold?: number
|
|
21
|
-
//
|
|
22
|
-
// See: https://developer.mozilla.org/en-US/docs/Web/API/Intersection_Observer_API#rootmargin
|
|
28
|
+
// Expands the intersection region by the specified margin.
|
|
23
29
|
intersectRootMargin?: MarginString
|
|
24
|
-
// Configure the intersection observer
|
|
25
|
-
configureIntersect?: (builder: IntersectionObserverBuilder, partElem: HTMLElement) => any
|
|
26
30
|
}
|
|
27
31
|
|
|
28
32
|
/**
|
|
@@ -50,17 +54,20 @@ export default class LoadOnScrollPlugin<TState> extends PartPlugin<LoadOnScrollO
|
|
|
50
54
|
return
|
|
51
55
|
}
|
|
52
56
|
|
|
53
|
-
this.
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
this.state.
|
|
57
|
+
const intersectRoot = (this.state.intersectRootSelector) ? elem.querySelector(this.state.intersectRootSelector) : null
|
|
58
|
+
|
|
59
|
+
// We may have re-rendered since the last update, in which case the intersectionRoot will be a new element.
|
|
60
|
+
// In that case, recreate observer with the new root.
|
|
61
|
+
if (!this.observer || this.observer.root !== intersectRoot) {
|
|
62
|
+
const config: IntersectionObserverInit = {
|
|
63
|
+
root: intersectRoot,
|
|
64
|
+
rootMargin: this.state.intersectRootMargin ?? '0px 0px 0px 0px',
|
|
65
|
+
threshold: this.state.intersectThreshold ?? 0.25,
|
|
62
66
|
}
|
|
63
|
-
this.observer
|
|
67
|
+
this.observer?.disconnect()
|
|
68
|
+
this.observer = new IntersectionObserver(this.onIntersect.bind(this), config)
|
|
69
|
+
} else {
|
|
70
|
+
this.observer.disconnect()
|
|
64
71
|
}
|
|
65
72
|
this.observer.observe(lastElement)
|
|
66
73
|
}
|
|
@@ -88,33 +95,4 @@ export default class LoadOnScrollPlugin<TState> extends PartPlugin<LoadOnScrollO
|
|
|
88
95
|
this.isLoading = false
|
|
89
96
|
this.part.stale()
|
|
90
97
|
}
|
|
91
|
-
}
|
|
92
|
-
|
|
93
|
-
export class IntersectionObserverBuilder {
|
|
94
|
-
private readonly callback: IntersectionObserverCallback
|
|
95
|
-
private readonly config: IntersectionObserverInit
|
|
96
|
-
|
|
97
|
-
constructor(callback: IntersectionObserverCallback) {
|
|
98
|
-
this.callback = callback
|
|
99
|
-
this.config = {}
|
|
100
|
-
}
|
|
101
|
-
|
|
102
|
-
root(root: Element | Document | undefined): IntersectionObserverBuilder {
|
|
103
|
-
this.config.root = root
|
|
104
|
-
return this
|
|
105
|
-
}
|
|
106
|
-
|
|
107
|
-
rootMargin(margin: MarginString): IntersectionObserverBuilder {
|
|
108
|
-
this.config.rootMargin = margin
|
|
109
|
-
return this
|
|
110
|
-
}
|
|
111
|
-
|
|
112
|
-
threshold(threshold: number): IntersectionObserverBuilder {
|
|
113
|
-
this.config.threshold = threshold
|
|
114
|
-
return this
|
|
115
|
-
}
|
|
116
|
-
|
|
117
|
-
build() : IntersectionObserver {
|
|
118
|
-
return new IntersectionObserver(this.callback, this.config)
|
|
119
|
-
}
|
|
120
98
|
}
|
package/terrier/tabs.ts
CHANGED
|
@@ -1,8 +1,9 @@
|
|
|
1
|
-
import {Logger} from "tuff-core/logging"
|
|
1
|
+
import { Logger } from "tuff-core/logging"
|
|
2
2
|
import Messages from "tuff-core/messages"
|
|
3
|
-
import {Part, PartParent, PartTag, StatelessPart} from "tuff-core/parts"
|
|
3
|
+
import { Part, PartParent, PartTag, StatelessPart } from "tuff-core/parts"
|
|
4
4
|
import TerrierPart from "./parts/terrier-part"
|
|
5
|
-
import {Action, IconName, Packet} from "./theme"
|
|
5
|
+
import { Action, IconName, Packet } from "./theme"
|
|
6
|
+
import SortablePlugin from "tuff-sortable/sortable-plugin"
|
|
6
7
|
|
|
7
8
|
const log = new Logger("Tabs")
|
|
8
9
|
|
|
@@ -31,7 +32,8 @@ export type TabSide = typeof Sides[number]
|
|
|
31
32
|
|
|
32
33
|
export type TabContainerState = {
|
|
33
34
|
side: TabSide
|
|
34
|
-
|
|
35
|
+
reorderable?: boolean
|
|
36
|
+
currentTab?: string
|
|
35
37
|
}
|
|
36
38
|
|
|
37
39
|
export class TabContainerPart extends TerrierPart<TabContainerState> {
|
|
@@ -39,8 +41,11 @@ export class TabContainerPart extends TerrierPart<TabContainerState> {
|
|
|
39
41
|
private tabs = {} as Record<string, TabDefinition>
|
|
40
42
|
changeTabKey = Messages.typedKey<{ tabKey: string }>()
|
|
41
43
|
changeSideKey = Messages.typedKey<{ side: TabSide }>()
|
|
44
|
+
tabsModifiedKey = Messages.typedKey<{ newOrder: string[] }>()
|
|
42
45
|
|
|
43
46
|
async init() {
|
|
47
|
+
this.state = Object.assign({ reorderable: false }, this.state)
|
|
48
|
+
|
|
44
49
|
this.onClick(this.changeTabKey, m => {
|
|
45
50
|
log.info(`Clicked on tab ${m.data.tabKey}`)
|
|
46
51
|
this.showTab(m.data.tabKey)
|
|
@@ -51,6 +56,23 @@ export class TabContainerPart extends TerrierPart<TabContainerState> {
|
|
|
51
56
|
this.state.side = m.data.side
|
|
52
57
|
this.dirty()
|
|
53
58
|
})
|
|
59
|
+
|
|
60
|
+
if (this.state.reorderable) {
|
|
61
|
+
this.makePlugin(SortablePlugin, {
|
|
62
|
+
zoneClass: 'tt-tab-list',
|
|
63
|
+
targetClass: 'tab',
|
|
64
|
+
onSorted: (_, evt) => {
|
|
65
|
+
this.onTabsModified(evt.toChildren)
|
|
66
|
+
}
|
|
67
|
+
})
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
onTabsModified(tabElementsMaybe?: HTMLElement[]) {
|
|
72
|
+
const tabElements = tabElementsMaybe ??
|
|
73
|
+
Array.from(this.element?.querySelectorAll('.tt-tab-list') ?? [])
|
|
74
|
+
const newOrder = tabElements.map(tabElement => tabElement.dataset.key)
|
|
75
|
+
this.emitMessage(this.tabsModifiedKey, { newOrder })
|
|
54
76
|
}
|
|
55
77
|
|
|
56
78
|
/**
|
|
@@ -65,7 +87,10 @@ export class TabContainerPart extends TerrierPart<TabContainerState> {
|
|
|
65
87
|
state: InferredPartStateType
|
|
66
88
|
): PartType {
|
|
67
89
|
const existingTab = this.tabs[tab.key] ?? {}
|
|
68
|
-
this.tabs[tab.key] = Object.assign(existingTab, {
|
|
90
|
+
this.tabs[tab.key] = Object.assign(existingTab, {
|
|
91
|
+
state: 'enabled',
|
|
92
|
+
}, tab)
|
|
93
|
+
this.onTabsModified()
|
|
69
94
|
const part = this.makePart(constructor, state)
|
|
70
95
|
existingTab.part = part
|
|
71
96
|
this.dirty()
|
|
@@ -89,16 +114,14 @@ export class TabContainerPart extends TerrierPart<TabContainerState> {
|
|
|
89
114
|
*/
|
|
90
115
|
removeTab(key: string) {
|
|
91
116
|
const tab = this.tabs[key]
|
|
92
|
-
if (tab) {
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
log.warn(`No tab ${key} to remove!`)
|
|
101
|
-
}
|
|
117
|
+
if (!tab) return log.warn(`No tab ${key} to remove!`)
|
|
118
|
+
|
|
119
|
+
log.info(`Removing tab ${key}`, tab)
|
|
120
|
+
delete this.tabs[key]
|
|
121
|
+
this.removeChild(tab.part)
|
|
122
|
+
this.onTabsModified()
|
|
123
|
+
this.state.currentTab = undefined
|
|
124
|
+
this.dirty()
|
|
102
125
|
}
|
|
103
126
|
|
|
104
127
|
/**
|
|
@@ -149,38 +172,32 @@ export class TabContainerPart extends TerrierPart<TabContainerState> {
|
|
|
149
172
|
parent.div('tt-tab-container', this.state.side, container => {
|
|
150
173
|
container.div('.tt-flex.tt-tab-list', tabList => {
|
|
151
174
|
if (this._beforeActions.length) {
|
|
152
|
-
this.theme.renderActions(tabList, this._beforeActions, {defaultClass: 'action'})
|
|
175
|
+
this.theme.renderActions(tabList, this._beforeActions, { defaultClass: 'action' })
|
|
153
176
|
}
|
|
154
177
|
for (const tab of Object.values(this.tabs)) {
|
|
155
178
|
if (tab.state == 'hidden') continue
|
|
156
179
|
|
|
157
180
|
tabList.a('.tab', a => {
|
|
181
|
+
a.attrs({ draggable: this.state.reorderable })
|
|
182
|
+
a.data({ key: tab.key })
|
|
158
183
|
a.class(tab.state || 'enabled')
|
|
159
|
-
if (tab.key === currentTabKey)
|
|
160
|
-
|
|
161
|
-
}
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
}
|
|
165
|
-
a.span({text: tab.title})
|
|
166
|
-
a.emitClick(this.changeTabKey, {tabKey: tab.key})
|
|
167
|
-
if (tab.click) {
|
|
168
|
-
a.emitClick(tab.click.key, tab.click.data || {})
|
|
169
|
-
}
|
|
184
|
+
if (tab.key === currentTabKey) a.class('active')
|
|
185
|
+
if (tab.icon) this.theme.renderIcon(a, tab.icon)
|
|
186
|
+
a.span({ text: tab.title })
|
|
187
|
+
a.emitClick(this.changeTabKey, { tabKey: tab.key })
|
|
188
|
+
if (tab.click) a.emitClick(tab.click.key, tab.click.data || {})
|
|
170
189
|
})
|
|
171
190
|
}
|
|
172
191
|
if (this._afterActions.length) {
|
|
173
192
|
tabList.div('.spacer')
|
|
174
|
-
this.theme.renderActions(tabList, this._afterActions, {defaultClass: 'action'})
|
|
193
|
+
this.theme.renderActions(tabList, this._afterActions, { defaultClass: 'action' })
|
|
175
194
|
}
|
|
176
195
|
})
|
|
177
196
|
|
|
178
197
|
if (currentTabKey) {
|
|
179
198
|
const currentTab = this.tabs[currentTabKey]
|
|
180
199
|
container.div('.tt-tab-content', panel => {
|
|
181
|
-
if (currentTab.classes?.length)
|
|
182
|
-
panel.class(...currentTab.classes)
|
|
183
|
-
}
|
|
200
|
+
if (currentTab.classes?.length) panel.class(...currentTab.classes)
|
|
184
201
|
panel.part(currentTab.part as StatelessPart)
|
|
185
202
|
})
|
|
186
203
|
}
|