dazscript-framework 0.1.14 → 0.1.16

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (82) hide show
  1. package/README.md +365 -93
  2. package/babel.config.js +33 -33
  3. package/dist/babel/trace-babel-plugin.js +243 -243
  4. package/dist/babel/trace-log-babel-plugin.js +164 -164
  5. package/dist/scripts/install-generator.js +185 -185
  6. package/package.json +72 -70
  7. package/src/common/dz-dump.ts +120 -120
  8. package/src/common/log.ts +56 -57
  9. package/src/common/trace.ts +26 -26
  10. package/src/core/action-decorator.ts +15 -15
  11. package/src/core/base-script.ts +30 -30
  12. package/src/core/custom-action.ts +11 -11
  13. package/src/core/global.ts +4 -4
  14. package/src/dialog/basic-dialog.ts +40 -32
  15. package/src/dialog/builders/button-builder.ts +52 -52
  16. package/src/dialog/builders/checkbox-builder.ts +29 -29
  17. package/src/dialog/builders/color-picker-builder.ts +36 -0
  18. package/src/dialog/builders/combo-box-builder.ts +38 -35
  19. package/src/dialog/builders/combo-edit-builder.ts +35 -35
  20. package/src/dialog/builders/dialog-builder.ts +49 -49
  21. package/src/dialog/builders/groupbox-builder.ts +121 -73
  22. package/src/dialog/builders/label-builder.ts +33 -29
  23. package/src/dialog/builders/layout-builder.ts +59 -59
  24. package/src/dialog/builders/line-edit-builder.ts +124 -119
  25. package/src/dialog/builders/list-box-builder.ts +103 -0
  26. package/src/dialog/builders/list-view-builder.ts +396 -328
  27. package/src/dialog/builders/node-selection-builder.ts +55 -55
  28. package/src/dialog/builders/path-combo-box-builder.ts +24 -24
  29. package/src/dialog/builders/popup-menu-builder.ts +46 -46
  30. package/src/dialog/builders/radio-builder.ts +42 -42
  31. package/src/dialog/builders/slider-builder.ts +40 -0
  32. package/src/dialog/builders/splitter-builder.ts +88 -88
  33. package/src/dialog/builders/tab-builder.ts +120 -106
  34. package/src/dialog/builders/widget-builder.ts +136 -124
  35. package/src/dialog/builders/widgets-builder.ts +140 -125
  36. package/src/dialog/input-dialog.ts +30 -27
  37. package/src/dialog/input-validator.ts +8 -8
  38. package/src/dialog/selection-dialog.ts +47 -0
  39. package/src/dialog/shared.ts +8 -8
  40. package/src/helpers/action-helper.ts +214 -81
  41. package/src/helpers/array-helper.ts +170 -145
  42. package/src/helpers/camera-helper.ts +12 -12
  43. package/src/helpers/custom-action-helper.ts +176 -176
  44. package/src/helpers/directory-helper.ts +14 -0
  45. package/src/helpers/file-helper.ts +90 -90
  46. package/src/helpers/http-helper.ts +186 -0
  47. package/src/helpers/input-helper.ts +18 -18
  48. package/src/helpers/list-view-helper.ts +105 -89
  49. package/src/helpers/menu-helper.ts +28 -28
  50. package/src/helpers/message-box-helper.ts +25 -15
  51. package/src/helpers/node-helper.ts +461 -236
  52. package/src/helpers/number-helper.ts +10 -10
  53. package/src/helpers/numeric-property-helper.ts +91 -91
  54. package/src/helpers/object-helper.ts +2 -2
  55. package/src/helpers/pane-helper.ts +28 -20
  56. package/src/helpers/progress-helper.ts +51 -33
  57. package/src/helpers/property-helper.ts +61 -52
  58. package/src/helpers/record-helper.ts +16 -16
  59. package/src/helpers/scene-helper.ts +144 -95
  60. package/src/helpers/script-helper.ts +15 -15
  61. package/src/helpers/skeleton-helper.ts +26 -26
  62. package/src/helpers/splitter-helper.ts +8 -8
  63. package/src/helpers/string-helper.ts +39 -31
  64. package/src/helpers/surface-helper.ts +5 -5
  65. package/src/helpers/undo-helper.ts +8 -7
  66. package/src/helpers/viewport-helper.ts +21 -8
  67. package/src/lib/delayed.ts +38 -38
  68. package/src/lib/dictionary.ts +3 -0
  69. package/src/lib/frame-keys.ts +67 -67
  70. package/src/lib/guid.ts +2 -2
  71. package/src/lib/menu-item.ts +10 -9
  72. package/src/lib/observable.ts +147 -94
  73. package/src/lib/set.ts +50 -25
  74. package/src/lib/settings.ts +112 -104
  75. package/src/lib/tree-node.ts +149 -145
  76. package/src/samples/config.ts +2 -2
  77. package/src/samples/hello-world.dsa.ts +12 -12
  78. package/src/samples/sample-dialog.dsa.ts +51 -51
  79. package/src/samples/sample-dialog.ts +48 -48
  80. package/src/shared/set-keyboard-shortcut.ts +146 -102
  81. package/tsconfig.json +116 -116
  82. package/webpack.config.js +70 -70
