@api-client/ui 0.0.11 → 0.0.13

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 (242) hide show
  1. package/.eslintrc +8 -0
  2. package/demo/elements/authorization/cc.ts +56 -27
  3. package/demo/elements/index.html +3 -0
  4. package/demo/elements/store/file-picker.html +15 -0
  5. package/demo/elements/store/file-picker.ts +134 -0
  6. package/demo/elements/store/index.html +19 -0
  7. package/demo/store/StorePlugin.js +1 -0
  8. package/dist/bindings/base/FileBindings.d.ts +4 -0
  9. package/dist/bindings/base/FileBindings.d.ts.map +1 -1
  10. package/dist/bindings/base/FileBindings.js +21 -1
  11. package/dist/bindings/base/FileBindings.js.map +1 -1
  12. package/dist/bindings/base/StoreBindings.d.ts +6 -17
  13. package/dist/bindings/base/StoreBindings.d.ts.map +1 -1
  14. package/dist/bindings/base/StoreBindings.js +15 -60
  15. package/dist/bindings/base/StoreBindings.js.map +1 -1
  16. package/dist/bindings/web/WebFileBindings.js +1 -1
  17. package/dist/bindings/web/WebFileBindings.js.map +1 -1
  18. package/dist/define/http/certificate-add.d.ts +9 -0
  19. package/dist/define/http/certificate-add.d.ts.map +1 -0
  20. package/dist/define/http/certificate-add.js +10 -0
  21. package/dist/define/http/certificate-add.js.map +1 -0
  22. package/dist/define/store/file-picker.d.ts +9 -0
  23. package/dist/define/store/file-picker.d.ts.map +1 -0
  24. package/dist/define/store/file-picker.js +10 -0
  25. package/dist/define/store/file-picker.js.map +1 -0
  26. package/dist/define/{files → store}/share-file.d.ts +1 -1
  27. package/dist/define/store/share-file.d.ts.map +1 -0
  28. package/dist/define/{files → store}/share-file.js +2 -2
  29. package/dist/define/store/share-file.js.map +1 -0
  30. package/dist/define/ui/ui-segmented-button-set.d.ts +1 -1
  31. package/dist/define/ui/ui-segmented-button-set.d.ts.map +1 -1
  32. package/dist/define/ui/ui-segmented-button-set.js.map +1 -1
  33. package/dist/elements/authorization/ui/CC.styles.d.ts.map +1 -1
  34. package/dist/elements/authorization/ui/CC.styles.js +4 -9
  35. package/dist/elements/authorization/ui/CC.styles.js.map +1 -1
  36. package/dist/elements/authorization/ui/CcAuthorization.d.ts +14 -29
  37. package/dist/elements/authorization/ui/CcAuthorization.d.ts.map +1 -1
  38. package/dist/elements/authorization/ui/CcAuthorization.js +67 -158
  39. package/dist/elements/authorization/ui/CcAuthorization.js.map +1 -1
  40. package/dist/elements/http/CertificateAdd.element.d.ts +91 -0
  41. package/dist/elements/http/CertificateAdd.element.d.ts.map +1 -0
  42. package/dist/elements/http/CertificateAdd.element.js +389 -0
  43. package/dist/elements/http/CertificateAdd.element.js.map +1 -0
  44. package/dist/elements/http/CertificateAdd.styles.d.ts +3 -0
  45. package/dist/elements/http/CertificateAdd.styles.d.ts.map +1 -0
  46. package/dist/elements/http/CertificateAdd.styles.js +61 -0
  47. package/dist/elements/http/CertificateAdd.styles.js.map +1 -0
  48. package/dist/elements/project/ProjectRunReport.d.ts +2 -1
  49. package/dist/elements/project/ProjectRunReport.d.ts.map +1 -1
  50. package/dist/elements/project/ProjectRunReport.js.map +1 -1
  51. package/dist/elements/store/FilePicker.element.d.ts +87 -0
  52. package/dist/elements/store/FilePicker.element.d.ts.map +1 -0
  53. package/dist/elements/store/FilePicker.element.js +263 -0
  54. package/dist/elements/store/FilePicker.element.js.map +1 -0
  55. package/dist/elements/store/FilePicker.styles.d.ts +3 -0
  56. package/dist/elements/store/FilePicker.styles.d.ts.map +1 -0
  57. package/dist/elements/store/FilePicker.styles.js +73 -0
  58. package/dist/elements/store/FilePicker.styles.js.map +1 -0
  59. package/dist/elements/store/FilesLib.d.ts +10 -0
  60. package/dist/elements/store/FilesLib.d.ts.map +1 -0
  61. package/dist/elements/store/FilesLib.js +38 -0
  62. package/dist/elements/store/FilesLib.js.map +1 -0
  63. package/dist/elements/{files/ShareFile.d.ts → store/ShareFile.element.d.ts} +1 -1
  64. package/dist/elements/store/ShareFile.element.d.ts.map +1 -0
  65. package/dist/elements/{files/ShareFile.js → store/ShareFile.element.js} +1 -1
  66. package/dist/elements/store/ShareFile.element.js.map +1 -0
  67. package/dist/elements/store/ShareFile.styles.d.ts.map +1 -0
  68. package/dist/elements/{files → store}/ShareFile.styles.js.map +1 -1
  69. package/dist/events/EventTypes.d.ts +7 -7
  70. package/dist/events/EventTypes.d.ts.map +1 -1
  71. package/dist/events/EventTypes.js +8 -7
  72. package/dist/events/EventTypes.js.map +1 -1
  73. package/dist/events/Events.d.ts +7 -1
  74. package/dist/events/Events.d.ts.map +1 -1
  75. package/dist/events/Events.js +2 -0
  76. package/dist/events/Events.js.map +1 -1
  77. package/dist/events/FilesystemEvents.d.ts +8 -0
  78. package/dist/events/FilesystemEvents.d.ts.map +1 -0
  79. package/dist/events/FilesystemEvents.js +59 -0
  80. package/dist/events/FilesystemEvents.js.map +1 -0
  81. package/dist/events/HttpClientEvents.d.ts +0 -2
  82. package/dist/events/HttpClientEvents.d.ts.map +1 -1
  83. package/dist/events/HttpClientEvents.js +0 -2
  84. package/dist/events/HttpClientEvents.js.map +1 -1
  85. package/dist/events/StoreEvents.d.ts +8 -1
  86. package/dist/events/StoreEvents.d.ts.map +1 -1
  87. package/dist/events/StoreEvents.js +19 -0
  88. package/dist/events/StoreEvents.js.map +1 -1
  89. package/dist/http-client/idb/Arc18DataUpgrade.d.ts +0 -8
  90. package/dist/http-client/idb/Arc18DataUpgrade.d.ts.map +1 -1
  91. package/dist/http-client/idb/Arc18DataUpgrade.js +11 -206
  92. package/dist/http-client/idb/Arc18DataUpgrade.js.map +1 -1
  93. package/dist/http-client/store/StoreBroadcast.d.ts +0 -5
  94. package/dist/http-client/store/StoreBroadcast.d.ts.map +1 -1
  95. package/dist/http-client/store/StoreBroadcast.js +0 -7
  96. package/dist/http-client/store/StoreBroadcast.js.map +1 -1
  97. package/dist/lib/files/FileUtils.d.ts +9 -0
  98. package/dist/lib/files/FileUtils.d.ts.map +1 -0
  99. package/dist/lib/files/FileUtils.js +13 -0
  100. package/dist/lib/files/FileUtils.js.map +1 -0
  101. package/dist/mixins/RouteMixin.d.ts +4 -0
  102. package/dist/mixins/RouteMixin.d.ts.map +1 -1
  103. package/dist/mixins/RouteMixin.js +1 -0
  104. package/dist/mixins/RouteMixin.js.map +1 -1
  105. package/dist/pages/ApplicationScreen.d.ts +1 -1
  106. package/dist/pages/ApplicationScreen.d.ts.map +1 -1
  107. package/dist/pages/ApplicationScreen.js +4 -2
  108. package/dist/pages/ApplicationScreen.js.map +1 -1
  109. package/dist/pages/api-client/ApiClient.screen.d.ts +4 -6
  110. package/dist/pages/api-client/ApiClient.screen.d.ts.map +1 -1
  111. package/dist/pages/api-client/ApiClient.screen.js +39 -31
  112. package/dist/pages/api-client/ApiClient.screen.js.map +1 -1
  113. package/dist/pages/api-client/ApiClient.styles.d.ts.map +1 -1
  114. package/dist/pages/api-client/ApiClient.styles.js +0 -12
  115. package/dist/pages/api-client/ApiClient.styles.js.map +1 -1
  116. package/dist/pages/api-client/Authenticate.screen.d.ts +1 -1
  117. package/dist/pages/api-client/Authenticate.screen.d.ts.map +1 -1
  118. package/dist/pages/api-client/Authenticate.screen.js +2 -2
  119. package/dist/pages/api-client/Authenticate.screen.js.map +1 -1
  120. package/dist/pages/api-client/pages/Files.page.d.ts +6 -35
  121. package/dist/pages/api-client/pages/Files.page.d.ts.map +1 -1
  122. package/dist/pages/api-client/pages/Files.page.js +45 -141
  123. package/dist/pages/api-client/pages/Files.page.js.map +1 -1
  124. package/dist/pages/api-client/pages/Shared.page.d.ts +1 -5
  125. package/dist/pages/api-client/pages/Shared.page.d.ts.map +1 -1
  126. package/dist/pages/api-client/pages/Shared.page.js +1 -40
  127. package/dist/pages/api-client/pages/Shared.page.js.map +1 -1
  128. package/dist/pages/demo/DemoPage.d.ts +7 -0
  129. package/dist/pages/demo/DemoPage.d.ts.map +1 -1
  130. package/dist/pages/demo/DemoPage.js +14 -0
  131. package/dist/pages/demo/DemoPage.js.map +1 -1
  132. package/dist/store/FileSystem.d.ts +90 -0
  133. package/dist/store/FileSystem.d.ts.map +1 -0
  134. package/dist/store/FileSystem.js +260 -0
  135. package/dist/store/FileSystem.js.map +1 -0
  136. package/dist/styles/global-styles.d.ts.map +1 -1
  137. package/dist/styles/global-styles.js +7 -0
  138. package/dist/styles/global-styles.js.map +1 -1
  139. package/dist/ui/button/SegmentedButtonsSet.d.ts +14 -0
  140. package/dist/ui/button/SegmentedButtonsSet.d.ts.map +1 -1
  141. package/dist/ui/button/SegmentedButtonsSet.js.map +1 -1
  142. package/dist/ui/icons/Icons.d.ts +2 -1
  143. package/dist/ui/icons/Icons.d.ts.map +1 -1
  144. package/dist/ui/icons/Icons.js +1 -0
  145. package/dist/ui/icons/Icons.js.map +1 -1
  146. package/dist/ui/list/UiDropdownList.d.ts +9 -1
  147. package/dist/ui/list/UiDropdownList.d.ts.map +1 -1
  148. package/dist/ui/list/UiDropdownList.js +39 -17
  149. package/dist/ui/list/UiDropdownList.js.map +1 -1
  150. package/dist/ui/list/UiList.d.ts +6 -1
  151. package/dist/ui/list/UiList.d.ts.map +1 -1
  152. package/dist/ui/list/UiList.js +24 -9
  153. package/dist/ui/list/UiList.js.map +1 -1
  154. package/dist/ui/notification/SnackNotifications.d.ts +1 -0
  155. package/dist/ui/notification/SnackNotifications.d.ts.map +1 -1
  156. package/dist/ui/notification/SnackNotifications.js +7 -0
  157. package/dist/ui/notification/SnackNotifications.js.map +1 -1
  158. package/dist/ui/table/DataTable.d.ts +4 -0
  159. package/dist/ui/table/DataTable.d.ts.map +1 -1
  160. package/dist/ui/table/DataTable.js +23 -1
  161. package/dist/ui/table/DataTable.js.map +1 -1
  162. package/package.json +1 -1
  163. package/src/bindings/base/FileBindings.ts +25 -1
  164. package/src/bindings/base/StoreBindings.ts +16 -73
  165. package/src/bindings/web/WebFileBindings.ts +1 -1
  166. package/src/define/http/certificate-add.ts +12 -0
  167. package/src/define/store/file-picker.ts +12 -0
  168. package/src/define/{files → store}/share-file.ts +2 -2
  169. package/src/define/ui/ui-segmented-button-set.ts +1 -1
  170. package/src/elements/authorization/ui/CC.styles.ts +4 -9
  171. package/src/elements/authorization/ui/CcAuthorization.ts +67 -167
  172. package/src/elements/http/CertificateAdd.element.ts +443 -0
  173. package/src/elements/http/CertificateAdd.styles.ts +61 -0
  174. package/src/elements/project/ProjectRunReport.ts +2 -1
  175. package/src/elements/store/FilePicker.element.ts +297 -0
  176. package/src/elements/store/FilePicker.styles.ts +73 -0
  177. package/src/elements/store/FilesLib.ts +32 -0
  178. package/src/events/EventTypes.ts +8 -7
  179. package/src/events/Events.ts +2 -0
  180. package/src/events/FilesystemEvents.ts +63 -0
  181. package/src/events/HttpClientEvents.ts +0 -2
  182. package/src/events/StoreEvents.ts +21 -1
  183. package/src/http-client/idb/Arc18DataUpgrade.ts +84 -84
  184. package/src/http-client/store/StoreBroadcast.ts +0 -8
  185. package/src/lib/files/FileUtils.ts +12 -0
  186. package/src/mixins/RouteMixin.ts +8 -1
  187. package/src/pages/ApplicationScreen.ts +5 -3
  188. package/src/pages/api-client/ApiClient.screen.ts +42 -33
  189. package/src/pages/api-client/ApiClient.styles.ts +0 -12
  190. package/src/pages/api-client/Authenticate.screen.ts +2 -2
  191. package/src/pages/api-client/pages/Files.page.ts +48 -164
  192. package/src/pages/api-client/pages/Shared.page.ts +2 -40
  193. package/src/pages/demo/DemoPage.ts +17 -0
  194. package/src/store/FileSystem.ts +325 -0
  195. package/src/styles/global-styles.ts +7 -0
  196. package/src/ui/button/SegmentedButtonsSet.ts +16 -1
  197. package/src/ui/icons/Icons.ts +2 -1
  198. package/src/ui/list/UiDropdownList.ts +44 -17
  199. package/src/ui/list/UiList.ts +26 -10
  200. package/src/ui/notification/SnackNotifications.ts +8 -0
  201. package/src/ui/table/DataTable.ts +29 -3
  202. package/test/elements/http/BodyFormdataEditorElement.test.ts +458 -454
  203. package/test/elements/http/BodyMultipartEditorElement.test.ts +609 -605
  204. package/test/elements/http/BodyRawEditorElement.test.ts +60 -56
  205. package/test/elements/http/CertificateAdd.test.ts +430 -0
  206. package/test/elements/store/FilePicker.test.ts +241 -0
  207. package/test/env.js +3 -0
  208. package/test/events/EventTypes.test.ts +0 -22
  209. package/test/helpers/StoreHelper.ts +390 -0
  210. package/test/helpers/UiMock.ts +19 -2
  211. package/tsconfig.eslint.json +3 -1
  212. package/web-test-runner.config.mjs +50 -3
  213. package/dist/define/files/share-file.d.ts.map +0 -1
  214. package/dist/define/files/share-file.js.map +0 -1
  215. package/dist/elements/files/ShareFile.d.ts.map +0 -1
  216. package/dist/elements/files/ShareFile.js.map +0 -1
  217. package/dist/elements/files/ShareFile.styles.d.ts.map +0 -1
  218. package/dist/events/http-client/models/CertificatesEvents.d.ts +0 -12
  219. package/dist/events/http-client/models/CertificatesEvents.d.ts.map +0 -1
  220. package/dist/events/http-client/models/CertificatesEvents.js +0 -18
  221. package/dist/events/http-client/models/CertificatesEvents.js.map +0 -1
  222. package/dist/http-client/idb/AuthDataModel.d.ts +0 -60
  223. package/dist/http-client/idb/AuthDataModel.d.ts.map +0 -1
  224. package/dist/http-client/idb/AuthDataModel.js +0 -150
  225. package/dist/http-client/idb/AuthDataModel.js.map +0 -1
  226. package/dist/http-client/idb/HostsModel.d.ts +0 -25
  227. package/dist/http-client/idb/HostsModel.d.ts.map +0 -1
  228. package/dist/http-client/idb/HostsModel.js +0 -82
  229. package/dist/http-client/idb/HostsModel.js.map +0 -1
  230. package/dist/http-client/idb/LegacyMockedStore.d.ts +0 -214
  231. package/dist/http-client/idb/LegacyMockedStore.d.ts.map +0 -1
  232. package/dist/http-client/idb/LegacyMockedStore.js +0 -486
  233. package/dist/http-client/idb/LegacyMockedStore.js.map +0 -1
  234. package/src/events/http-client/models/CertificatesEvents.ts +0 -23
  235. package/src/http-client/idb/AuthDataModel.ts +0 -175
  236. package/src/http-client/idb/HostsModel.ts +0 -125
  237. package/src/http-client/idb/LegacyMockedStore.ts +0 -544
  238. package/test/apic-ui.test.ts +0 -31
  239. /package/dist/elements/{files → store}/ShareFile.styles.d.ts +0 -0
  240. /package/dist/elements/{files → store}/ShareFile.styles.js +0 -0
  241. /package/src/elements/{files/ShareFile.ts → store/ShareFile.element.ts} +0 -0
  242. /package/src/elements/{files → store}/ShareFile.styles.ts +0 -0
