terrier-engine 4.6.2 → 4.7.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.
@@ -1,7 +1,7 @@
1
1
  import {DdUser} from "./dd-user"
2
2
  import Api from "../terrier/api"
3
3
  import {DdDiveGroup} from "./gen/models"
4
- import {arrays} from "tuff-core";
4
+ import Arrays from "tuff-core/arrays"
5
5
  import {SelectOptions} from "tuff-core/forms"
6
6
  import {Logger} from "tuff-core/logging"
7
7
 
@@ -76,7 +76,7 @@ export default class DdSession {
76
76
  }
77
77
 
78
78
  groupsInOrder(): DdDiveGroup[] {
79
- return arrays.sortBy(Object.values(this.data.groupMap), 'name')
79
+ return Arrays.sortBy(Object.values(this.data.groupMap), 'name')
80
80
  }
81
81
 
82
82
  groupOptions(): SelectOptions {
@@ -5,7 +5,6 @@ import {Query, QueryModelPicker} from "../queries/queries"
5
5
  import QueryEditor from "../queries/query-editor"
6
6
  import {Logger} from "tuff-core/logging"
7
7
  import QueryForm from "../queries/query-form"
8
- import {arrays, messages} from "tuff-core"
9
8
  import {TabContainerPart} from "../../terrier/tabs"
10
9
  import PagePart from "../../terrier/parts/page-part"
11
10
  import ContentPart from "../../terrier/parts/content-part"
@@ -15,7 +14,9 @@ import Ids from "../../terrier/ids"
15
14
  import Db from "../dd-db"
16
15
  import DdSession from "../dd-session"
17
16
  import {DiveRunModal} from "./dive-runs"
18
- import Nav from "tuff-core/nav";
17
+ import Nav from "tuff-core/nav"
18
+ import Messages from "tuff-core/messages"
19
+ import Arrays from "tuff-core/arrays"
19
20
 
20
21
  const log = new Logger("DiveEditor")
21
22
 
@@ -34,9 +35,9 @@ export default class DiveEditor extends ContentPart<DiveEditorState> {
34
35
 
35
36
  tabs!: TabContainerPart
36
37
 
37
- newQueryKey = messages.untypedKey()
38
+ newQueryKey = Messages.untypedKey()
38
39
 
39
- static readonly diveChangedKey = messages.untypedKey()
40
+ static readonly diveChangedKey = Messages.untypedKey()
40
41
 
41
42
  queries = new Array<Query>()
42
43
 
@@ -88,7 +89,7 @@ export default class DiveEditor extends ContentPart<DiveEditorState> {
88
89
 
89
90
  deleteQuery(id: string) {
90
91
  log.info(`Deleting query ${id}`)
91
- if (arrays.deleteIf(this.queries, q => q.id == id) > 0) {
92
+ if (Arrays.deleteIf(this.queries, q => q.id == id) > 0) {
92
93
  this.tabs.removeTab(id)
93
94
  this.dirty()
94
95
  }
@@ -102,7 +103,7 @@ export default class DiveEditor extends ContentPart<DiveEditorState> {
102
103
  parent.part(this.tabs)
103
104
  }
104
105
 
105
- static readonly deleteQueryKey = messages.typedKey<{ id: string }>()
106
+ static readonly deleteQueryKey = Messages.typedKey<{ id: string }>()
106
107
 
107
108
  async serialize(): Promise<DdDive> {
108
109
  const queries = this.queries
@@ -117,10 +118,10 @@ export class DiveEditorPage extends PagePart<{id: string}> {
117
118
  editor!: DiveEditor
118
119
  session!: DdSession
119
120
 
120
- showHintsKey = messages.untypedKey()
121
- saveKey = messages.untypedKey()
122
- discardKey = messages.untypedKey()
123
- runKey = messages.untypedKey()
121
+ showHintsKey = Messages.untypedKey()
122
+ saveKey = Messages.untypedKey()
123
+ discardKey = Messages.untypedKey()
124
+ runKey = Messages.untypedKey()
124
125
 
125
126
  async init() {
126
127
  log.info(`Loading dive ${this.state.id}`)
@@ -233,7 +234,7 @@ type NewQueryState = {
233
234
 
234
235
  class NewQueryModal extends ModalPart<NewQueryState> {
235
236
 
236
- addKey = messages.untypedKey()
237
+ addKey = Messages.untypedKey()
237
238
  settingsForm!: QueryForm
238
239
  modelPicker!: QueryModelPicker
239
240
 
@@ -2,7 +2,6 @@ import {Logger} from "tuff-core/logging"
2
2
  import PagePart from "../../terrier/parts/page-part"
3
3
  import {PartTag} from "tuff-core/parts"
4
4
  import Schema, {SchemaDef} from "../../terrier/schema"
5
- import {arrays, messages} from "tuff-core"
6
5
  import {DdDive, DdDiveGroup, UnpersistedDdDive, UnpersistedDdDiveGroup} from "../gen/models"
7
6
  import Dives, {DiveListResult} from "./dives"
8
7
  import {GroupEditorModal} from "./group-editor"
@@ -11,6 +10,8 @@ import {IconName} from "../../terrier/theme"
11
10
  import {routes} from "../dd-routes"
12
11
  import {DiveSettingsModal} from "./dive-settings"
13
12
  import DdSession from "../dd-session"
13
+ import Messages from "tuff-core/messages"
14
+ import Arrays from "tuff-core/arrays"
14
15
 
15
16
  const log = new Logger("DiveList")
16
17
 
@@ -21,10 +22,10 @@ const log = new Logger("DiveList")
21
22
 
22
23
  export class DiveListPage extends PagePart<{}> {
23
24
 
24
- newGroupKey = messages.untypedKey()
25
- editGroupKey = messages.typedKey<{id: string}>()
26
- newDiveKey = messages.typedKey<{group_id: string}>()
27
- editDiveKey = messages.typedKey<{id: string}>()
25
+ newGroupKey = Messages.untypedKey()
26
+ editGroupKey = Messages.typedKey<{id: string}>()
27
+ newDiveKey = Messages.typedKey<{group_id: string}>()
28
+ editDiveKey = Messages.typedKey<{id: string}>()
28
29
 
29
30
  session!: DdSession
30
31
  result!: DiveListResult
@@ -104,16 +105,16 @@ export class DiveListPage extends PagePart<{}> {
104
105
  this.result = await Dives.list()
105
106
  log.info("Loading data dive list", this.result)
106
107
  this.groupMap = this.session.data.groupMap
107
- this.diveMap = arrays.indexBy(this.result.dives, 'id')
108
+ this.diveMap = Arrays.indexBy(this.result.dives, 'id')
108
109
  this.dirty()
109
110
  }
110
111
 
111
112
  renderContent(parent: PartTag): void {
112
113
 
113
- const groupedDives = arrays.groupBy(this.result.dives, 'dd_dive_group_id')
114
+ const groupedDives = Arrays.groupBy(this.result.dives, 'dd_dive_group_id')
114
115
 
115
116
  parent.div('.dd-group-grid', grid => {
116
- const groups = arrays.sortBy(Object.values(this.groupMap), 'name')
117
+ const groups = Arrays.sortBy(Object.values(this.groupMap), 'name')
117
118
  for (const group of groups) {
118
119
  this.renderGroupPanel(grid, group, groupedDives[group.id] || [])
119
120
  }
@@ -127,7 +128,7 @@ export class DiveListPage extends PagePart<{}> {
127
128
  .classes('group')
128
129
  .content(content => {
129
130
  content.class('tt-list')
130
- for (const dive of arrays.sortBy(dives, 'name')) {
131
+ for (const dive of Arrays.sortBy(dives, 'name')) {
131
132
  this.renderDiveRow(content, dive)
132
133
  }
133
134
  })
@@ -5,7 +5,6 @@ import Db from "../dd-db"
5
5
  import Api, {ErrorEvent} from "../../terrier/api"
6
6
  import {Query} from "../queries/queries"
7
7
  import {DivTag, HtmlParentTag} from "tuff-core/html"
8
- import {messages} from "tuff-core"
9
8
  import {IconName} from "../../terrier/theme"
10
9
  import Filters, {DateRangeFilter, DirectFilter, FilterInput, InclusionFilter} from "../queries/filters"
11
10
  import Dives from "./dives"
@@ -17,6 +16,7 @@ import Dates, {DateLiteral, DatePeriodPickerPart, DatePeriodPickerState, Literal
17
16
  import dayjs from "dayjs"
18
17
  import {ProgressBarPart} from "../../terrier/progress";
19
18
  import {LogListPart} from "../../terrier/logging";
19
+ import Messages from "tuff-core/messages"
20
20
 
21
21
  const log = new Logger("DiveRuns")
22
22
 
@@ -55,8 +55,8 @@ export class DiveRunModal extends ModalPart<{dive: DdDive }> {
55
55
  progressBar!: ProgressBarPart
56
56
  logList!: LogListPart
57
57
 
58
- startKey = messages.untypedKey()
59
- pickDateKey = messages.typedKey<{ input_key: string }>()
58
+ startKey = Messages.untypedKey()
59
+ pickDateKey = Messages.typedKey<{ input_key: string }>()
60
60
 
61
61
  async init() {
62
62
  this.setTitle("Run Dive")
@@ -1,6 +1,5 @@
1
1
  import TerrierPart from "../../terrier/parts/terrier-part"
2
2
  import {Logger} from "tuff-core/logging"
3
- import {messages} from "tuff-core"
4
3
  import {PartTag} from "tuff-core/parts"
5
4
  import {DdDive, DdDiveEnumFields, UnpersistedDdDive} from "../gen/models"
6
5
  import inflection from "inflection"
@@ -15,6 +14,7 @@ import {DbErrors} from "../../terrier/db-client"
15
14
  import {TerrierFormFields} from "../../terrier/forms"
16
15
  import DdSession from "../dd-session"
17
16
  import Dives from "./dives";
17
+ import Messages from "tuff-core/messages"
18
18
 
19
19
  const log = new Logger("DiveForm")
20
20
 
@@ -39,7 +39,7 @@ class DiveForm extends TerrierPart<{dive: DiveSettings, session: DdSession}> {
39
39
  }, {attach: 'passive'})
40
40
  }
41
41
 
42
- static readonly settingsChangedKey = messages.typedKey<DiveSettings>()
42
+ static readonly settingsChangedKey = Messages.typedKey<DiveSettings>()
43
43
 
44
44
 
45
45
  get parentClasses(): Array<string> {
@@ -109,8 +109,8 @@ export class DiveSettingsModal extends ModalPart<DiveSettingsState> {
109
109
 
110
110
  settingsForm!: DiveForm
111
111
  modelPicker!: QueryModelPicker
112
- saveKey = messages.untypedKey()
113
- deleteKey = messages.untypedKey()
112
+ saveKey = Messages.untypedKey()
113
+ deleteKey = Messages.untypedKey()
114
114
  isNew = true
115
115
 
116
116
  async init() {
@@ -3,12 +3,12 @@ import TerrierPart from "../../terrier/parts/terrier-part"
3
3
  import {DdDiveGroup, UnpersistedDdDiveGroup} from "../gen/models"
4
4
  import Db from "../dd-db"
5
5
  import {PartTag} from "tuff-core/parts"
6
- import {messages} from "tuff-core"
7
6
  import {DbErrors} from "../../terrier/db-client"
8
7
  import DdSession from "../dd-session"
9
8
  import Nav from "tuff-core/nav"
10
9
  import {routes} from "../dd-routes"
11
10
  import {TerrierFormFields} from "../../terrier/forms"
11
+ import Messages from "tuff-core/messages"
12
12
 
13
13
  class GroupForm extends TerrierPart<{ group: UnpersistedDdDiveGroup }> {
14
14
 
@@ -66,8 +66,8 @@ export type GroupModalState = {
66
66
  export class GroupEditorModal extends ModalPart<GroupModalState> {
67
67
 
68
68
  form!: GroupForm
69
- saveKey = messages.untypedKey()
70
- deleteKey = messages.untypedKey()
69
+ saveKey = Messages.untypedKey()
70
+ deleteKey = Messages.untypedKey()
71
71
 
72
72
  async init() {
73
73
  const group = this.state.group
@@ -4,12 +4,13 @@ import {TableRef, TableView} from "./tables"
4
4
  import {Logger} from "tuff-core/logging"
5
5
  import {FormFields, SelectOptions} from "tuff-core/forms"
6
6
  import Forms from "../../terrier/forms"
7
- import {arrays, messages} from "tuff-core"
8
7
  import Objects from "tuff-core/objects"
9
8
  import {ModalPart} from "../../terrier/modals";
10
9
  import TerrierFormPart from "../../terrier/parts/terrier-form-part"
11
10
  import {Dropdown} from "../../terrier/dropdowns"
12
11
  import DiveEditor from "../dives/dive-editor"
12
+ import Messages from "tuff-core/messages"
13
+ import Arrays from "tuff-core/arrays"
13
14
 
14
15
  const log = new Logger("Columns")
15
16
 
@@ -90,10 +91,10 @@ export type ColumnsEditorState = {
90
91
  tableView: TableView<TableRef>
91
92
  }
92
93
 
93
- const saveKey = messages.untypedKey()
94
- const addKey = messages.untypedKey()
95
- const addSingleKey = messages.typedKey<{ name: string }>()
96
- const removeKey = messages.typedKey<{id: string}>()
94
+ const saveKey = Messages.untypedKey()
95
+ const addKey = Messages.untypedKey()
96
+ const addSingleKey = Messages.typedKey<{ name: string }>()
97
+ const removeKey = Messages.typedKey<{id: string}>()
97
98
 
98
99
  /**
99
100
  * A modal that lets the user edit the columns being referenced for a particular table.
@@ -235,9 +236,9 @@ export class ColumnsEditorModal extends ModalPart<ColumnsEditorState> {
235
236
  }
236
237
 
237
238
  removeColumn(id: string) {
238
- const col = arrays.find(this.columnStates, c => c.id == id)
239
+ const col = Arrays.find(this.columnStates, c => c.id == id)
239
240
  if (col) {
240
- this.columnStates = arrays.without(this.columnStates, col)
241
+ this.columnStates = Arrays.without(this.columnStates, col)
241
242
  this.updateColumnEditors()
242
243
  }
243
244
  }
@@ -315,9 +316,9 @@ class ColumnEditor extends TerrierFormPart<ColumnState> {
315
316
  // Add Column Dropdown
316
317
  ////////////////////////////////////////////////////////////////////////////////
317
318
 
318
- const checkAllKey = messages.untypedKey()
319
- const applySelectionKey = messages.untypedKey()
320
- const checkChangedKey = messages.typedKey<{column: string}>()
319
+ const checkAllKey = Messages.untypedKey()
320
+ const applySelectionKey = Messages.untypedKey()
321
+ const checkChangedKey = Messages.typedKey<{column: string}>()
321
322
 
322
323
  type SelectColumnsCallback = (columns: string[]) => any
323
324
 
@@ -2,8 +2,8 @@ import inflection from "inflection"
2
2
  import dayjs from "dayjs"
3
3
  import {Dropdown} from "../../terrier/dropdowns"
4
4
  import {PartTag} from "tuff-core/parts"
5
- import {messages} from "tuff-core"
6
5
  import {Logger} from "tuff-core/logging"
6
+ import Messages from "tuff-core/messages"
7
7
 
8
8
  const log = new Logger("Dates")
9
9
 
@@ -211,7 +211,7 @@ export type DatePeriodPickerState = {
211
211
  */
212
212
  export class DatePeriodPickerPart extends Dropdown<DatePeriodPickerState> {
213
213
 
214
- periodKey = messages.typedKey<{period: string}>()
214
+ periodKey = Messages.typedKey<{period: string}>()
215
215
 
216
216
  async init() {
217
217
  await super.init()
@@ -2,16 +2,17 @@ import {Part, PartTag} from "tuff-core/parts"
2
2
  import Dates, {DateLiteral, VirtualDatePeriod, VirtualDateRange} from "./dates"
3
3
  import {ColumnDef, ModelDef, SchemaDef} from "../../terrier/schema"
4
4
  import {TableRef, TableView} from "./tables"
5
- import {arrays, messages} from "tuff-core"
6
5
  import {Logger} from "tuff-core/logging"
7
6
  import Objects from "tuff-core/objects"
8
7
  import inflection from "inflection"
9
- import {ModalPart} from "../../terrier/modals";
8
+ import {ModalPart} from "../../terrier/modals"
10
9
  import TerrierFormPart from "../../terrier/parts/terrier-form-part"
11
10
  import {Dropdown} from "../../terrier/dropdowns"
12
11
  import dayjs from "dayjs"
13
12
  import Format from "../../terrier/format"
14
13
  import DiveEditor from "../dives/dive-editor"
14
+ import Messages from "tuff-core/messages"
15
+ import Arrays from "tuff-core/arrays"
15
16
 
16
17
  const log = new Logger("Filters")
17
18
 
@@ -125,9 +126,9 @@ export type FiltersEditorState = {
125
126
  tableView: TableView<TableRef>
126
127
  }
127
128
 
128
- const saveKey = messages.untypedKey()
129
- const addKey = messages.untypedKey()
130
- const removeKey = messages.typedKey<{ id: string }>()
129
+ const saveKey = Messages.untypedKey()
130
+ const addKey = Messages.untypedKey()
131
+ const removeKey = Messages.typedKey<{ id: string }>()
131
132
 
132
133
  export class FiltersEditorModal extends ModalPart<FiltersEditorState> {
133
134
 
@@ -202,10 +203,10 @@ export class FiltersEditorModal extends ModalPart<FiltersEditorState> {
202
203
  }
203
204
 
204
205
  removeFilter(id: string) {
205
- const filter = arrays.find(this.filterStates, f => f.id == id)
206
+ const filter = Arrays.find(this.filterStates, f => f.id == id)
206
207
  if (filter) {
207
208
  log.info(`Removing filter ${id}`, filter)
208
- this.filterStates = arrays.without(this.filterStates, filter)
209
+ this.filterStates = Arrays.without(this.filterStates, filter)
209
210
  this.updateFilterEditors()
210
211
  }
211
212
  }
@@ -336,7 +337,7 @@ class FilterEditorContainer extends Part<FilterState> {
336
337
 
337
338
  class DirectFilterEditor extends FilterEditor<DirectFilter> {
338
339
 
339
- numericChangeKey = messages.untypedKey()
340
+ numericChangeKey = Messages.untypedKey()
340
341
 
341
342
  async init() {
342
343
  await super.init()
@@ -399,7 +400,7 @@ class DirectFilterEditor extends FilterEditor<DirectFilter> {
399
400
  // Inclusion Editor
400
401
  ////////////////////////////////////////////////////////////////////////////////
401
402
 
402
- const inclusionChangedKey = messages.typedKey<{value: string}>()
403
+ const inclusionChangedKey = Messages.typedKey<{value: string}>()
403
404
 
404
405
  class InclusionFilterEditor extends FilterEditor<InclusionFilter> {
405
406
 
@@ -456,9 +457,9 @@ class InclusionFilterEditor extends FilterEditor<InclusionFilter> {
456
457
  // Date Range Editor
457
458
  ////////////////////////////////////////////////////////////////////////////////
458
459
 
459
- const dateRangeRelativeChangedKey = messages.untypedKey()
460
- const dateRangePeriodChangedKey = messages.typedKey<{period: string}>()
461
- const dateRangePreselectKey = messages.typedKey<VirtualDateRange>()
460
+ const dateRangeRelativeChangedKey = Messages.untypedKey()
461
+ const dateRangePeriodChangedKey = Messages.typedKey<{period: string}>()
462
+ const dateRangePreselectKey = Messages.typedKey<VirtualDateRange>()
462
463
 
463
464
  class DateRangeFilterEditor extends FilterEditor<DateRangeFilter> {
464
465
 
@@ -550,7 +551,7 @@ class DateRangeFilterEditor extends FilterEditor<DateRangeFilter> {
550
551
 
551
552
  type AddFilterCallback = (filter: Filter) => any
552
553
 
553
- const columnSelectedKey = messages.typedKey<{column: string}>()
554
+ const columnSelectedKey = Messages.typedKey<{column: string}>()
554
555
 
555
556
  class AddFilterDropdown extends Dropdown<{modelDef: ModelDef, callback: AddFilterCallback}> {
556
557
  columns!: ColumnDef[]
@@ -562,7 +563,7 @@ class AddFilterDropdown extends Dropdown<{modelDef: ModelDef, callback: AddFilte
562
563
  async init() {
563
564
  await super.init()
564
565
 
565
- this.columns = arrays.sortByFunction(Object.values(this.state.modelDef.columns), col => {
566
+ this.columns = Arrays.sortByFunction(Object.values(this.state.modelDef.columns), col => {
566
567
  const visibility = col.metadata?.visibility
567
568
  const sort = visibility == 'common' ? '0' : '1'
568
569
  return `${sort}${col.name}`
@@ -6,9 +6,11 @@ import dayjs from "dayjs"
6
6
  import QueryEditor from "./query-editor"
7
7
  import TerrierPart from "../../terrier/parts/terrier-part"
8
8
  import Schema, {ModelDef, SchemaDef} from "../../terrier/schema"
9
- import {arrays, messages, strings} from "tuff-core"
10
9
  import {Logger} from "tuff-core/logging"
11
- import inflection from "inflection";
10
+ import inflection from "inflection"
11
+ import Messages from "tuff-core/messages"
12
+ import Strings from "tuff-core/strings"
13
+ import Arrays from "tuff-core/arrays"
12
14
 
13
15
  const log = new Logger("Queries")
14
16
 
@@ -184,7 +186,7 @@ export type QueryModelPickerState = {
184
186
  */
185
187
  export class QueryModelPicker extends TerrierPart<QueryModelPickerState> {
186
188
 
187
- pickedKey = messages.typedKey<{ model: string }>()
189
+ pickedKey = Messages.typedKey<{ model: string }>()
188
190
  model?: ModelDef
189
191
 
190
192
  async init() {
@@ -205,7 +207,7 @@ export class QueryModelPicker extends TerrierPart<QueryModelPickerState> {
205
207
  label.input({type: 'radio', name: `new-query-model-${this.id}`, value: model.name})
206
208
  .emitChange(this.pickedKey, {model: model.name})
207
209
  label.div(col => {
208
- const name = inflection.pluralize(strings.titleize(model.name))
210
+ const name = inflection.pluralize(Strings.titleize(model.name))
209
211
  col.div('.name').text(name)
210
212
  if (model.metadata?.description) {
211
213
  col.div('.description').text(model.metadata.description)
@@ -228,7 +230,7 @@ export class QueryModelPicker extends TerrierPart<QueryModelPickerState> {
228
230
  h3.i('.glyp-refresh')
229
231
  h3.span().text("Common Tables")
230
232
  })
231
- for (const model of arrays.sortBy(commonModels, 'name')) {
233
+ for (const model of Arrays.sortBy(commonModels, 'name')) {
232
234
  this.renderModelOption(col, model)
233
235
  }
234
236
  }
@@ -241,7 +243,7 @@ export class QueryModelPicker extends TerrierPart<QueryModelPickerState> {
241
243
  h3.i('.glyp-pending')
242
244
  h3.span().text("Other Tables")
243
245
  })
244
- for (const model of arrays.sortBy(uncommonModels, 'name')) {
246
+ for (const model of Arrays.sortBy(uncommonModels, 'name')) {
245
247
  this.renderModelOption(col, model)
246
248
  }
247
249
  }
@@ -5,10 +5,10 @@ import {Logger} from "tuff-core/logging"
5
5
  import QueryForm, {QuerySettings, QuerySettingsColumns} from "./query-form"
6
6
  import DiveEditor, {DiveEditorState} from "../dives/dive-editor"
7
7
  import Objects from "tuff-core/objects"
8
- import {messages} from "tuff-core"
9
8
  import Html from "tuff-core/html"
10
9
  import ContentPart from "../../terrier/parts/content-part"
11
10
  import {TabContainerPart} from "../../terrier/tabs"
11
+ import Messages from "tuff-core/messages"
12
12
 
13
13
  const log = new Logger("QueryEditor")
14
14
 
@@ -17,7 +17,7 @@ const log = new Logger("QueryEditor")
17
17
  // Keys
18
18
  ////////////////////////////////////////////////////////////////////////////////
19
19
 
20
- const validationKey = messages.typedKey<QueryValidation>()
20
+ const validationKey = Messages.typedKey<QueryValidation>()
21
21
 
22
22
 
23
23
  ////////////////////////////////////////////////////////////////////////////////
@@ -157,7 +157,7 @@ export default class QueryEditor extends ContentPart<QueryEditorState> {
157
157
  sqlPart!: SqlPart
158
158
  previewPart!: PreviewPart
159
159
 
160
- updatePreviewKey = messages.untypedKey()
160
+ updatePreviewKey = Messages.untypedKey()
161
161
 
162
162
  async init() {
163
163
  const query = this.state.query
@@ -231,5 +231,5 @@ export default class QueryEditor extends ContentPart<QueryEditorState> {
231
231
  this.tabs.showTab('preview')
232
232
  }
233
233
 
234
- static readonly copyToClipboardKey = messages.typedKey<{ value: string }>()
234
+ static readonly copyToClipboardKey = Messages.typedKey<{ value: string }>()
235
235
  }
@@ -2,8 +2,8 @@ import {Query} from "./queries"
2
2
  import {PartTag} from "tuff-core/parts"
3
3
  import {FormFields} from "tuff-core/forms"
4
4
  import {Logger} from "tuff-core/logging"
5
- import {messages} from "tuff-core"
6
- import ContentPart from "../../terrier/parts/content-part";
5
+ import ContentPart from "../../terrier/parts/content-part"
6
+ import Messages from "tuff-core/messages"
7
7
 
8
8
  const log = new Logger("QueryForm")
9
9
 
@@ -46,6 +46,6 @@ export default class QueryForm extends ContentPart<{ query: QuerySettings }> {
46
46
  })
47
47
  }
48
48
 
49
- static readonly settingsChangedKey = messages.typedKey<QuerySettings>()
49
+ static readonly settingsChangedKey = Messages.typedKey<QuerySettings>()
50
50
 
51
51
  }
@@ -3,13 +3,14 @@ import Schema, {BelongsToDef, ModelDef, SchemaDef} from "../../terrier/schema"
3
3
  import inflection from "inflection"
4
4
  import Filters, {Filter, FilterInput, FiltersEditorModal} from "./filters"
5
5
  import Columns, {ColumnRef, ColumnsEditorModal} from "./columns"
6
- import {arrays, messages} from "tuff-core"
7
6
  import {Logger} from "tuff-core/logging"
8
7
  import ContentPart from "../../terrier/parts/content-part"
9
8
  import {ActionsDropdown} from "../../terrier/dropdowns"
10
9
  import {ModalPart} from "../../terrier/modals"
11
10
  import TerrierFormPart from "../../terrier/parts/terrier-form-part"
12
- import DiveEditor from "../dives/dive-editor";
11
+ import DiveEditor from "../dives/dive-editor"
12
+ import Messages from "tuff-core/messages"
13
+ import Arrays from "tuff-core/arrays"
13
14
 
14
15
  const log = new Logger("Tables")
15
16
 
@@ -35,7 +36,7 @@ export type JoinedTableRef = TableRef & {
35
36
  // Keys
36
37
  ////////////////////////////////////////////////////////////////////////////////
37
38
 
38
- const updatedKey = messages.typedKey<TableRef>()
39
+ const updatedKey = Messages.typedKey<TableRef>()
39
40
 
40
41
 
41
42
  ////////////////////////////////////////////////////////////////////////////////
@@ -75,11 +76,11 @@ export class TableView<T extends TableRef> extends ContentPart<{ schema: SchemaD
75
76
  modelDef!: ModelDef
76
77
  parentView?: TableView<any>
77
78
 
78
- editTableKey = messages.untypedKey()
79
- editColumnsKey = messages.untypedKey()
80
- editFiltersKey = messages.untypedKey()
81
- newJoinedKey = messages.untypedKey()
82
- createJoinedKey = messages.typedKey<{name: string}>()
79
+ editTableKey = Messages.untypedKey()
80
+ editColumnsKey = Messages.untypedKey()
81
+ editFiltersKey = Messages.untypedKey()
82
+ newJoinedKey = Messages.untypedKey()
83
+ createJoinedKey = Messages.typedKey<{name: string}>()
83
84
 
84
85
  async init() {
85
86
  this.schema = this.state.schema
@@ -111,7 +112,7 @@ export class TableView<T extends TableRef> extends ContentPart<{ schema: SchemaD
111
112
 
112
113
  // show the common tables at the top
113
114
  let showingCommon = true
114
- const actions = arrays.sortByFunction(newJoins, bt => {
115
+ const actions = Arrays.sortByFunction(newJoins, bt => {
115
116
  const model = this.schema.models[bt.model]
116
117
  const common = model.metadata?.visibility == 'common' ? '0' : '1'
117
118
  return `${common}${bt.name}`
@@ -394,7 +395,7 @@ class JoinedTableEditorForm extends TerrierFormPart<JoinedTableRef> {
394
395
  class JoinedTableEditorModal extends ModalPart<JoinedTableEditorState> {
395
396
 
396
397
  form!: JoinedTableEditorForm
397
- applyKey = messages.untypedKey()
398
+ applyKey = Messages.untypedKey()
398
399
 
399
400
  async init() {
400
401
  this.form = this.makePart(JoinedTableEditorForm, this.state.table)
package/package.json CHANGED
@@ -4,7 +4,7 @@
4
4
  "files": [
5
5
  "*"
6
6
  ],
7
- "version": "4.6.2",
7
+ "version": "4.7.3",
8
8
  "repository": {
9
9
  "type": "git",
10
10
  "url": "https://github.com/Terrier-Tech/terrier-engine"
package/terrier/app.ts CHANGED
@@ -1,4 +1,4 @@
1
- import { Logger } from "tuff-core/logging"
1
+ import {Logger} from "tuff-core/logging"
2
2
  import {Part, PartConstructor, PartParent} from "tuff-core/parts"
3
3
  import TerrierPart from "./parts/terrier-part"
4
4
  import Tooltips from "./tooltips"
@@ -6,11 +6,12 @@ import Lightbox from "./lightbox"
6
6
  import Theme from "./theme"
7
7
  import {ModalPart, ModalStackPart} from "./modals"
8
8
  import {OverlayLayerType, OverlayPart} from "./overlays"
9
+ import Messages from "tuff-core/messages"
9
10
 
10
11
  // @ts-ignore
11
12
  import logoUrl from './images/optimized/terrier-hub-logo-light.svg'
12
- import Sheets, {AlertSheetState, ConfirmSheetState, Sheet, SheetState} from "./sheets";
13
- import {messages} from "tuff-core";
13
+ import Sheets, {AlertSheetState, ConfirmSheetState, Sheet, SheetState} from "./sheets"
14
+
14
15
 
15
16
  const log = new Logger('App')
16
17
  Logger.level = 'info'
@@ -103,7 +104,7 @@ export abstract class TerrierApp<TState> extends TerrierPart<TState> {
103
104
  * @param callback gets called if the user hits "Confirm"
104
105
  */
105
106
  confirm(options: ConfirmSheetState, callback: () => any) {
106
- const key = messages.untypedKey()
107
+ const key = Messages.untypedKey()
107
108
  const state = {...options,
108
109
  primaryActions: [
109
110
  {
@@ -1,15 +1,15 @@
1
1
  import {Logger} from "tuff-core/logging"
2
- import {untypedKey} from "tuff-core/messages"
3
- import {unique} from "tuff-core/arrays"
2
+ import Messages from "tuff-core/messages"
4
3
  import {PartTag, StatelessPart} from "tuff-core/parts"
5
4
  import Overlays from "./overlays"
6
5
  import TerrierPart from "./parts/terrier-part"
7
6
  import Objects from "tuff-core/objects"
8
7
  import {Action} from "./theme"
8
+ import Arrays from "tuff-core/arrays"
9
9
 
10
10
  const log = new Logger('Dropdowns')
11
11
 
12
- const clearDropdownKey = untypedKey()
12
+ const clearDropdownKey = Messages.untypedKey()
13
13
 
14
14
  /**
15
15
  * Abstract base class for dropdown parts.
@@ -109,7 +109,7 @@ export class ActionsDropdown extends Dropdown<Array<Action>> {
109
109
  renderContent(parent: PartTag) {
110
110
  // handle each key declared on the actions directly,
111
111
  // then clear the dropdown and re-emit them on the parent part
112
- const keys = unique(this.state.map(action => action.click?.key).filter(Objects.notNull))
112
+ const keys = Arrays.unique(this.state.map(action => action.click?.key).filter(Objects.notNull))
113
113
  for (const key of keys) {
114
114
  this.onClick(key, m => {
115
115
  this.clear()
package/terrier/forms.ts CHANGED
@@ -1,13 +1,15 @@
1
1
  import {Field, FormFields, FormPartData, InputType, KeyOfType, SelectOptions} from "tuff-core/forms"
2
- import {logging, messages, strings} from "tuff-core"
3
2
  import {DbErrors} from "./db-client"
4
3
  import {PartTag} from "tuff-core/parts"
5
4
  import {InputTag, InputTagAttrs} from "tuff-core/html"
6
5
  import TerrierPart from "./parts/terrier-part"
7
6
  import GlypPicker from "./parts/glyp-picker"
8
7
  import Glyps from "./glyps"
8
+ import Messages from "tuff-core/messages"
9
+ import {Logger} from "tuff-core/logging"
10
+ import Strings from "tuff-core/strings"
9
11
 
10
- const log = new logging.Logger("TerrierForms")
12
+ const log = new Logger("TerrierForms")
11
13
 
12
14
  ////////////////////////////////////////////////////////////////////////////////
13
15
  // Options
@@ -19,7 +21,7 @@ const log = new logging.Logger("TerrierForms")
19
21
  */
20
22
  function titleizeOptions(opts: string[], blank?: string): SelectOptions {
21
23
  const out = opts.map(c => {
22
- return {value: c, title: strings.titleize(c)}
24
+ return {value: c, title: Strings.titleize(c)}
23
25
  })
24
26
  if (blank != undefined) { // don't test length, allow it to be a blank string
25
27
  out.unshift({title: blank, value: ''})
@@ -39,7 +41,7 @@ export class TerrierFormFields<T extends FormPartData> extends FormFields<T> {
39
41
 
40
42
  errors?: DbErrors<T>
41
43
 
42
- pickGlypKey = messages.typedKey<{ key: KeyOfType<T, string | undefined> & string }>()
44
+ pickGlypKey = Messages.typedKey<{ key: KeyOfType<T, string | undefined> & string }>()
43
45
 
44
46
  /**
45
47
  * You must pass a `TerrierPart` so that we can render the error bubble with it.
package/terrier/glyps.ts CHANGED
@@ -1,6 +1,7 @@
1
1
  // This file was automatically generated by glyps:compile on 08/19/23 9:07 AM, DO NOT MANUALLY EDIT!
2
2
 
3
- import {strings} from "tuff-core"
3
+
4
+ import Strings from "tuff-core/strings"
4
5
 
5
6
  const names = ['glyp-abacus', 'glyp-account', 'glyp-accounts_payable', 'glyp-accounts_receivable', 'glyp-action_log', 'glyp-activate', 'glyp-active', 'glyp-activity_high', 'glyp-activity_low', 'glyp-activity_medium', 'glyp-activity_none', 'glyp-address1', 'glyp-adjustment', 'glyp-admin', 'glyp-administration', 'glyp-air_freshener', 'glyp-alert', 'glyp-align_horizontal', 'glyp-align_vertical', 'glyp-anchor', '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-attachment', 'glyp-audit_analyzer', 'glyp-autopay', 'glyp-availability', 'glyp-background_batch', 'glyp-background_job', '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-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-calculate', 'glyp-calendar', 'glyp-calendar_branch', 'glyp-calendar_map', 'glyp-calendar_rolling', 'glyp-calendar_share', 'glyp-calendar_snap', 'glyp-california', 'glyp-call', 'glyp-callback', 'glyp-camera', 'glyp-cancellation', 'glyp-cancelled', 'glyp-card_american_express', 'glyp-card_discover', 'glyp-card_mastercard', 'glyp-card_visa', 'glyp-catalog', 'glyp-caught', 'glyp-cert', 'glyp-check_all', 'glyp-check_in', 'glyp-check_in_service', 'glyp-checked', '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_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-city', 'glyp-click', 'glyp-client_actions', 'glyp-client_pest_sightings', 'glyp-client_required', 'glyp-close', 'glyp-cloud', 'glyp-clypboard', 'glyp-clypedia', 'glyp-clypmart', 'glyp-code', 'glyp-code_details', 'glyp-collections', 'glyp-columns', 'glyp-comment', 'glyp-comment_filled', 'glyp-commission_origin', 'glyp-commissions', 'glyp-company_setup', 'glyp-compass', 'glyp-complete', 'glyp-complete_certificate', 'glyp-complete_enrollment', '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-contract', 'glyp-contract_cancellation', 'glyp-contract_overview', 'glyp-conversation', 'glyp-copesan', 'glyp-copy', 'glyp-credit_memo', 'glyp-credit_non_revenue', 'glyp-credit_production', 'glyp-credit_prospect', 'glyp-credit_sales_bonus', 'glyp-crew', 'glyp-cumulative', 'glyp-cursor', 'glyp-custom_form', 'glyp-customer', 'glyp-customer_service', 'glyp-dashboard', 'glyp-data_dive', 'glyp-data_dive_query', 'glyp-data_dives', 'glyp-database', '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-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-exclusion', 'glyp-expand', 'glyp-expired', 'glyp-expiring', 'glyp-exterior', 'glyp-extras', 'glyp-facebook', 'glyp-farm', 'glyp-farm_grain_seed', 'glyp-fast_and_frequent', 'glyp-favorite', '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-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-google', 'glyp-google_calendar', 'glyp-government', 'glyp-grain_seed', 'glyp-grid', 'glyp-grouped', 'glyp-grouping_combine', 'glyp-grouping_separate', 'glyp-has_many', 'glyp-health_care', 'glyp-heat_map', 'glyp-heat_treatment', 'glyp-help', 'glyp-hidden', 'glyp-hint', 'glyp-honeybee_removal', 'glyp-housing', '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_review', 'glyp-irrigation_install', 'glyp-irrigation_maintenance', 'glyp-items', 'glyp-job', 'glyp-join', 'glyp-join_inner', 'glyp-join_left', '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-line_cap_arrow', 'glyp-line_cap_bar', 'glyp-line_cap_circle', 'glyp-line_cap_none', 'glyp-line_caps', 'glyp-line_style', 'glyp-link', 'glyp-location', 'glyp-location_charge', 'glyp-location_credit', 'glyp-location_kind', 'glyp-location_message', 'glyp-location_origin', '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-manager', '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-misc', 'glyp-miscellaneous', 'glyp-move_order', 'glyp-mowing', 'glyp-multi_housing', 'glyp-mute', 'glyp-navicon', '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-number', 'glyp-office', 'glyp-office_government', 'glyp-office_training', 'glyp-on_demand', 'glyp-on_demand_order', '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_structure', 'glyp-org_unit', 'glyp-org_unit_settings', 'glyp-origin', 'glyp-origin_client', 'glyp-origin_tech', 'glyp-outbox', 'glyp-outlook', 'glyp-overlap', 'glyp-password', 'glyp-past_due', '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_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_table', 'glyp-print', 'glyp-privacy', 'glyp-product_sale', 'glyp-production', 'glyp-professional_consultation', '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-recommendation', 'glyp-record_details', 'glyp-recurring_revenue', 'glyp-redo', 'glyp-refresh', 'glyp-refund', 'glyp-region', 'glyp-released', 'glyp-remove', '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-route_change', 'glyp-route_optimization', 'glyp-rows', '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-script', 'glyp-search', 'glyp-seeding', 'glyp-segment', 'glyp-sent', 'glyp-sentricon', 'glyp-service_agreement', 'glyp-service_form', '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-skip', '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-statement', 'glyp-states', '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-supplemental', 'glyp-support', 'glyp-sync', 'glyp-table', 'glyp-tablet', 'glyp-tablets', 'glyp-tag_manager', 'glyp-tags', 'glyp-task_runs', 'glyp-tech_pest_sightings', 'glyp-technician', 'glyp-technician_approach', 'glyp-template', 'glyp-termite_fumigation', 'glyp-terrier', 'glyp-territory', 'glyp-text', 'glyp-thermometer', 'glyp-third_party_billing', 'glyp-ticket', 'glyp-ticket_type', 'glyp-tickets', 'glyp-tidy', 'glyp-time', 'glyp-time_entry', 'glyp-timeline', 'glyp-toolbox', 'glyp-tqi', 'glyp-tracker', 'glyp-tracking', 'glyp-training_course', 'glyp-treatment_split', 'glyp-trends', 'glyp-trip_charge', 'glyp-ui_type', 'glyp-unarchive', '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-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_fit'] as const
6
7
 
@@ -9,7 +10,7 @@ const names = ['glyp-abacus', 'glyp-account', 'glyp-accounts_payable', 'glyp-acc
9
10
  * @param glyp
10
11
  */
11
12
  const displayName = (glyp: string): string => {
12
- return strings.titleize(glyp.replace('glyp-', ''))
13
+ return Strings.titleize(glyp.replace('glyp-', ''))
13
14
  }
14
15
 
15
16
  const Glyps = {
@@ -1,5 +1,5 @@
1
1
  import {Logger} from "tuff-core/logging"
2
- import {untypedKey} from "tuff-core/messages"
2
+ import Messages from "tuff-core/messages"
3
3
  import {Part, PartTag} from "tuff-core/parts"
4
4
  import {TerrierApp} from "./app"
5
5
 
@@ -52,7 +52,7 @@ function showPart(app: TerrierApp<any>, state: LightboxState) {
52
52
  app.addOverlay(LightboxPart, state, 'lightbox')
53
53
  }
54
54
 
55
- const closeKey = untypedKey()
55
+ const closeKey = Messages.untypedKey()
56
56
 
57
57
  class LightboxPart extends Part<LightboxState> {
58
58
 
package/terrier/modals.ts CHANGED
@@ -1,8 +1,8 @@
1
1
  import {Logger} from "tuff-core/logging"
2
- import {untypedKey} from "tuff-core/messages"
3
2
  import TerrierPart from "./parts/terrier-part"
4
3
  import {PartConstructor, PartTag} from "tuff-core/parts"
5
4
  import ContentPart from "./parts/content-part"
5
+ import Messages from "tuff-core/messages"
6
6
 
7
7
  const log = new Logger('Modals')
8
8
 
@@ -99,7 +99,7 @@ export abstract class ModalPart<TState> extends ContentPart<TState> {
99
99
  /**
100
100
  * Emit this key from anywhere inside a modal to pop it off the stack.
101
101
  */
102
- export const modalPopKey = untypedKey()
102
+ export const modalPopKey = Messages.untypedKey()
103
103
 
104
104
  export class ModalStackPart extends TerrierPart<{}> {
105
105
 
@@ -1,7 +1,7 @@
1
1
  import {Part, PartTag, StatelessPart, NoState, PartConstructor} from "tuff-core/parts"
2
- import { Size, Box, Side } from "tuff-core/box"
2
+ import { Size, Box, Side } from "tuff-core/boxes"
3
3
  import { Logger } from "tuff-core/logging"
4
- import {arrays} from "tuff-core";
4
+ import Arrays from "tuff-core/arrays"
5
5
 
6
6
  const log = new Logger('Overlays')
7
7
 
@@ -73,7 +73,7 @@ export class OverlayPart extends Part<NoState> {
73
73
  for (let i = this.layerStates.length-1; i>=0; i--) {
74
74
  if (this.layerStates[i].type == type) {
75
75
  const part = oldParts[i]
76
- this.layerStates = arrays.without(this.layerStates, this.layerStates[i])
76
+ this.layerStates = Arrays.without(this.layerStates, this.layerStates[i])
77
77
  this.updateLayers()
78
78
  return part
79
79
  }
@@ -96,7 +96,7 @@ export class OverlayPart extends Part<NoState> {
96
96
  removeLayer<StateType>(state: StateType): boolean {
97
97
  for (const layerState of this.layerStates) {
98
98
  if (layerState.partState == state) {
99
- this.layerStates = arrays.without(this.layerStates, layerState)
99
+ this.layerStates = Arrays.without(this.layerStates, layerState)
100
100
  this.updateLayers()
101
101
  return true
102
102
  }
@@ -1,12 +1,13 @@
1
1
  import {ModalPart} from "../modals"
2
2
  import {Part, PartTag} from "tuff-core/parts"
3
- import {messages, logging} from "tuff-core"
4
3
  import Glyps from "../glyps"
4
+ import {Logger} from "tuff-core/logging"
5
+ import Messages from "tuff-core/messages"
5
6
 
6
- const log = new logging.Logger("GlypPicker")
7
+ const log = new Logger("GlypPicker")
7
8
 
8
9
 
9
- const pickKey = messages.typedKey<{ icon: string }>()
10
+ const pickKey = Messages.typedKey<{ icon: string }>()
10
11
 
11
12
  export type GlypPickerState = {
12
13
  icon?: string
@@ -20,7 +21,7 @@ class GlypPickerModal extends ModalPart<GlypPickerState> {
20
21
 
21
22
  grid!: GlypGrid
22
23
 
23
- filterKey = messages.untypedKey()
24
+ filterKey = Messages.untypedKey()
24
25
 
25
26
  async init() {
26
27
  await super.init()
@@ -1,7 +1,7 @@
1
1
  import ContentPart from "./content-part"
2
2
  import {PartTag} from "tuff-core/parts"
3
3
  import Fragments from "../fragments"
4
- import {untypedKey} from "tuff-core/messages";
4
+ import Messages from "tuff-core/messages"
5
5
 
6
6
  export type CollapsibleConfig = {
7
7
  collapsed?: boolean
@@ -13,8 +13,8 @@ export type CollapsibleConfig = {
13
13
  export default abstract class PanelPart<TState> extends ContentPart<TState & { collapsible?: CollapsibleConfig}> {
14
14
  protected static readonly DEFAULT_CHEVRON_SIDE: 'left' | 'right' = 'left'
15
15
 
16
- private _toggleCollapseKey = untypedKey()
17
- private _transitionEndKey = untypedKey()
16
+ private _toggleCollapseKey = Messages.untypedKey()
17
+ private _transitionEndKey = Messages.untypedKey()
18
18
 
19
19
  private _prevCollapsedState?: boolean
20
20
 
package/terrier/sheets.ts CHANGED
@@ -2,8 +2,8 @@ import {Action, IconName} from "./theme"
2
2
  import TerrierPart from "./parts/terrier-part"
3
3
  import {PartTag} from "tuff-core/parts"
4
4
  import Fragments from "./fragments"
5
- import {messages} from "tuff-core"
6
5
  import {Logger} from "tuff-core/logging"
6
+ import Messages from "tuff-core/messages"
7
7
 
8
8
  const log = new Logger('Sheets')
9
9
 
@@ -20,7 +20,7 @@ export type SheetState = {
20
20
  secondaryActions?: Action[]
21
21
  }
22
22
 
23
- const clearKey = messages.untypedKey()
23
+ const clearKey = Messages.untypedKey()
24
24
 
25
25
  export class Sheet<TState extends SheetState> extends TerrierPart<TState> {
26
26
 
package/terrier/tabs.ts CHANGED
@@ -1,5 +1,5 @@
1
1
  import {Logger} from "tuff-core/logging"
2
- import {typedKey} from "tuff-core/messages"
2
+ import Messages from "tuff-core/messages"
3
3
  import {Part, PartParent, PartTag, StatelessPart} from "tuff-core/parts"
4
4
  import TerrierPart from "./parts/terrier-part"
5
5
  import {Action, IconName, Packet} from "./theme"
@@ -37,8 +37,8 @@ export type TabContainerState = {
37
37
  export class TabContainerPart extends TerrierPart<TabContainerState> {
38
38
 
39
39
  private tabs = {} as Record<string, TabDefinition>
40
- changeTabKey = typedKey<{ tabKey: string }>()
41
- changeSideKey = typedKey<{ side: TabSide }>()
40
+ changeTabKey = Messages.typedKey<{ tabKey: string }>()
41
+ changeSideKey = Messages.typedKey<{ side: TabSide }>()
42
42
 
43
43
  async init() {
44
44
  this.onClick(this.changeTabKey, m => {
package/terrier/theme.ts CHANGED
@@ -1,7 +1,7 @@
1
1
  import {PartTag} from "tuff-core/parts"
2
- import {messages} from "tuff-core"
3
2
  import {GlypName} from "./glyps"
4
3
  import HubIcons, {HubIconName} from "./gen/hub-icons"
4
+ import {Key} from "tuff-core/messages"
5
5
 
6
6
  export interface ThemeType {
7
7
  readonly icons: string
@@ -22,7 +22,7 @@ export type ColorName = typeof ColorNames[number]
22
22
  * A combination of a message key and its associated data.
23
23
  */
24
24
  export type Packet = {
25
- key: messages.Key
25
+ key: Key
26
26
  data?: Record<string, unknown>
27
27
  }
28
28
 
@@ -102,7 +102,7 @@ export default class Theme {
102
102
  if (action.subtitle?.length) {
103
103
  a.div('.subtitle', {text: action.subtitle})
104
104
  }
105
- else {
105
+ if (!(action.title?.length || action.subtitle?.length)) {
106
106
  a.class('icon-only')
107
107
  }
108
108
  if (action.href?.length) {