@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.
- package/.eslintrc +8 -0
- package/demo/elements/authorization/cc.ts +56 -27
- package/demo/elements/index.html +3 -0
- package/demo/elements/store/file-picker.html +15 -0
- package/demo/elements/store/file-picker.ts +134 -0
- package/demo/elements/store/index.html +19 -0
- package/demo/store/StorePlugin.js +1 -0
- package/dist/bindings/base/FileBindings.d.ts +4 -0
- package/dist/bindings/base/FileBindings.d.ts.map +1 -1
- package/dist/bindings/base/FileBindings.js +21 -1
- package/dist/bindings/base/FileBindings.js.map +1 -1
- package/dist/bindings/base/StoreBindings.d.ts +6 -17
- package/dist/bindings/base/StoreBindings.d.ts.map +1 -1
- package/dist/bindings/base/StoreBindings.js +15 -60
- package/dist/bindings/base/StoreBindings.js.map +1 -1
- package/dist/bindings/web/WebFileBindings.js +1 -1
- package/dist/bindings/web/WebFileBindings.js.map +1 -1
- package/dist/define/http/certificate-add.d.ts +9 -0
- package/dist/define/http/certificate-add.d.ts.map +1 -0
- package/dist/define/http/certificate-add.js +10 -0
- package/dist/define/http/certificate-add.js.map +1 -0
- package/dist/define/store/file-picker.d.ts +9 -0
- package/dist/define/store/file-picker.d.ts.map +1 -0
- package/dist/define/store/file-picker.js +10 -0
- package/dist/define/store/file-picker.js.map +1 -0
- package/dist/define/{files → store}/share-file.d.ts +1 -1
- package/dist/define/store/share-file.d.ts.map +1 -0
- package/dist/define/{files → store}/share-file.js +2 -2
- package/dist/define/store/share-file.js.map +1 -0
- package/dist/define/ui/ui-segmented-button-set.d.ts +1 -1
- package/dist/define/ui/ui-segmented-button-set.d.ts.map +1 -1
- package/dist/define/ui/ui-segmented-button-set.js.map +1 -1
- package/dist/elements/authorization/ui/CC.styles.d.ts.map +1 -1
- package/dist/elements/authorization/ui/CC.styles.js +4 -9
- package/dist/elements/authorization/ui/CC.styles.js.map +1 -1
- package/dist/elements/authorization/ui/CcAuthorization.d.ts +14 -29
- package/dist/elements/authorization/ui/CcAuthorization.d.ts.map +1 -1
- package/dist/elements/authorization/ui/CcAuthorization.js +67 -158
- package/dist/elements/authorization/ui/CcAuthorization.js.map +1 -1
- package/dist/elements/http/CertificateAdd.element.d.ts +91 -0
- package/dist/elements/http/CertificateAdd.element.d.ts.map +1 -0
- package/dist/elements/http/CertificateAdd.element.js +389 -0
- package/dist/elements/http/CertificateAdd.element.js.map +1 -0
- package/dist/elements/http/CertificateAdd.styles.d.ts +3 -0
- package/dist/elements/http/CertificateAdd.styles.d.ts.map +1 -0
- package/dist/elements/http/CertificateAdd.styles.js +61 -0
- package/dist/elements/http/CertificateAdd.styles.js.map +1 -0
- package/dist/elements/project/ProjectRunReport.d.ts +2 -1
- package/dist/elements/project/ProjectRunReport.d.ts.map +1 -1
- package/dist/elements/project/ProjectRunReport.js.map +1 -1
- package/dist/elements/store/FilePicker.element.d.ts +87 -0
- package/dist/elements/store/FilePicker.element.d.ts.map +1 -0
- package/dist/elements/store/FilePicker.element.js +263 -0
- package/dist/elements/store/FilePicker.element.js.map +1 -0
- package/dist/elements/store/FilePicker.styles.d.ts +3 -0
- package/dist/elements/store/FilePicker.styles.d.ts.map +1 -0
- package/dist/elements/store/FilePicker.styles.js +73 -0
- package/dist/elements/store/FilePicker.styles.js.map +1 -0
- package/dist/elements/store/FilesLib.d.ts +10 -0
- package/dist/elements/store/FilesLib.d.ts.map +1 -0
- package/dist/elements/store/FilesLib.js +38 -0
- package/dist/elements/store/FilesLib.js.map +1 -0
- package/dist/elements/{files/ShareFile.d.ts → store/ShareFile.element.d.ts} +1 -1
- package/dist/elements/store/ShareFile.element.d.ts.map +1 -0
- package/dist/elements/{files/ShareFile.js → store/ShareFile.element.js} +1 -1
- package/dist/elements/store/ShareFile.element.js.map +1 -0
- package/dist/elements/store/ShareFile.styles.d.ts.map +1 -0
- package/dist/elements/{files → store}/ShareFile.styles.js.map +1 -1
- package/dist/events/EventTypes.d.ts +7 -7
- package/dist/events/EventTypes.d.ts.map +1 -1
- package/dist/events/EventTypes.js +8 -7
- package/dist/events/EventTypes.js.map +1 -1
- package/dist/events/Events.d.ts +7 -1
- package/dist/events/Events.d.ts.map +1 -1
- package/dist/events/Events.js +2 -0
- package/dist/events/Events.js.map +1 -1
- package/dist/events/FilesystemEvents.d.ts +8 -0
- package/dist/events/FilesystemEvents.d.ts.map +1 -0
- package/dist/events/FilesystemEvents.js +59 -0
- package/dist/events/FilesystemEvents.js.map +1 -0
- package/dist/events/HttpClientEvents.d.ts +0 -2
- package/dist/events/HttpClientEvents.d.ts.map +1 -1
- package/dist/events/HttpClientEvents.js +0 -2
- package/dist/events/HttpClientEvents.js.map +1 -1
- package/dist/events/StoreEvents.d.ts +8 -1
- package/dist/events/StoreEvents.d.ts.map +1 -1
- package/dist/events/StoreEvents.js +19 -0
- package/dist/events/StoreEvents.js.map +1 -1
- package/dist/http-client/idb/Arc18DataUpgrade.d.ts +0 -8
- package/dist/http-client/idb/Arc18DataUpgrade.d.ts.map +1 -1
- package/dist/http-client/idb/Arc18DataUpgrade.js +11 -206
- package/dist/http-client/idb/Arc18DataUpgrade.js.map +1 -1
- package/dist/http-client/store/StoreBroadcast.d.ts +0 -5
- package/dist/http-client/store/StoreBroadcast.d.ts.map +1 -1
- package/dist/http-client/store/StoreBroadcast.js +0 -7
- package/dist/http-client/store/StoreBroadcast.js.map +1 -1
- package/dist/lib/files/FileUtils.d.ts +9 -0
- package/dist/lib/files/FileUtils.d.ts.map +1 -0
- package/dist/lib/files/FileUtils.js +13 -0
- package/dist/lib/files/FileUtils.js.map +1 -0
- package/dist/mixins/RouteMixin.d.ts +4 -0
- package/dist/mixins/RouteMixin.d.ts.map +1 -1
- package/dist/mixins/RouteMixin.js +1 -0
- package/dist/mixins/RouteMixin.js.map +1 -1
- package/dist/pages/ApplicationScreen.d.ts +1 -1
- package/dist/pages/ApplicationScreen.d.ts.map +1 -1
- package/dist/pages/ApplicationScreen.js +4 -2
- package/dist/pages/ApplicationScreen.js.map +1 -1
- package/dist/pages/api-client/ApiClient.screen.d.ts +4 -6
- package/dist/pages/api-client/ApiClient.screen.d.ts.map +1 -1
- package/dist/pages/api-client/ApiClient.screen.js +39 -31
- package/dist/pages/api-client/ApiClient.screen.js.map +1 -1
- package/dist/pages/api-client/ApiClient.styles.d.ts.map +1 -1
- package/dist/pages/api-client/ApiClient.styles.js +0 -12
- package/dist/pages/api-client/ApiClient.styles.js.map +1 -1
- package/dist/pages/api-client/Authenticate.screen.d.ts +1 -1
- package/dist/pages/api-client/Authenticate.screen.d.ts.map +1 -1
- package/dist/pages/api-client/Authenticate.screen.js +2 -2
- package/dist/pages/api-client/Authenticate.screen.js.map +1 -1
- package/dist/pages/api-client/pages/Files.page.d.ts +6 -35
- package/dist/pages/api-client/pages/Files.page.d.ts.map +1 -1
- package/dist/pages/api-client/pages/Files.page.js +45 -141
- package/dist/pages/api-client/pages/Files.page.js.map +1 -1
- package/dist/pages/api-client/pages/Shared.page.d.ts +1 -5
- package/dist/pages/api-client/pages/Shared.page.d.ts.map +1 -1
- package/dist/pages/api-client/pages/Shared.page.js +1 -40
- package/dist/pages/api-client/pages/Shared.page.js.map +1 -1
- package/dist/pages/demo/DemoPage.d.ts +7 -0
- package/dist/pages/demo/DemoPage.d.ts.map +1 -1
- package/dist/pages/demo/DemoPage.js +14 -0
- package/dist/pages/demo/DemoPage.js.map +1 -1
- package/dist/store/FileSystem.d.ts +90 -0
- package/dist/store/FileSystem.d.ts.map +1 -0
- package/dist/store/FileSystem.js +260 -0
- package/dist/store/FileSystem.js.map +1 -0
- package/dist/styles/global-styles.d.ts.map +1 -1
- package/dist/styles/global-styles.js +7 -0
- package/dist/styles/global-styles.js.map +1 -1
- package/dist/ui/button/SegmentedButtonsSet.d.ts +14 -0
- package/dist/ui/button/SegmentedButtonsSet.d.ts.map +1 -1
- package/dist/ui/button/SegmentedButtonsSet.js.map +1 -1
- package/dist/ui/icons/Icons.d.ts +2 -1
- package/dist/ui/icons/Icons.d.ts.map +1 -1
- package/dist/ui/icons/Icons.js +1 -0
- package/dist/ui/icons/Icons.js.map +1 -1
- package/dist/ui/list/UiDropdownList.d.ts +9 -1
- package/dist/ui/list/UiDropdownList.d.ts.map +1 -1
- package/dist/ui/list/UiDropdownList.js +39 -17
- package/dist/ui/list/UiDropdownList.js.map +1 -1
- package/dist/ui/list/UiList.d.ts +6 -1
- package/dist/ui/list/UiList.d.ts.map +1 -1
- package/dist/ui/list/UiList.js +24 -9
- package/dist/ui/list/UiList.js.map +1 -1
- package/dist/ui/notification/SnackNotifications.d.ts +1 -0
- package/dist/ui/notification/SnackNotifications.d.ts.map +1 -1
- package/dist/ui/notification/SnackNotifications.js +7 -0
- package/dist/ui/notification/SnackNotifications.js.map +1 -1
- package/dist/ui/table/DataTable.d.ts +4 -0
- package/dist/ui/table/DataTable.d.ts.map +1 -1
- package/dist/ui/table/DataTable.js +23 -1
- package/dist/ui/table/DataTable.js.map +1 -1
- package/package.json +1 -1
- package/src/bindings/base/FileBindings.ts +25 -1
- package/src/bindings/base/StoreBindings.ts +16 -73
- package/src/bindings/web/WebFileBindings.ts +1 -1
- package/src/define/http/certificate-add.ts +12 -0
- package/src/define/store/file-picker.ts +12 -0
- package/src/define/{files → store}/share-file.ts +2 -2
- package/src/define/ui/ui-segmented-button-set.ts +1 -1
- package/src/elements/authorization/ui/CC.styles.ts +4 -9
- package/src/elements/authorization/ui/CcAuthorization.ts +67 -167
- package/src/elements/http/CertificateAdd.element.ts +443 -0
- package/src/elements/http/CertificateAdd.styles.ts +61 -0
- package/src/elements/project/ProjectRunReport.ts +2 -1
- package/src/elements/store/FilePicker.element.ts +297 -0
- package/src/elements/store/FilePicker.styles.ts +73 -0
- package/src/elements/store/FilesLib.ts +32 -0
- package/src/events/EventTypes.ts +8 -7
- package/src/events/Events.ts +2 -0
- package/src/events/FilesystemEvents.ts +63 -0
- package/src/events/HttpClientEvents.ts +0 -2
- package/src/events/StoreEvents.ts +21 -1
- package/src/http-client/idb/Arc18DataUpgrade.ts +84 -84
- package/src/http-client/store/StoreBroadcast.ts +0 -8
- package/src/lib/files/FileUtils.ts +12 -0
- package/src/mixins/RouteMixin.ts +8 -1
- package/src/pages/ApplicationScreen.ts +5 -3
- package/src/pages/api-client/ApiClient.screen.ts +42 -33
- package/src/pages/api-client/ApiClient.styles.ts +0 -12
- package/src/pages/api-client/Authenticate.screen.ts +2 -2
- package/src/pages/api-client/pages/Files.page.ts +48 -164
- package/src/pages/api-client/pages/Shared.page.ts +2 -40
- package/src/pages/demo/DemoPage.ts +17 -0
- package/src/store/FileSystem.ts +325 -0
- package/src/styles/global-styles.ts +7 -0
- package/src/ui/button/SegmentedButtonsSet.ts +16 -1
- package/src/ui/icons/Icons.ts +2 -1
- package/src/ui/list/UiDropdownList.ts +44 -17
- package/src/ui/list/UiList.ts +26 -10
- package/src/ui/notification/SnackNotifications.ts +8 -0
- package/src/ui/table/DataTable.ts +29 -3
- package/test/elements/http/BodyFormdataEditorElement.test.ts +458 -454
- package/test/elements/http/BodyMultipartEditorElement.test.ts +609 -605
- package/test/elements/http/BodyRawEditorElement.test.ts +60 -56
- package/test/elements/http/CertificateAdd.test.ts +430 -0
- package/test/elements/store/FilePicker.test.ts +241 -0
- package/test/env.js +3 -0
- package/test/events/EventTypes.test.ts +0 -22
- package/test/helpers/StoreHelper.ts +390 -0
- package/test/helpers/UiMock.ts +19 -2
- package/tsconfig.eslint.json +3 -1
- package/web-test-runner.config.mjs +50 -3
- package/dist/define/files/share-file.d.ts.map +0 -1
- package/dist/define/files/share-file.js.map +0 -1
- package/dist/elements/files/ShareFile.d.ts.map +0 -1
- package/dist/elements/files/ShareFile.js.map +0 -1
- package/dist/elements/files/ShareFile.styles.d.ts.map +0 -1
- package/dist/events/http-client/models/CertificatesEvents.d.ts +0 -12
- package/dist/events/http-client/models/CertificatesEvents.d.ts.map +0 -1
- package/dist/events/http-client/models/CertificatesEvents.js +0 -18
- package/dist/events/http-client/models/CertificatesEvents.js.map +0 -1
- package/dist/http-client/idb/AuthDataModel.d.ts +0 -60
- package/dist/http-client/idb/AuthDataModel.d.ts.map +0 -1
- package/dist/http-client/idb/AuthDataModel.js +0 -150
- package/dist/http-client/idb/AuthDataModel.js.map +0 -1
- package/dist/http-client/idb/HostsModel.d.ts +0 -25
- package/dist/http-client/idb/HostsModel.d.ts.map +0 -1
- package/dist/http-client/idb/HostsModel.js +0 -82
- package/dist/http-client/idb/HostsModel.js.map +0 -1
- package/dist/http-client/idb/LegacyMockedStore.d.ts +0 -214
- package/dist/http-client/idb/LegacyMockedStore.d.ts.map +0 -1
- package/dist/http-client/idb/LegacyMockedStore.js +0 -486
- package/dist/http-client/idb/LegacyMockedStore.js.map +0 -1
- package/src/events/http-client/models/CertificatesEvents.ts +0 -23
- package/src/http-client/idb/AuthDataModel.ts +0 -175
- package/src/http-client/idb/HostsModel.ts +0 -125
- package/src/http-client/idb/LegacyMockedStore.ts +0 -544
- package/test/apic-ui.test.ts +0 -31
- /package/dist/elements/{files → store}/ShareFile.styles.d.ts +0 -0
- /package/dist/elements/{files → store}/ShareFile.styles.js +0 -0
- /package/src/elements/{files/ShareFile.ts → store/ShareFile.element.ts} +0 -0
- /package/src/elements/{files → store}/ShareFile.styles.ts +0 -0
|
@@ -0,0 +1,443 @@
|
|
|
1
|
+
import { Certificate, CertificateFile, CertificateType } from "@api-client/core/build/browser.js";
|
|
2
|
+
import { CSSResult, html, nothing, TemplateResult } from "lit";
|
|
3
|
+
import { property, state } from "lit/decorators.js";
|
|
4
|
+
import { live } from "lit/directives/live.js";
|
|
5
|
+
import { Events } from "../../events/Events.js";
|
|
6
|
+
import ApiElement from "../ApiElement.js";
|
|
7
|
+
import styles from './CertificateAdd.styles.js';
|
|
8
|
+
import { FileUtils } from "../../lib/files/FileUtils.js";
|
|
9
|
+
import type { ISegmentedButtonSelectionDetail } from '../../ui/button/SegmentedButtonsSet.js';
|
|
10
|
+
import type SegmentedButton from "../../ui/button/SegmentedButton.js";
|
|
11
|
+
import type Input from "../../ui/input/Input.js";
|
|
12
|
+
import type { IFileFilter, IOpenFileDialogInit } from "../../bindings/base/FileBindings.js";
|
|
13
|
+
import { SnackNotifications } from "../../ui/notification/SnackNotifications.js";
|
|
14
|
+
import '../../define/ui/ui-segmented-button.js';
|
|
15
|
+
import '../../define/ui/ui-segmented-button-set.js';
|
|
16
|
+
import '../../define/ui/ui-text-field.js';
|
|
17
|
+
import '../../define/ui/ui-button.js';
|
|
18
|
+
import '../../define/ui/ui-icon.js';
|
|
19
|
+
import '../../define/ui/ui-progress.js';
|
|
20
|
+
|
|
21
|
+
interface CertificateInfo {
|
|
22
|
+
fileName: string;
|
|
23
|
+
contents: ArrayBuffer | Buffer;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
/**
|
|
27
|
+
* An element that renders a certificate import UI.
|
|
28
|
+
*
|
|
29
|
+
* Notes for implementation:
|
|
30
|
+
* - `p12` is a single file, may have a passphrase
|
|
31
|
+
* - `pem` is 2 files: the certificate and the key
|
|
32
|
+
* - `pem` may have a `passphrase` on the key but not on the certificate.
|
|
33
|
+
*/
|
|
34
|
+
export default class CertificateAdd extends ApiElement {
|
|
35
|
+
static override get styles(): CSSResult[] {
|
|
36
|
+
return styles;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
/**
|
|
40
|
+
* The type of the certificate to import.
|
|
41
|
+
* @attribute
|
|
42
|
+
*/
|
|
43
|
+
@property({ type: String }) importType: CertificateType = 'pem';
|
|
44
|
+
|
|
45
|
+
/**
|
|
46
|
+
* The parent folder where to insert the imported certificate.
|
|
47
|
+
* @attribute
|
|
48
|
+
*/
|
|
49
|
+
@property({ type: String }) folder?: string;
|
|
50
|
+
|
|
51
|
+
/**
|
|
52
|
+
* The current workspace for the file.
|
|
53
|
+
* @attribute
|
|
54
|
+
*/
|
|
55
|
+
@property({ type: String }) space?: string;
|
|
56
|
+
|
|
57
|
+
/**
|
|
58
|
+
* When an IO operation is in progress.
|
|
59
|
+
*/
|
|
60
|
+
@state() working?: boolean;
|
|
61
|
+
|
|
62
|
+
@state() certificateFile?: CertificateInfo;
|
|
63
|
+
|
|
64
|
+
@state() keyFile?: CertificateInfo;
|
|
65
|
+
|
|
66
|
+
/**
|
|
67
|
+
* The password for the certificate
|
|
68
|
+
*/
|
|
69
|
+
certificatePassword?: string;
|
|
70
|
+
|
|
71
|
+
/**
|
|
72
|
+
* The password for the key.
|
|
73
|
+
*/
|
|
74
|
+
keyPassword?: string;
|
|
75
|
+
|
|
76
|
+
/**
|
|
77
|
+
* The user entered certificate name.
|
|
78
|
+
*/
|
|
79
|
+
protected certificateName?: string;
|
|
80
|
+
|
|
81
|
+
get hasKeyImport(): boolean {
|
|
82
|
+
return this.importType === 'pem';
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
get hasCertificatePasswordInput(): boolean {
|
|
86
|
+
return this.importType === 'p12';
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
protected handleViewSelection(e: CustomEvent<ISegmentedButtonSelectionDetail>): void {
|
|
90
|
+
if (!e.detail.selected) {
|
|
91
|
+
return;
|
|
92
|
+
}
|
|
93
|
+
const button = e.detail.button as SegmentedButton;
|
|
94
|
+
const type = button.dataset.value as CertificateType | undefined;
|
|
95
|
+
if (type) {
|
|
96
|
+
this.importType = type;
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
protected handleNameChange(e: Event): void {
|
|
101
|
+
const input = e.target as Input;
|
|
102
|
+
this.certificateName = input.value;
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
protected handleCertificatePasswordChange(e: Event): void {
|
|
106
|
+
const input = e.target as Input;
|
|
107
|
+
this.certificatePassword = input.value;
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
protected handleKeyPasswordChange(e: Event): void {
|
|
111
|
+
const input = e.target as Input;
|
|
112
|
+
this.keyPassword = input.value;
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
protected handleSelectCertificate(): void {
|
|
116
|
+
this.selectCertificateFLow();
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
protected handleSelectKey(): void {
|
|
120
|
+
this.selectKeyFLow();
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
async selectCertificateFLow(): Promise<void> {
|
|
124
|
+
this.working = true;
|
|
125
|
+
const options: IOpenFileDialogInit = {
|
|
126
|
+
multiple: false,
|
|
127
|
+
title: 'Select a certificate file',
|
|
128
|
+
filters: [{
|
|
129
|
+
description: 'Certificate files',
|
|
130
|
+
accept: {},
|
|
131
|
+
}],
|
|
132
|
+
};
|
|
133
|
+
const filters = options.filters as IFileFilter[];
|
|
134
|
+
if (this.importType === 'p12') {
|
|
135
|
+
filters[0].accept = {
|
|
136
|
+
'application/x-pkcs12': ['.p12', '.pfx'],
|
|
137
|
+
};
|
|
138
|
+
} else {
|
|
139
|
+
filters[0].accept = {
|
|
140
|
+
'application/x-pem-file': ['.pem', '.crt', '.cer', '.key'],
|
|
141
|
+
};
|
|
142
|
+
}
|
|
143
|
+
const pickResult = await Events.Filesystem.requestOpenFile(options, this);
|
|
144
|
+
if (!pickResult || pickResult.canceled) {
|
|
145
|
+
this.working = false;
|
|
146
|
+
return;
|
|
147
|
+
}
|
|
148
|
+
const [path] = pickResult.filePath as string[];
|
|
149
|
+
const readResult = await Events.Filesystem.readFile(path, { returnType: 'buffer', dispose: true }, this);
|
|
150
|
+
if (!readResult) {
|
|
151
|
+
this.working = false;
|
|
152
|
+
return;
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
const fileName = FileUtils.getFileName(path);
|
|
156
|
+
this.certificateFile = {
|
|
157
|
+
fileName,
|
|
158
|
+
contents: readResult as ArrayBuffer | Buffer,
|
|
159
|
+
};
|
|
160
|
+
this.working = false;
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
async selectKeyFLow(): Promise<void> {
|
|
164
|
+
this.working = true;
|
|
165
|
+
const options: IOpenFileDialogInit = {
|
|
166
|
+
multiple: false,
|
|
167
|
+
title: 'Select a key file',
|
|
168
|
+
filters: [{
|
|
169
|
+
description: 'Certificate key files',
|
|
170
|
+
accept: {
|
|
171
|
+
'application/x-pem-file': ['.pem', '.crt', '.cer', '.key']
|
|
172
|
+
},
|
|
173
|
+
}],
|
|
174
|
+
};
|
|
175
|
+
const pickResult = await Events.Filesystem.requestOpenFile(options, this);
|
|
176
|
+
if (!pickResult || pickResult.canceled) {
|
|
177
|
+
this.working = false;
|
|
178
|
+
return;
|
|
179
|
+
}
|
|
180
|
+
const [path] = pickResult.filePath as string[];
|
|
181
|
+
const readResult = await Events.Filesystem.readFile(path, { returnType: 'buffer', dispose: true }, this);
|
|
182
|
+
if (!readResult) {
|
|
183
|
+
this.working = false;
|
|
184
|
+
return;
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
const fileName = FileUtils.getFileName(path);
|
|
188
|
+
this.keyFile = {
|
|
189
|
+
fileName,
|
|
190
|
+
contents: readResult as ArrayBuffer | Buffer,
|
|
191
|
+
};
|
|
192
|
+
this.working = false;
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
protected isValidDropTarget(dt: DataTransfer): boolean {
|
|
196
|
+
const types = Array.from(dt.types);
|
|
197
|
+
return types.includes('Files');
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
protected handleFileDragEnter(e: DragEvent): void {
|
|
201
|
+
const dt = e.dataTransfer as DataTransfer;
|
|
202
|
+
if (!this.isValidDropTarget(dt)) {
|
|
203
|
+
return;
|
|
204
|
+
}
|
|
205
|
+
e.preventDefault();
|
|
206
|
+
dt.dropEffect = 'copy';
|
|
207
|
+
const node = e.currentTarget as HTMLElement;
|
|
208
|
+
node.classList.add('dragover');
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
protected handleFileDragLeave(e: DragEvent): void {
|
|
212
|
+
const dt = e.dataTransfer as DataTransfer;
|
|
213
|
+
if (!this.isValidDropTarget(dt)) {
|
|
214
|
+
return;
|
|
215
|
+
}
|
|
216
|
+
e.preventDefault();
|
|
217
|
+
dt.dropEffect = 'none';
|
|
218
|
+
const node = e.currentTarget as HTMLElement;
|
|
219
|
+
node.classList.remove('dragover');
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
protected handleFileDragOver(e: DragEvent): void {
|
|
223
|
+
const dt = e.dataTransfer as DataTransfer;
|
|
224
|
+
if (!this.isValidDropTarget(dt)) {
|
|
225
|
+
return;
|
|
226
|
+
}
|
|
227
|
+
e.preventDefault();
|
|
228
|
+
const node = e.currentTarget as HTMLElement;
|
|
229
|
+
node.classList.add('dragover');
|
|
230
|
+
}
|
|
231
|
+
|
|
232
|
+
protected handleFileDrop(e: DragEvent): void {
|
|
233
|
+
const dt = e.dataTransfer as DataTransfer;
|
|
234
|
+
e.preventDefault();
|
|
235
|
+
const node = e.currentTarget as HTMLElement;
|
|
236
|
+
node.classList.remove('dragover');
|
|
237
|
+
const file = dt.files[0];
|
|
238
|
+
if (!file) {
|
|
239
|
+
return;
|
|
240
|
+
}
|
|
241
|
+
const { kind } = node.dataset;
|
|
242
|
+
if (!kind) {
|
|
243
|
+
return;
|
|
244
|
+
}
|
|
245
|
+
this.processDroppedFile(file, kind as 'certificate' | 'key');
|
|
246
|
+
}
|
|
247
|
+
|
|
248
|
+
async processDroppedFile(file: File, kind: 'certificate' | 'key'): Promise<void> {
|
|
249
|
+
this.working = true;
|
|
250
|
+
const buff = await file.arrayBuffer();
|
|
251
|
+
const fileName = FileUtils.getFileName(file.name);
|
|
252
|
+
if (kind === 'certificate') {
|
|
253
|
+
this.certificateFile = {
|
|
254
|
+
fileName,
|
|
255
|
+
contents: buff,
|
|
256
|
+
};
|
|
257
|
+
} else if (kind === 'key') {
|
|
258
|
+
this.keyFile = {
|
|
259
|
+
fileName,
|
|
260
|
+
contents: buff,
|
|
261
|
+
};
|
|
262
|
+
}
|
|
263
|
+
this.working = false;
|
|
264
|
+
}
|
|
265
|
+
|
|
266
|
+
protected handleCancel(): void {
|
|
267
|
+
this.dispatchEvent(new Event('close'));
|
|
268
|
+
}
|
|
269
|
+
|
|
270
|
+
protected handleImport(): void {
|
|
271
|
+
this.submit();
|
|
272
|
+
}
|
|
273
|
+
|
|
274
|
+
async submit(): Promise<void> {
|
|
275
|
+
const invalid = this.reportValidity();
|
|
276
|
+
if (invalid) {
|
|
277
|
+
return;
|
|
278
|
+
}
|
|
279
|
+
const { certificateFile, certificateName, certificatePassword, keyFile, keyPassword, space, folder } = this;
|
|
280
|
+
if (!space) {
|
|
281
|
+
throw new Error(`The workspace key is not set on the certificate import element.`);
|
|
282
|
+
}
|
|
283
|
+
const cert = this.importType === 'p12' ?
|
|
284
|
+
Certificate.fromP12(certificateFile?.contents as ArrayBuffer, certificateName as string, certificatePassword) :
|
|
285
|
+
Certificate.fromPem(certificateFile?.contents as ArrayBuffer, keyFile?.contents as ArrayBuffer, certificateName as string, keyPassword);
|
|
286
|
+
const file = CertificateFile.fromCertificate(cert, space);
|
|
287
|
+
await Events.Store.File.create(file.toJSON(), cert.toJSON(), { parent: folder }, this);
|
|
288
|
+
this.handleCancel();
|
|
289
|
+
}
|
|
290
|
+
|
|
291
|
+
reportValidity(): boolean {
|
|
292
|
+
const inputs = Array.from((this.shadowRoot as ShadowRoot).querySelectorAll('ui-text-field'));
|
|
293
|
+
let invalid = false;
|
|
294
|
+
inputs.forEach((input) => {
|
|
295
|
+
const inputResult = input.reportValidity();
|
|
296
|
+
if (!inputResult) {
|
|
297
|
+
invalid = true;
|
|
298
|
+
}
|
|
299
|
+
});
|
|
300
|
+
|
|
301
|
+
if (!invalid) {
|
|
302
|
+
if (!this.certificateFile) {
|
|
303
|
+
invalid = true;
|
|
304
|
+
SnackNotifications.notify(`Certificate file is required.`);
|
|
305
|
+
}
|
|
306
|
+
if (!invalid && this.hasKeyImport && !this.keyFile) {
|
|
307
|
+
invalid = true;
|
|
308
|
+
SnackNotifications.notify(`The key file is required.`);
|
|
309
|
+
}
|
|
310
|
+
}
|
|
311
|
+
return invalid;
|
|
312
|
+
}
|
|
313
|
+
|
|
314
|
+
protected override render(): TemplateResult {
|
|
315
|
+
return html`
|
|
316
|
+
<div class="form">
|
|
317
|
+
${this.renderProgress()}
|
|
318
|
+
${this.renderViewToggle()}
|
|
319
|
+
${this.renderNameInput()}
|
|
320
|
+
${this.renderCertificateFile()}
|
|
321
|
+
${this.renderCertificatePasswordInput()}
|
|
322
|
+
${this.renderKeyFile()}
|
|
323
|
+
${this.renderKeyPasswordInput()}
|
|
324
|
+
${this.renderImportButton()}
|
|
325
|
+
</div>
|
|
326
|
+
`;
|
|
327
|
+
}
|
|
328
|
+
|
|
329
|
+
protected renderViewToggle(): TemplateResult {
|
|
330
|
+
const { importType } = this;
|
|
331
|
+
return html`
|
|
332
|
+
<div class="view-toggle">
|
|
333
|
+
<ui-segmented-button-set @select="${this.handleViewSelection}">
|
|
334
|
+
<ui-segmented-button
|
|
335
|
+
.selected="${importType === 'pem'}"
|
|
336
|
+
title="Import a certificate in PEM format"
|
|
337
|
+
data-value="pem"
|
|
338
|
+
>PEM</ui-segmented-button>
|
|
339
|
+
<ui-segmented-button
|
|
340
|
+
.selected="${importType === 'p12'}"
|
|
341
|
+
title="Import a bundled PFX or PKCS12 encoded private key and certificate"
|
|
342
|
+
data-value="p12"
|
|
343
|
+
>PFX or PKCS12</ui-segmented-button>
|
|
344
|
+
</ui-segmented-button-set>
|
|
345
|
+
</div>
|
|
346
|
+
`;
|
|
347
|
+
}
|
|
348
|
+
|
|
349
|
+
protected renderNameInput(): TemplateResult {
|
|
350
|
+
const { certificateName = '' } = this;
|
|
351
|
+
return html`
|
|
352
|
+
<div class="form-input">
|
|
353
|
+
<ui-text-field
|
|
354
|
+
required
|
|
355
|
+
name="name"
|
|
356
|
+
.value="${live(certificateName)}"
|
|
357
|
+
label="Certificate name"
|
|
358
|
+
@change="${this.handleNameChange}"
|
|
359
|
+
invalidText="The name is required"
|
|
360
|
+
></ui-text-field>
|
|
361
|
+
</div>
|
|
362
|
+
`;
|
|
363
|
+
}
|
|
364
|
+
|
|
365
|
+
protected renderCertificateFile(): TemplateResult {
|
|
366
|
+
const { certificateFile } = this;
|
|
367
|
+
return html`
|
|
368
|
+
<div class="cert-file" data-kind="certificate" @dragenter="${this.handleFileDragEnter}" @dragleave="${this.handleFileDragLeave}" @dragover="${this.handleFileDragOver}" @drop="${this.handleFileDrop}">
|
|
369
|
+
<p class="body-medium">Select or drop a certificate file here.</p>
|
|
370
|
+
<ui-button type="tonal" @click="${this.handleSelectCertificate}">Select certificate file</ui-button>
|
|
371
|
+
${certificateFile ? html`<span class="cert-info body-medium">${certificateFile.fileName}</span>` : html`<span class="missing body-medium"><ui-icon role="presentation" icon="warning" class="missing-icon"></ui-icon>Certificate is not selected</span>`}
|
|
372
|
+
</div>
|
|
373
|
+
`;
|
|
374
|
+
}
|
|
375
|
+
|
|
376
|
+
protected renderCertificatePasswordInput(): TemplateResult | typeof nothing {
|
|
377
|
+
const { certificatePassword = '' } = this;
|
|
378
|
+
if (!this.hasCertificatePasswordInput) {
|
|
379
|
+
return nothing;
|
|
380
|
+
}
|
|
381
|
+
return html`
|
|
382
|
+
<div class="form-input">
|
|
383
|
+
<ui-text-field
|
|
384
|
+
name="certificatePassword"
|
|
385
|
+
type="password"
|
|
386
|
+
.value="${live(certificatePassword)}"
|
|
387
|
+
label="Certificate password"
|
|
388
|
+
@change="${this.handleCertificatePasswordChange}"
|
|
389
|
+
supportingText="Optional password for the certificate"
|
|
390
|
+
></ui-text-field>
|
|
391
|
+
</div>
|
|
392
|
+
`;
|
|
393
|
+
}
|
|
394
|
+
|
|
395
|
+
protected renderKeyFile(): TemplateResult | typeof nothing {
|
|
396
|
+
if (!this.hasKeyImport) {
|
|
397
|
+
return nothing;
|
|
398
|
+
}
|
|
399
|
+
const { keyFile } = this;
|
|
400
|
+
return html`
|
|
401
|
+
<div class="cert-file" data-kind="key" @dragenter="${this.handleFileDragEnter}" @dragleave="${this.handleFileDragLeave}" @dragover="${this.handleFileDragOver}" @drop="${this.handleFileDrop}">
|
|
402
|
+
<p class="body-medium">Select or drop a key file here.</p>
|
|
403
|
+
<ui-button type="tonal" @click="${this.handleSelectKey}">Select key file</ui-button>
|
|
404
|
+
${keyFile ? html`<span class="cert-info body-medium">${keyFile.fileName}</span>` : html`<span class="missing body-medium"><ui-icon role="presentation" icon="warning" class="missing-icon"></ui-icon>Key is not selected</span>`}
|
|
405
|
+
</div>
|
|
406
|
+
`;
|
|
407
|
+
}
|
|
408
|
+
|
|
409
|
+
protected renderKeyPasswordInput(): TemplateResult | typeof nothing {
|
|
410
|
+
if (!this.hasKeyImport) {
|
|
411
|
+
return nothing;
|
|
412
|
+
}
|
|
413
|
+
const { keyPassword = '' } = this;
|
|
414
|
+
return html`
|
|
415
|
+
<div class="form-input">
|
|
416
|
+
<ui-text-field
|
|
417
|
+
name="keyPassword"
|
|
418
|
+
type="password"
|
|
419
|
+
.value="${live(keyPassword)}"
|
|
420
|
+
label="Key password"
|
|
421
|
+
@change="${this.handleKeyPasswordChange}"
|
|
422
|
+
supportingText="Optional password for the key"
|
|
423
|
+
></ui-text-field>
|
|
424
|
+
</div>
|
|
425
|
+
`;
|
|
426
|
+
}
|
|
427
|
+
|
|
428
|
+
protected renderImportButton(): TemplateResult {
|
|
429
|
+
return html`
|
|
430
|
+
<div class="form-action">
|
|
431
|
+
<ui-button type="filled" @click="${this.handleImport}">Import</ui-button>
|
|
432
|
+
<ui-button type="text" @click="${this.handleCancel}">Cancel</ui-button>
|
|
433
|
+
</div>
|
|
434
|
+
`;
|
|
435
|
+
}
|
|
436
|
+
|
|
437
|
+
protected renderProgress(): TemplateResult | typeof nothing {
|
|
438
|
+
if (!this.working) {
|
|
439
|
+
return nothing;
|
|
440
|
+
}
|
|
441
|
+
return html`<ui-progress indeterminate class="working"></ui-progress>`;
|
|
442
|
+
}
|
|
443
|
+
}
|
|
@@ -0,0 +1,61 @@
|
|
|
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
|
+
|
|
9
|
+
.form {
|
|
10
|
+
position: relative;
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
.working {
|
|
14
|
+
position: absolute;
|
|
15
|
+
top: 1px;
|
|
16
|
+
width: 100%;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
.view-toggle {
|
|
20
|
+
margin-bottom: 20px;
|
|
21
|
+
padding-top: 20px;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
.form-input {
|
|
25
|
+
margin: 12px 0;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
.cert-file {
|
|
29
|
+
margin: 20px 0;
|
|
30
|
+
padding: 8px 4px;
|
|
31
|
+
border: 1px transparent solid;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
.cert-file.dragover {
|
|
35
|
+
background-color: var(--md-sys-color-surface);
|
|
36
|
+
border-color: var(--md-sys-color-outline-variant);
|
|
37
|
+
border-radius: 8px;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
.missing,
|
|
41
|
+
.cert-info {
|
|
42
|
+
display: inline-flex;
|
|
43
|
+
margin-left: 12px;
|
|
44
|
+
vertical-align: middle;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
.missing-icon {
|
|
48
|
+
fill: var(--md-sys-color-error);
|
|
49
|
+
width: 16px;
|
|
50
|
+
height: 16px;
|
|
51
|
+
margin-right: 8px;
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
ui-text-field {
|
|
55
|
+
min-width: 320px;
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
.form-action {
|
|
59
|
+
margin-top: 20px;
|
|
60
|
+
}
|
|
61
|
+
`];
|
|
@@ -8,6 +8,7 @@ import {
|
|
|
8
8
|
import { statusTemplate } from '../http/HttpStatus.js';
|
|
9
9
|
import SegmentedButton from '../../ui/button/SegmentedButton.js';
|
|
10
10
|
import { RequestLogView } from '../http/RequestLog.js';
|
|
11
|
+
import type { ISegmentedButtonSelectionDetail } from '../../ui/button/SegmentedButtonsSet.js';
|
|
11
12
|
import '@github/relative-time-element';
|
|
12
13
|
import '../../define/http/http-request-log.js';
|
|
13
14
|
import '../../define/ui/ui-icon.js';
|
|
@@ -125,7 +126,7 @@ export default class ProjectRunReport extends LitElement {
|
|
|
125
126
|
this.currentLog = item;
|
|
126
127
|
}
|
|
127
128
|
|
|
128
|
-
protected handleViewSelection(e: CustomEvent): void {
|
|
129
|
+
protected handleViewSelection(e: CustomEvent<ISegmentedButtonSelectionDetail>): void {
|
|
129
130
|
if (!e.detail.selected) {
|
|
130
131
|
return;
|
|
131
132
|
}
|