@@ -0,0 +1,297 @@
1
+ import {
2
+ FolderKind, IFile,
3
+ ListFileKind
4
+ } from "@api-client/core/build/browser.js";
5
+ import { CSSResult, html, nothing, TemplateResult } from "lit";
6
+ import { eventOptions, property, query, state } from "lit/decorators.js";
7
+ import { classMap } from "lit/directives/class-map.js";
8
+ import ApiElement from "../ApiElement.js";
9
+ import styles from './FilePicker.styles.js';
10
+ import { fileIcon } from "./FilesLib.js";
11
+ import type UiList from "../../ui/list/UiList.js";
12
+ import type { UiListSelection } from "../../ui/list/UiList.js";
13
+ import { FileSystem } from "../../store/FileSystem.js";
14
+ import '../../define/ui/ui-divider.js';
15
+ import '../../define/ui/ui-button.js';
16
+ import '../../define/ui/ui-icon-button.js';
17
+ import '../../define/ui/ui-icon.js';
18
+ import '../../define/ui/ui-list.js';
19
+ import '../../define/ui/ui-list-item.js';
20
+ import '../../define/ui/ui-progress.js';
21
+
22
+ export interface FilePickerClosingReason {
23
+ /**
24
+ * Whether the picker was canceled.
25
+ */
26
+ canceled: boolean;
27
+ /**
28
+ * The file selected by the user. This is always and only selected when the `canceled` is false.
29
+ */
30
+ file?: IFile;
31
+ }
32
+
33
+ /**
34
+ * A portable element that allow to pick a file from the Store.
35
+ *
36
+ * @fires close - When a file is selected or the user cancelled the dialog. The detail object is the picked file object. Note, this event bubbles.
37
+ * @fires querycomplete - When the page of results was loaded.
38
+ */
39
+ export default class FilePicker extends ApiElement {
40
+ static override get styles(): CSSResult[] {
41
+ return styles;
42
+ }
43
+
44
+ /**
45
+ * The key of the parent folder to query for files.
46
+ * @attribute
47
+ */
48
+ @property({ type: String, hasChanged: () => false })
49
+ get folder(): string | undefined {
50
+ return this.fs.parent;
51
+ }
52
+
53
+ set folder(value: string | undefined) {
54
+ this.fs.selectFolder(value);
55
+ }
56
+
57
+ /**
58
+ * The page limit. Defaults to the store defaults.
59
+ * @attribute
60
+ */
61
+ @property({ type: Number, hasChanged: () => false })
62
+ set limit(value: number | undefined) {
63
+ this.fs.limit = value;
64
+ }
65
+
66
+ get limit(): number | undefined {
67
+ return this.fs.limit;
68
+ }
69
+
70
+ /**
71
+ * The timeout for the page query debouncer.
72
+ * @attribute
73
+ */
74
+ @property({ type: Number, hasChanged: () => false })
75
+ get debounceTimeout(): number {
76
+ return this.fs.debounceTimeout;
77
+ }
78
+
79
+ set debounceTimeout(value: number) {
80
+ this.fs.debounceTimeout = value || 0;
81
+ }
82
+
83
+ /**
84
+ * The list of file kinds to list.
85
+ * Folders are always included.
86
+ */
87
+ @property({ type: Array, hasChanged: () => false })
88
+ get kinds(): ListFileKind[] | undefined {
89
+ return this.fs.kinds;
90
+ }
91
+
92
+ set kinds(value: ListFileKind[] | undefined) {
93
+ this.fs.kinds = value;
94
+ this.fs.resetList();
95
+ this.fs.debounceQuery();
96
+ }
97
+
98
+ @query('ui-list') protected list?: UiList;
99
+
100
+ /**
101
+ * The currently selected in the picker file.
102
+ */
103
+ @state() protected selectedFile?: IFile;
104
+
105
+ @state() errorMessage?: string;
106
+
107
+ /**
108
+ * When set it does not query for files when attached to the DOM.
109
+ * It will still query for files when attributes change. This is primarily used in tests.
110
+ * @attribute
111
+ */
112
+ @property({ type: Boolean }) manualQuery?: boolean;
113
+
114
+ get selectedKey(): string | undefined {
115
+ return this.selectedFile?.key;
116
+ }
117
+
118
+ fs = new FileSystem();
119
+
120
+ constructor() {
121
+ super();
122
+ this.fs.eventsTarget = this;
123
+ this.fs.addEventListener('change', () => this.requestUpdate());
124
+ this.fs.addEventListener('error', (e: Event) => {
125
+ const event = e as CustomEvent<string>;
126
+ this.errorMessage = event.detail;
127
+ });
128
+ this.fs.addEventListener('querycomplete', () => {
129
+ this.dispatchEvent(new Event('querycomplete'));
130
+ });
131
+ this.fs.addEventListener('delete', (e: Event) => {
132
+ const event = e as CustomEvent<string>;
133
+ if (this.selectedFile && this.selectedFile.key === event.detail) {
134
+ this.selectedFile = undefined;
135
+ }
136
+ });
137
+ }
138
+
139
+ override connectedCallback(): void {
140
+ super.connectedCallback();
141
+ this.fs.observe();
142
+ if (!this.manualQuery) {
143
+ this.fs.debounceQuery();
144
+ }
145
+ if (!this.hasAttribute('tabindex')) {
146
+ this.setAttribute('tabindex', '0');
147
+ }
148
+ }
149
+
150
+ override disconnectedCallback(): void {
151
+ super.disconnectedCallback();
152
+ this.fs.unobserve();
153
+ }
154
+
155
+ override focus(options?: FocusOptions | undefined): void {
156
+ const { list } = this;
157
+ if (list) {
158
+ list.focus(options);
159
+ }
160
+ }
161
+
162
+ protected handleFileSelect(e: CustomEvent<UiListSelection>): void {
163
+ // this prevents the dropdown list to close the UI.
164
+ e.preventDefault();
165
+ const file = this.fs.files[e.detail.index];
166
+ if (!file) {
167
+ return;
168
+ }
169
+ if (file.kind === FolderKind) {
170
+ this.fs.selectFolder(file.key);
171
+ this.selectedFile = undefined;
172
+ return;
173
+ }
174
+ this.selectedFile = file;
175
+ }
176
+
177
+ protected handleParentUp(): void {
178
+ this.fs.parentUp();
179
+ this.selectedFile = undefined;
180
+ }
181
+
182
+ protected notifyClose(canceled: boolean): void {
183
+ if (!canceled && !this.selectedFile) {
184
+ return;
185
+ }
186
+ const detail: FilePickerClosingReason = {
187
+ canceled,
188
+ };
189
+ if (!canceled) {
190
+ detail.file = this.selectedFile;
191
+ }
192
+ // this event bubbles so any dropdown on the way can close itself.
193
+ const e = new CustomEvent<FilePickerClosingReason>('close', {
194
+ bubbles: true,
195
+ cancelable: true,
196
+ composed: true,
197
+ detail,
198
+ });
199
+ this.dispatchEvent(e);
200
+ }
201
+
202
+ protected handleSelect(): void {
203
+ this.notifyClose(false);
204
+ }
205
+
206
+ protected handleCancel(): void {
207
+ this.notifyClose(true);
208
+ }
209
+
210
+ @eventOptions({ passive: true })
211
+ protected handleListScroll(e: Event): void {
212
+ const list = e.target as UiList;
213
+ if (this.fs.isListEnd(list)) {
214
+ this.fs.debounceQuery();
215
+ }
216
+ }
217
+
218
+ protected override render(): TemplateResult {
219
+ return html`
220
+ <div class="content">
221
+ ${this.renderHeader()}
222
+ <ui-divider></ui-divider>
223
+ ${this.renderFiles()}
224
+ ${this.errorMessage ? html`<p class="error">${this.errorMessage}</p>` : nothing}
225
+ <ui-divider></ui-divider>
226
+ ${this.renderActions()}
227
+ </div>
228
+ `;
229
+ }
230
+
231
+ protected renderHeader(): TemplateResult {
232
+ const { breadcrumbs = [], reading } = this.fs;
233
+ let content: TemplateResult;
234
+ let withIcon = false;
235
+ if (!breadcrumbs.length) {
236
+ content = html`<span class="title-large label">My files</span>`;
237
+ } else {
238
+ withIcon = true;
239
+ const [parent] = breadcrumbs;
240
+ content = html`
241
+ <ui-icon-button aria-label="Open parent folder" @click="${this.handleParentUp}" class="back-button">
242
+ <ui-icon role="presentation" icon="arrowBack"></ui-icon>
243
+ </ui-icon-button>
244
+ <span class="title-large label">${parent.name}</span>
245
+ `;
246
+ }
247
+ const classes = {
248
+ header: true,
249
+ withIcon,
250
+ }
251
+ return html`
252
+ <div class="${classMap(classes)}">
253
+ ${content}
254
+ ${reading ? html`<ui-progress indeterminate class="progress"></ui-progress>` : nothing}
255
+ </div>
256
+ `;
257
+ }
258
+
259
+ protected renderFiles(): TemplateResult {
260
+ const { files } = this.fs;
261
+ if (!files || !files.length) {
262
+ return this.renderEmptyList();
263
+ }
264
+ return html`
265
+ <ui-list class="list" role="menu" @select="${this.handleFileSelect}" selectActive @scroll="${this.handleListScroll}">
266
+ ${files.map(item => this.renderFileItem(item))}
267
+ </ui-list>
268
+ `;
269
+ }
270
+
271
+ protected renderEmptyList(): TemplateResult {
272
+ return html`
273
+ <p class="no-files body-large">No files in this view.</p>
274
+ `;
275
+ }
276
+
277
+ protected renderFileItem(item: IFile): TemplateResult {
278
+ const icon = fileIcon(item);
279
+ return html`
280
+ <ui-list-item role="menuitem" data-key="${item.key}" data-kind="${item.kind}">
281
+ ${icon ? html`<ui-icon icon="${icon}" class="file-icon"></ui-icon>` : nothing}
282
+ ${item.info.name || 'Unnamed file'}
283
+ </ui-list-item>
284
+ `;
285
+ }
286
+
287
+ protected renderActions(): TemplateResult {
288
+ const { selectedFile } = this;
289
+ const disableSelect = !selectedFile;
290
+ return html`
291
+ <div class="actions">
292
+ <ui-button type="text" @click="${this.handleCancel}" value="cancel">Cancel</ui-button>
293
+ <ui-button type="tonal" ?disabled="${disableSelect}" @click="${this.handleSelect}" value="select">Select</ui-button>
294
+ </div>
295
+ `;
296
+ }
297
+ }
@@ -0,0 +1,73 @@
1
+ import { css } from "lit";
2
+ import typography from '../../styles/m3/typography.module.js';
3
+
4
+ export default [typography, css`
5
+ :host {
6
+ display: block;
7
+
8
+ width: 420px;
9
+ height: 400px;
10
+
11
+ background-color: var(--md-sys-color-background);
12
+ color: var(--md-sys-color-on-background);
13
+ }
14
+
15
+ .content {
16
+ height: 100%;
17
+ display: flex;
18
+ flex-direction: column;
19
+ }
20
+
21
+ .header {
22
+ height: 56px;
23
+ display: flex;
24
+ align-items: center;
25
+ position: relative;
26
+ margin: 0 16px;
27
+ }
28
+
29
+ .header.withIcon {
30
+ margin: 0 16px 0 4px;
31
+ }
32
+
33
+ .header .label {
34
+ display: block;
35
+ }
36
+
37
+ .progress {
38
+ position: absolute;
39
+ bottom: -10px; /* aligns with the divider */
40
+ width: 100%;
41
+ }
42
+
43
+ .list {
44
+ overflow-y: auto;
45
+ flex: 1;
46
+ margin: 0;
47
+ padding: 0;
48
+ }
49
+
50
+ .actions {
51
+ display: flex;
52
+ align-items: center;
53
+ justify-content: flex-end;
54
+ margin: 0 16px;
55
+ }
56
+
57
+ .file-icon {
58
+ margin-right: 12px;
59
+ }
60
+
61
+ .error {
62
+ background-color: var(--md-sys-color-error-container);
63
+ color: var(--md-sys-color-on-error-container);
64
+ display: block;
65
+ padding: 8px 12px;
66
+ border-radius: var(--md-sys-shape-corner-small);
67
+ }
68
+
69
+ .no-files {
70
+ flex: 1;
71
+ margin-left: 16px;
72
+ }
73
+ `];
@@ -0,0 +1,32 @@
1
+ import { CertificateFileKind, DataFileKind, FolderKind, IFile, ProjectKind } from "@api-client/core/build/browser.js";
2
+ import { IconType } from "../../ui/icons/Icons.js";
3
+
4
+ /**
5
+ * Sorts files on the list.
6
+ *
7
+ * Folders are always on top.
8
+ */
9
+ export function filesSortFunction(a: IFile, b: IFile): number {
10
+ if (a.kind !== b.kind) {
11
+ if (a.kind === FolderKind) {
12
+ return -1;
13
+ }
14
+ return 1;
15
+ }
16
+ if (a.kind === b.kind && a.kind === FolderKind) {
17
+ return (a.info.name || '').localeCompare(b.info.name || '');
18
+ }
19
+ return b.lastModified.time - a.lastModified.time;
20
+ }
21
+
22
+ export function fileIcon(item: IFile): IconType | undefined {
23
+ let icon: IconType | undefined;
24
+ switch (item.kind) {
25
+ case DataFileKind: icon = 'schema'; break;
26
+ case FolderKind: icon = 'folder'; break;
27
+ case ProjectKind: icon = 'collectionsBookmark'; break;
28
+ case CertificateFileKind: icon = 'certificate'; break;
29
+ default:
30
+ }
31
+ return icon;
32
+ }
@@ -21,6 +21,7 @@ export const EventTypes = Object.freeze({
21
21
  delete: 'storefilesdelete',
22
22
  patchUsers: 'storefilespatchusers',
23
23
  listUsers: 'storefileslistusers',
24
+ breadcrumbs: 'storefilesbreadcrumbs',
24
25
  }),