@@ -0,0 +1,186 @@
1
+ import * as log from '@dsf/common/log'
2
+
3
+ export type HttpMethod = 'GET' | 'POST' | 'PUT' | 'PATCH' | 'DELETE' | 'HEAD'
4
+ export type HttpConnectionMode = 'http' | 'https'
5
+ export type HttpResponseType = 'json' | 'text' | 'bytes'
6
+
7
+ export interface HttpAuthOptions {
8
+ basic?: {
9
+ username: string
10
+ password: string
11
+ }
12
+ bearerToken?: string
13
+ }
14
+
15
+ export interface HttpRequestOptions {
16
+ host: string
17
+ path: string
18
+ method?: HttpMethod
19
+ connectionMode?: HttpConnectionMode
20
+ responseType?: HttpResponseType
21
+ queryString?: string
22
+ headers?: Record<string, string>
23
+ contentType?: string
24
+ body?: string | ByteArray | object
25
+ auth?: HttpAuthOptions
26
+ transport?: any
27
+ }
28
+
29
+ export interface HttpResponse<T = any> {
30
+ ok: boolean
31
+ bytes: ByteArray
32
+ text: string
33
+ data: T | null
34
+ error: string
35
+ parseError: string
36
+ }
37
+
38
+ export const basicAuth = (username: string, password: string): string => {
39
+ const credentials = new ByteArray(username + ':' + password)
40
+ const encoded = credentials.toBase64().convertToString()
41
+ return 'Basic ' + encoded.replace(/\r|\n/g, '')
42
+ }
43
+
44
+ export const bearerAuth = (token: string): string => {
45
+ return 'Bearer ' + token
46
+ }
47
+
48
+ export const request = <T = any>(options: HttpRequestOptions): HttpResponse<T> => {
49
+ const emptyBytes = new ByteArray()
50
+ const emptyResponse: HttpResponse<T> = {
51
+ ok: false,
52
+ bytes: emptyBytes,
53
+ text: '',
54
+ data: null,
55
+ error: '',
56
+ parseError: ''
57
+ }
58
+
59
+ if (!options || !options.host || !options.path) {
60
+ return {
61
+ ...emptyResponse,
62
+ error: 'Http request requires host and path.'
63
+ }
64
+ }
65
+
66
+ // Parse host:port format
67
+ let hostOnly = options.host
68
+ let port = 0
69
+ const colonIdx = options.host.indexOf(':')
70
+ if (colonIdx > 0) {
71
+ hostOnly = options.host.substring(0, colonIdx)
72
+ const portStr = options.host.substring(colonIdx + 1)
73
+ port = parseInt(portStr)
74
+ }
75
+
76
+ const http = options.transport ?? new DzHttpHelper()
77
+ http.setConnectionMode(options.connectionMode ?? 'https')
78
+ http.setHost(hostOnly)
79
+ if (port > 0) {
80
+ http.setPort(port)
81
+ }
82
+ http.setPath(options.path)
83
+ http.setRequestMethod(options.method ?? 'GET')
84
+
85
+ if (options.queryString) {
86
+ http.setQueryString(options.queryString)
87
+ }
88
+
89
+ const headers = buildHeaders(options)
90
+ const keys = Object.keys(headers)
91
+ if (keys.length > 0) {
92
+ const values: string[] = []
93
+ for (let i = 0; i < keys.length; i++) {
94
+ values.push(headers[keys[i]])
95
+ }
96
+ http.setHeaderValues(keys, values)
97
+ }
98
+
99
+ try {
100
+ const requestBody = buildRequestBody(options)
101
+ // buildRequestBody may set options.contentType to 'application/json' as a side
102
+ // effect when body is an object — so setContentType must come after
103
+ if (options.contentType) {
104
+ http.setContentType(options.contentType)
105
+ }
106
+ const bytes = requestBody ? http.doSynchronousRequest(requestBody) : http.doSynchronousRequest()
107
+ const error = http.getError()
108
+ const text = bytes ? bytes.convertToStringFromUtf8() : ''
109
+ const responseType = options.responseType ?? 'json'
110
+
111
+ let parseError = ''
112
+ let data: T | null = null
113
+
114
+ if (responseType === 'json' && text) {
115
+ try {
116
+ data = JSON.parse(text) as T
117
+ } catch (e) {
118
+ parseError = 'Json parse error: ' + e
119
+ }
120
+ }
121
+
122
+ return {
123
+ ok: !error && !parseError,
124
+ bytes: bytes,
125
+ text: text,
126
+ data: data,
127
+ error: error,
128
+ parseError: parseError
129
+ }
130
+ } catch (e) {
131
+ const exceptionText = 'Http request exception: ' + e
132
+ log.error(exceptionText)
133
+ return {
134
+ ...emptyResponse,
135
+ error: exceptionText
136
+ }
137
+ }
138
+ }
139
+
140
+ export const get = <T = any>(options: Omit<HttpRequestOptions, 'method'>): HttpResponse<T> => {
141
+ return request({ ...options, method: 'GET' })
142
+ }
143
+
144
+ export const post = <T = any>(options: Omit<HttpRequestOptions, 'method'>): HttpResponse<T> => {
145
+ return request({ ...options, method: 'POST' })
146
+ }
147
+
148
+ export const put = <T = any>(options: Omit<HttpRequestOptions, 'method'>): HttpResponse<T> => {
149
+ return request({ ...options, method: 'PUT' })
150
+ }
151
+
152
+ export const patch = <T = any>(options: Omit<HttpRequestOptions, 'method'>): HttpResponse<T> => {
153
+ return request({ ...options, method: 'PATCH' })
154
+ }
155
+
156
+ export const del = <T = any>(options: Omit<HttpRequestOptions, 'method'>): HttpResponse<T> => {
157
+ return request({ ...options, method: 'DELETE' })
158
+ }
159
+
160
+ export const head = <T = any>(options: Omit<HttpRequestOptions, 'method'>): HttpResponse<T> => {
161
+ return request({ ...options, method: 'HEAD' })
162
+ }
163
+
164
+ const buildRequestBody = (options: HttpRequestOptions): ByteArray | undefined => {
165
+ if (options.body == null) return undefined
166
+ if (typeof options.body === 'string') return new ByteArray(options.body)
167
+ if (options.body instanceof ByteArray) return options.body
168
+
169
+ if (!options.contentType) {
170
+ options.contentType = 'application/json'
171
+ }
172
+
173
+ return new ByteArray(JSON.stringify(options.body))
174
+ }
175
+
176
+ const buildHeaders = (options: HttpRequestOptions): Record<string, string> => {
177
+ const headers = { ...(options.headers ?? {}) }
178
+
179
+ if (options.auth?.bearerToken) {
180
+ headers.Authorization = bearerAuth(options.auth.bearerToken)
181
+ } else if (options.auth?.basic && !headers.Authorization) {
182
+ headers.Authorization = basicAuth(options.auth.basic.username, options.auth.basic.password)
183
+ }
184
+
185
+ return headers
186
+ }
@@ -1,19 +1,19 @@
1
- export const getModifierKeys = (): {
2
- shift: boolean,
3
- ctrl: boolean,
4
- command: boolean,
5
- win: boolean,
6
- control: boolean,
7
- alt: boolean
8
- } => {
9
- var nModifierState = App.modifierKeyState();
10
-
11
- return {
12
- shift: (nModifierState & 0x02000000) != 0,
13
- ctrl: (nModifierState & 0x04000000) != 0,
14
- alt: (nModifierState & 0x08000000) != 0,
15
- win: (nModifierState & 0x10000000) != 0,
16
- command: (nModifierState & 0x04000000) != 0,
17
- control: (nModifierState & 0x10000000) != 0
18
- };
1
+ export const getModifierKeys = (): {
2
+ shift: boolean,
3
+ ctrl: boolean,
4
+ command: boolean,
5
+ win: boolean,
6
+ control: boolean,
7
+ alt: boolean
8
+ } => {
9
+ var nModifierState = App.modifierKeyState();
10
+
11
+ return {
12
+ shift: (nModifierState & 0x02000000) != 0,
13
+ ctrl: (nModifierState & 0x04000000) != 0,
14
+ alt: (nModifierState & 0x08000000) != 0,
15
+ win: (nModifierState & 0x10000000) != 0,
16
+ command: (nModifierState & 0x04000000) != 0,
17
+ control: (nModifierState & 0x10000000) != 0
18
+ };
19
19
  }
@@ -1,89 +1,105 @@
1
- import { contains } from './string-helper'
2
-
3
- export const clearColumns = (listView: DzListView) => {
4
- for (let i = 0; i < listView.columns; i++) {
5
- listView.removeColumn(i)
6
- }
7
- }
8
-
9
- export const setDataItem = (listItem: DzListViewItem, data: any) => {
10
- listItem.addDataItem('data', data)
11
- }
12
-
13
- export const getDataItem = <T>(listItem: DzListViewItem): T | null => {
14
- return listItem?.getDataItem('data') ?? null
15
- }
16
-
17
- export const filter = (listView: DzListView, filterOn: (viewItem: DzListViewItem) => string, keywords: string, options?: { selectOnFilter?: boolean, filters?: (viewItem: DzListViewItem) => boolean }) => {
18
- listView.clearSelection()
19
- listView.getItems(DzListView.All).forEach(item => item.visible = true)
20
-
21
- const matchFilter = (text: string): boolean => {
22
- text = text.toLowerCase()
23
- var words = keywords?.toLowerCase().split(" ") ?? []
24
-
25
- return !keywords || keywords.trim() == "" ||
26
- words.every(w => {
27
- return w.length >= 1 || !isNaN(Number(w))
28
- ? contains(text, w)
29
- : text.startsWith(w)
30
- });
31
- }
32
-
33
- const setListViewItemVisibility = (viewItem: DzListViewItem): boolean => {
34
- let keywordMatch = matchFilter(filterOn(viewItem))
35
- let filtersMatch = !options?.filters || options.filters?.(viewItem) === true
36
- viewItem.visible = keywordMatch && filtersMatch
37
-
38
- if (options?.selectOnFilter === true && viewItem.visible && !listView.selectedItem()) {
39
- listView.setSelected(viewItem, true)
40
- listView.ensureItemVisible(viewItem)
41
- }
42
-
43
- return viewItem.visible;
44
- }
45
-
46
- const filterListViewItem = (viewItem: DzListViewItem): boolean => {
47
- var visible = false;
48
-
49
- if (viewItem.childCount() > 0) {
50
- var child = viewItem.firstChild()
51
- while (child) {
52
- visible = visible || filterListViewItem(child)
53
- child = child.nextSibling()
54
- }
55
- }
56
-
57
- viewItem.visible = visible || setListViewItemVisibility(viewItem);
58
- return viewItem.visible;
59
- }
60
-
61
- listView.getItems(DzListView.All).forEach(viewItem => {
62
- viewItem.visible = true
63
- filterListViewItem(viewItem)
64
- });
65
- }
66
-
67
- export const expand = (listView: DzListView, expandOrCollapse: boolean, listItem?: DzListViewItem) => {
68
- if (listItem) {
69
- listItem.open = expandOrCollapse
70
- if (listItem.childCount() > 0) {
71
- var child = listItem.firstChild()
72
- while (child) {
73
- expand(listView, expandOrCollapse, child)
74
- child = child.nextSibling()
75
- }
76
- }
77
- }
78
- else {
79
- listView.getItems(DzListView.All).forEach((item) => {
80
- item.open = expandOrCollapse
81
- })
82
- }
83
- }
84
-
85
- export const checkAll = (listView: DzListView, onOff: boolean) => {
86
- listView.getItems(onOff ? DzListView.NotChecked : DzListView.Checked).forEach(item => {
87
- (item as DzCheckListItem).on = onOff
88
- })
89
- }
1
+ import { contains } from './string-helper'
2
+
3
+ let filterRunId = 0
4
+
5
+ export const clearColumns = (listView: DzListView) => {
6
+ for (let i = 0; i < listView.columns; i++) {
7
+ listView.removeColumn(i)
8
+ }
9
+ }
10
+
11
+ export const setDataItem = (listItem: DzListViewItem, data: any) => {
12
+ listItem.addDataItem('data', data)
13
+ }
14
+
15
+ export const getDataItem = <T>(listItem: DzListViewItem): T | null => {
16
+ return listItem?.getDataItem('data') ?? null
17
+ }
18
+
19
+ export const filter = (listView: DzListView, filterOn: (viewItem: DzListViewItem) => string, keywords: string, options?: { selectOnFilter?: boolean, filters?: (viewItem: DzListViewItem) => boolean }) => {
20
+ filterRunId++
21
+ const currentRunId = filterRunId
22
+ const visitKey = '__dsfFilterVisitId'
23
+
24
+ listView.clearSelection()
25
+ const normalizedKeywords = keywords?.toLowerCase() ?? ''
26
+ const words = normalizedKeywords.split(" ")
27
+
28
+ listView.getItems(DzListView.All).forEach(item => item.visible = true)
29
+
30
+ const matchFilter = (text: string): boolean => {
31
+ text = text.toLowerCase()
32
+
33
+ return !keywords || keywords.trim() == "" ||
34
+ words.every(w => {
35
+ return w.length >= 1 || !isNaN(Number(w))
36
+ ? contains(text, w)
37
+ : text.startsWith(w)
38
+ });
39
+ }
40
+
41
+ const setListViewItemVisibility = (viewItem: DzListViewItem): boolean => {
42
+ let keywordMatch = matchFilter(filterOn(viewItem))
43
+ let filtersMatch = !options?.filters || options.filters?.(viewItem) === true
44
+ viewItem.visible = keywordMatch && filtersMatch
45
+
46
+ if (options?.selectOnFilter === true && viewItem.visible && viewItem.childCount() === 0 && !listView.selectedItem()) {
47
+ listView.setSelected(viewItem, true)
48
+ listView.ensureItemVisible(viewItem)
49
+ }
50
+
51
+ return viewItem.visible;
52
+ }
53
+
54
+ const filterListViewItem = (viewItem: DzListViewItem): boolean => {
55
+ if ((viewItem as any)[visitKey] === currentRunId) {
56
+ return viewItem.visible
57
+ }
58
+ ; (viewItem as any)[visitKey] = currentRunId
59
+
60
+ var visible = false;
61
+
62
+ if (viewItem.childCount() > 0) {
63
+ var child = viewItem.firstChild()
64
+ while (child) {
65
+ visible = visible || filterListViewItem(child)
66
+ child = child.nextSibling()
67
+ }
68
+ }
69
+
70
+ const selfVisible = setListViewItemVisibility(viewItem)
71
+ viewItem.visible = viewItem.childCount() > 0
72
+ ? visible
73
+ : selfVisible
74
+ return viewItem.visible;
75
+ }
76
+
77
+ listView.getItems(DzListView.All).forEach(viewItem => {
78
+ viewItem.visible = true
79
+ filterListViewItem(viewItem)
80
+ });
81
+ }
82
+
83
+ export const expand = (listView: DzListView, expandOrCollapse: boolean, listItem?: DzListViewItem) => {
84
+ if (listItem) {
85
+ listItem.open = expandOrCollapse
86
+ if (listItem.childCount() > 0) {
87
+ var child = listItem.firstChild()
88
+ while (child) {
89
+ expand(listView, expandOrCollapse, child)
90
+ child = child.nextSibling()
91
+ }
92
+ }
93
+ }
94
+ else {
95
+ listView.getItems(DzListView.All).forEach((item) => {
96
+ item.open = expandOrCollapse
97
+ })
98
+ }
99
+ }
100
+
101
+ export const checkAll = (listView: DzListView, onOff: boolean) => {
102
+ listView.getItems(onOff ? DzListView.NotChecked : DzListView.Checked).forEach(item => {
103
+ (item as DzCheckListItem).on = onOff
104
+ })
105
+ }
@@ -1,29 +1,29 @@
1
- import { mainWindow } from '@dsf/core/global'
2
-
3
- const actionMgr = mainWindow.getActionMgr()
4
- const paneMgr = mainWindow.getPaneMgr()
5
-
6
- export const getMenu = (menuPath: string, createIfNotFound: boolean): DzActionMenu => {
7
- var index = menuPath.indexOf("::")
8
- var hasPaneDelimiter = index >= 0
9
-
10
- // TODO: Check what a path delimiter is and how to use it
11
- if (hasPaneDelimiter) {
12
- var paneClass = menuPath.substring(0, index)
13
- var paneManager = paneMgr.findPane(paneClass)
14
- if (paneManager) {
15
- var menu = paneManager.getOptionsMenu();
16
- var subMenu = menuPath.substring(index + 2)
17
- // Get/Create the sub menu
18
- return createIfNotFound
19
- ? menu.findOrCreateSubMenu(subMenu)
20
- : menu.findSubMenu(subMenu);
21
- }
22
- }
23
- else {
24
- // Get/Create the sub menu
25
- return createIfNotFound
26
- ? actionMgr.getMenu().findOrCreateSubMenu(menuPath)
27
- : actionMgr.getMenu().findSubMenu(menuPath)
28
- }
1
+ import { mainWindow } from '@dsf/core/global'
2
+
3
+ const actionMgr = mainWindow.getActionMgr()
4
+ const paneMgr = mainWindow.getPaneMgr()
5
+
6
+ export const getMenu = (menuPath: string, createIfNotFound: boolean): DzActionMenu => {
7
+ var index = menuPath.indexOf("::")
8
+ var hasPaneDelimiter = index >= 0
9
+
10
+ // TODO: Check what a path delimiter is and how to use it
11
+ if (hasPaneDelimiter) {
12
+ var paneClass = menuPath.substring(0, index)
13
+ var paneManager = paneMgr.findPane(paneClass)
14
+ if (paneManager) {
15
+ var menu = paneManager.getOptionsMenu();
16
+ var subMenu = menuPath.substring(index + 2)
17
+ // Get/Create the sub menu
18
+ return createIfNotFound
19
+ ? menu.findOrCreateSubMenu(subMenu)
20
+ : menu.findSubMenu(subMenu);
21
+ }
22
+ }
23
+ else {
24
+ // Get/Create the sub menu
25
+ return createIfNotFound
26
+ ? actionMgr.getMenu().findOrCreateSubMenu(menuPath)
27
+ : actionMgr.getMenu().findSubMenu(menuPath)
28
+ }
29
29
  }
@@ -1,16 +1,26 @@
1
- import * as log from "@dsf/common/log"
2
-
3
- export const info = (msg: string) => {
4
- MessageBox.information(msg, "", "Ok")
5
- }
6
-
7
- export const error = (message: string, writeLog?: boolean) => {
8
- if (writeLog) log.debug(message)
9
- MessageBox.critical(message, "Error", "Ok")
10
- }
11
-
12
- export const confirm = (message?: string): { ok: boolean, cancel: boolean } => {
13
- var response = MessageBox.question(message ?? "Confirm?", "", "Ok", "Cancel");
14
-
15
- return { ok: response == 0, cancel: response != 0 };
1
+ import * as log from "@dsf/common/log"
2
+
3
+ export const info = (msg: string) => {
4
+ MessageBox.information(msg, "", "Ok")
5
+ }
6
+
7
+ export const error = (message: string, writeLog: boolean = true) => {
8
+ if (writeLog) log.debug(message)
9
+ MessageBox.critical(message, "Error", "Ok")
10
+ }
11
+
12
+ export const warning = (message: string) => {
13
+ MessageBox.warning(message, "Warning", "Ok")
14
+ }
15
+
16
+ export const confirm = (message?: string): { ok: boolean, cancel: boolean } => {
17
+ var response = MessageBox.question(message ?? "Confirm?", "", "Ok", "Cancel");
18
+
19
+ return { ok: response == 0, cancel: response != 0 };
20
+ }
21
+
22
+ export const prompt = (text: string, title: string, button0: string, button1?: string): { cancel: boolean, selection: number } => {
23
+ const response = MessageBox.question(text, title, button0, button1, "Cancel")
24
+
25
+ return { cancel: response === 0, selection: response };
16
26
  }