25
26
  User: Object.freeze({
26
27
  me: 'storeuserme',
@@ -48,13 +49,6 @@ export const EventTypes = Object.freeze({
48
49
  clearProject: 'storeprojectrunsclearproject',
49
50
  clearParent: 'storeprojectrunsclearparent',
50
51
  }),
51
- Certificate: Object.freeze({
52
- read: 'storeclientcertificateread',
53
- list: 'storeclientcertificatelist',
54
- delete: 'storeclientcertificatedelete',
55
- update: 'storeclientcertificateupdate',
56
- insert: 'storeclientcertificateinsert',
57
- }),
58
52
  }),
59
53
  Config: Object.freeze({
60
54
  Environment: Object.freeze({
@@ -181,4 +175,11 @@ export const EventTypes = Object.freeze({
181
175
  }),
182
176
  }),
183
177
  }),
178
+ // Filesystem access
179
+ Filesystem: Object.freeze({
180
+ requestSaveFile: 'filesystemrequestsavefile',
181
+ requestOpenFile: 'filesystemrequestopenfile',
182
+ writeFile: 'filesystemwritefile',
183
+ readFile: 'filesystemreadfile',
184
+ }),
184
185
  });
@@ -5,6 +5,7 @@ import { HttpProjectEvents } from './HttpProjectEvents.js';
5
5
  import { SchemaDesignEvents } from './SchemaDesignEvents.js';
6
6
  import { HttpClientEvents } from './HttpClientEvents.js';
7
7
  import { HttpEvents } from './HttpEvents.js';
8
+ import { FilesystemEvents } from './FilesystemEvents.js';
8
9
 
9
10
  export const Events = Object.freeze({
10
11
  Config: ConfigEvents,
@@ -14,4 +15,5 @@ export const Events = Object.freeze({
14
15
  HttpClient: HttpClientEvents,
15
16
  SchemaDesign: SchemaDesignEvents,
16
17
  Http: HttpEvents,
18
+ Filesystem: FilesystemEvents,
17
19
  });
@@ -0,0 +1,63 @@
1
+ import type { FileReadOptions, FileWriteOptions, IOpenFileDialogInit, IOpenFileDialogResult, ISaveFileDialogInit, ISaveFileDialogResult } from "../bindings/base/FileBindings.js";
2
+ import { EventTypes } from "./EventTypes.js";
3
+
4
+ export const FilesystemEvents = Object.freeze({
5
+ requestSaveFile: async (opts?: ISaveFileDialogInit, target: EventTarget = document.body): Promise<ISaveFileDialogResult | undefined> => {
6
+ const e = new CustomEvent(EventTypes.Filesystem.requestSaveFile, {
7
+ bubbles: true,
8
+ composed: true,
9
+ cancelable: true,
10
+ detail: {
11
+ options: opts,
12
+ result: undefined,
13
+ }
14
+ });
15
+ target.dispatchEvent(e);
16
+ return ((e.detail.result as unknown) as Promise<ISaveFileDialogResult>);
17
+ },
18
+
19
+ requestOpenFile: async (opts?: IOpenFileDialogInit, target: EventTarget = document.body): Promise<IOpenFileDialogResult | undefined> => {
20
+ const e = new CustomEvent(EventTypes.Filesystem.requestOpenFile, {
21
+ bubbles: true,
22
+ composed: true,
23
+ cancelable: true,
24
+ detail: {
25
+ options: opts,
26
+ result: undefined,
27
+ }
28
+ });
29
+ target.dispatchEvent(e);
30
+ return ((e.detail.result as unknown) as Promise<IOpenFileDialogResult>);
31
+ },
32
+
33
+ writeFile: async (path: string, contents: BufferSource | Blob | string | Buffer, opts?: FileWriteOptions, target: EventTarget = document.body): Promise<void> => {
34
+ const e = new CustomEvent(EventTypes.Filesystem.writeFile, {
35
+ bubbles: true,
36
+ composed: true,
37
+ cancelable: true,
38
+ detail: {
39
+ path,
40
+ contents,
41
+ options: opts,
42
+ result: undefined,
43
+ }
44
+ });
45
+ target.dispatchEvent(e);
46
+ await ((e.detail.result as unknown) as Promise<void>);
47
+ },
48
+
49
+ readFile: async (path: string, opts?: FileReadOptions, target: EventTarget = document.body): Promise<Buffer | ArrayBuffer | string | undefined> => {
50
+ const e = new CustomEvent(EventTypes.Filesystem.readFile, {
51
+ bubbles: true,
52
+ composed: true,
53
+ cancelable: true,
54
+ detail: {
55
+ path,
56
+ options: opts,
57
+ result: undefined,
58
+ }
59
+ });
60
+ target.dispatchEvent(e);
61
+ return ((e.detail.result as unknown) as Promise<Buffer | ArrayBuffer | string>);
62
+ },
63
+ });
@@ -1,6 +1,5 @@
1
1
  import { ContextDeleteEvent, ContextQueryEvent, IQueryResponse, IRequestUiMeta, IUrl } from '@api-client/core/build/browser.js';
2
2
  import { EventTypes } from './EventTypes.js';
3
- import { CertificatesEvents } from './http-client/models/CertificatesEvents.js';
4
3
 
5
4
  export interface IRequestUiInsertDetail {
6
5
  pid: string;
@@ -10,7 +9,6 @@ export interface IRequestUiInsertDetail {
10
9
 
11
10
  export const HttpClientEvents = Object.freeze({
12
11
  Model: Object.freeze({
13
- Certificate: CertificatesEvents,
14
12
  UrlHistory: Object.freeze({
15
13
  /**
16
14
  * Adds a new URL to the URL history store.
@@ -2,7 +2,7 @@
2
2
  import {
3
3
  IBackendInfo, IFile, IFileCreateOptions,
4
4
  ListFileKind, AccessOperation, IUser, IPatchRevision, IApplication, IHttpHistory, IHttpHistoryBulkAdd, HistoryListOptions,
5
- ContextChangeRecord, ContextDeleteEvent, ContextDeleteBulkEvent, ContextListOptions, ContextListResult, IProjectExecution, IProjectExecutionListOptions, IBulkOperationResult,
5
+ ContextChangeRecord, ContextDeleteEvent, ContextDeleteBulkEvent, ContextListOptions, ContextListResult, IProjectExecution, IProjectExecutionListOptions, IBulkOperationResult, FileBreadcrumb,
6
6
  } from '@api-client/core/build/browser.js';
7
7
  import { Patch } from '@api-client/json';
8
8
  import { IConfigEnvironment, IConfigInit } from '../lib/config/Config.js';
@@ -371,6 +371,26 @@ export const StoreEvents = Object.freeze({
371
371
  target.dispatchEvent(e);
372
372
  return ((e.detail.result as unknown) as Promise<ContextListResult<IUser>>);
373
373
  },
374
+
375
+ /**
376
+ * Lists breadcrumbs to the file.
377
+ *
378
+ * @param fileOrFolder The if of the file or folder to query for.
379
+ * @param options Optional query options.
380
+ */
381
+ breadcrumbs: async (fileOrFolder: string, target: EventTarget = document.body): Promise<ContextListResult<FileBreadcrumb>> => {
382
+ const e = new CustomEvent(EventTypes.Store.File.breadcrumbs, {
383
+ bubbles: true,
384
+ cancelable: true,
385
+ composed: true,
386
+ detail: {
387
+ key: fileOrFolder,
388
+ result: undefined,
389
+ },
390
+ });
391
+ target.dispatchEvent(e);
392
+ return ((e.detail.result as unknown) as Promise<ContextListResult<FileBreadcrumb>>);
393
+ },
374
394
  }),
375
395
  /**
376
396
  * Reads the current user.