@adcops/autocore-react 3.3.9 → 3.3.10
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/LICENSE +58 -58
- package/additional-docs/AutoCoreTagContext.md +441 -441
- package/additional-docs/ButtonApiSpecs.md +48 -48
- package/additional-docs/GlobalEventEmitter.md +243 -243
- package/additional-docs/general_recommendations.md +22 -22
- package/additional-docs/react_performance_notes.md +94 -94
- package/dist/assets/svg/blockly_logo.svg +82 -82
- package/dist/assets/svg/distance.svg +40 -40
- package/dist/assets/svg/python_logo.svg +246 -246
- package/dist/assets/svg/rotation_ccw.svg +50 -50
- package/dist/assets/svg/rotation_ccw_a.svg +57 -57
- package/dist/assets/svg/rotation_ccw_b.svg +57 -57
- package/dist/assets/svg/rotation_ccw_c.svg +57 -57
- package/dist/assets/svg/rotation_cw.svg +49 -49
- package/dist/assets/svg/rotation_cw_a.svg +30 -30
- package/dist/assets/svg/rotation_cw_b.svg +30 -30
- package/dist/assets/svg/rotation_cw_c.svg +30 -30
- package/dist/assets/svg/speed.svg +39 -39
- package/dist/components/BlocklyEditor.css +93 -93
- package/dist/components/JogPanel.css +41 -41
- package/dist/components/ProgressBarWithValue.css +27 -27
- package/dist/components/ValueIndicator.css +31 -31
- package/dist/components/osk.css +123 -123
- package/dist/core/AutoCoreTagContext.d.ts.map +1 -1
- package/dist/core/AutoCoreTagContext.js +1 -1
- package/dist/hub/HubBase.d.ts +3 -3
- package/dist/hub/HubBase.d.ts.map +1 -1
- package/dist/hub/HubBase.js +1 -1
- package/package.json +104 -104
- package/readme.md +343 -343
- package/src/assets/BlocklyLogo.tsx +27 -27
- package/src/assets/Distance.tsx +18 -18
- package/src/assets/JogLong.tsx +13 -13
- package/src/assets/JogMedium.tsx +13 -13
- package/src/assets/JogShort.tsx +13 -13
- package/src/assets/PythonLogo.tsx +83 -83
- package/src/assets/Rotation3D.tsx +13 -13
- package/src/assets/RotationCcw.tsx +33 -33
- package/src/assets/RotationCcwA.tsx +45 -45
- package/src/assets/RotationCcwB.tsx +45 -45
- package/src/assets/RotationCcwC.tsx +45 -45
- package/src/assets/RotationCw.tsx +31 -31
- package/src/assets/RotationCwA.tsx +42 -42
- package/src/assets/RotationCwB.tsx +42 -42
- package/src/assets/RotationCwC.tsx +42 -42
- package/src/assets/Run.tsx +13 -13
- package/src/assets/Speed.tsx +18 -18
- package/src/assets/SpeedFast.tsx +13 -13
- package/src/assets/SpeedMedium.tsx +13 -13
- package/src/assets/SpeedNone.tsx +13 -13
- package/src/assets/SpeedSlow.tsx +13 -13
- package/src/assets/Walk.tsx +13 -13
- package/src/assets/index.ts +22 -22
- package/src/assets/svg/blockly_logo.svg +82 -82
- package/src/assets/svg/distance.svg +40 -40
- package/src/assets/svg/python_logo.svg +246 -246
- package/src/assets/svg/rotation_ccw.svg +50 -50
- package/src/assets/svg/rotation_ccw_a.svg +57 -57
- package/src/assets/svg/rotation_ccw_b.svg +57 -57
- package/src/assets/svg/rotation_ccw_c.svg +57 -57
- package/src/assets/svg/rotation_cw.svg +49 -49
- package/src/assets/svg/rotation_cw_a.svg +30 -30
- package/src/assets/svg/rotation_cw_b.svg +30 -30
- package/src/assets/svg/rotation_cw_c.svg +30 -30
- package/src/assets/svg/speed.svg +39 -39
- package/src/components/AutoCoreDevPanel.tsx +414 -414
- package/src/components/BlocklyEditor.css +93 -93
- package/src/components/BlocklyEditor.tsx +609 -609
- package/src/components/CodeEditor.tsx +155 -155
- package/src/components/FileList.tsx +390 -390
- package/src/components/FileSelect.tsx +128 -128
- package/src/components/FitText.tsx +35 -35
- package/src/components/Indicator.tsx +188 -188
- package/src/components/IndicatorButton.tsx +214 -214
- package/src/components/IndicatorRect.tsx +172 -172
- package/src/components/JogPanel.css +41 -41
- package/src/components/JogPanel.tsx +461 -461
- package/src/components/Lamp.tsx +243 -243
- package/src/components/Osk.tsx +192 -192
- package/src/components/OskDialog.tsx +164 -164
- package/src/components/ProgressBarWithValue.css +27 -27
- package/src/components/ProgressBarWithValue.tsx +48 -48
- package/src/components/TextInput.tsx +195 -195
- package/src/components/ToggleGroup.tsx +322 -322
- package/src/components/ValueDisplay.tsx +236 -236
- package/src/components/ValueIndicator.css +31 -31
- package/src/components/ValueIndicator.tsx +135 -135
- package/src/components/ValueInput.tsx +368 -368
- package/src/components/osk.css +123 -123
- package/src/core/ActionMode.ts +19 -19
- package/src/core/AutoCoreTagContext.tsx +625 -614
- package/src/core/AutoCoreTagTypes.ts +334 -334
- package/src/core/CoreStreamTypes.ts +512 -512
- package/src/core/EventEmitterContext.tsx +434 -434
- package/src/core/IndicatorButtonState.ts +34 -34
- package/src/core/IndicatorColor.ts +35 -35
- package/src/core/MaskPatterns.ts +87 -87
- package/src/core/NumerableTypes.ts +80 -80
- package/src/core/PositionContext.ts +59 -59
- package/src/core/UniqueId.ts +41 -41
- package/src/core/ValueSimulator.ts +166 -166
- package/src/core/hoc.tsx +65 -65
- package/src/hooks/adsHooks.tsx +287 -287
- package/src/hooks/commandHooks.tsx +300 -300
- package/src/hooks/index.ts +12 -12
- package/src/hooks/useAutoCoreTag.ts +103 -103
- package/src/hooks/useScaledValue.tsx +99 -99
- package/src/hub/CommandMessage.ts +89 -89
- package/src/hub/DebugPanel.ts +307 -307
- package/src/hub/HubBase.ts +249 -236
- package/src/hub/HubSimulate.ts +124 -124
- package/src/hub/HubTauri.ts +140 -140
- package/src/hub/HubWebSocket.ts +250 -250
- package/src/hub/debug.ts +211 -211
- package/src/hub/index.ts +81 -81
- package/src/themes/adc-dark/_extensions.scss +166 -166
- package/src/themes/adc-dark/_variables.scss +913 -913
- package/src/themes/adc-dark/blue/_fonts.scss +23 -23
- package/src/themes/adc-dark/blue/adc_theme.scss +31 -31
- package/src/themes/adc-dark/blue/theme.scss +14 -14
- package/src/themes/theme-base/_colors.scss +17 -17
- package/src/themes/theme-base/_common.scss +74 -74
- package/src/themes/theme-base/_components.scss +111 -111
- package/src/themes/theme-base/_mixins.scss +243 -243
- package/src/themes/theme-base/components/button/_button.scss +644 -644
- package/src/themes/theme-base/components/button/_speeddial.scss +91 -91
- package/src/themes/theme-base/components/button/_splitbutton.scss +358 -358
- package/src/themes/theme-base/components/data/_carousel.scss +39 -39
- package/src/themes/theme-base/components/data/_datascroller.scss +47 -47
- package/src/themes/theme-base/components/data/_datatable.scss +388 -388
- package/src/themes/theme-base/components/data/_dataview.scss +47 -47
- package/src/themes/theme-base/components/data/_filter.scss +137 -137
- package/src/themes/theme-base/components/data/_orderlist.scss +86 -86
- package/src/themes/theme-base/components/data/_organizationchart.scss +50 -50
- package/src/themes/theme-base/components/data/_paginator.scss +91 -91
- package/src/themes/theme-base/components/data/_picklist.scss +73 -73
- package/src/themes/theme-base/components/data/_timeline.scss +38 -38
- package/src/themes/theme-base/components/data/_tree.scss +184 -184
- package/src/themes/theme-base/components/data/_treetable.scss +431 -431
- package/src/themes/theme-base/components/file/_fileupload.scss +41 -41
- package/src/themes/theme-base/components/input/_autocomplete.scss +94 -94
- package/src/themes/theme-base/components/input/_calendar.scss +251 -251
- package/src/themes/theme-base/components/input/_cascadeselect.scss +107 -107
- package/src/themes/theme-base/components/input/_checkbox.scss +181 -181
- package/src/themes/theme-base/components/input/_chips.scss +102 -102
- package/src/themes/theme-base/components/input/_colorpicker.scss +17 -17
- package/src/themes/theme-base/components/input/_dropdown.scss +252 -252
- package/src/themes/theme-base/components/input/_editor.scss +122 -122
- package/src/themes/theme-base/components/input/_iconfield.scss +9 -9
- package/src/themes/theme-base/components/input/_inputgroup.scss +74 -74
- package/src/themes/theme-base/components/input/_inputicon.scss +14 -14
- package/src/themes/theme-base/components/input/_inputnumber.scss +4 -4
- package/src/themes/theme-base/components/input/_inputotp.scss +10 -10
- package/src/themes/theme-base/components/input/_inputswitch.scss +99 -99
- package/src/themes/theme-base/components/input/_inputtext.scss +101 -101
- package/src/themes/theme-base/components/input/_listbox.scss +138 -138
- package/src/themes/theme-base/components/input/_mention.scss +30 -30
- package/src/themes/theme-base/components/input/_multiselect.scss +278 -278
- package/src/themes/theme-base/components/input/_password.scss +32 -32
- package/src/themes/theme-base/components/input/_radiobutton.scss +169 -169
- package/src/themes/theme-base/components/input/_rating.scss +80 -80
- package/src/themes/theme-base/components/input/_selectbutton.scss +49 -49
- package/src/themes/theme-base/components/input/_slider.scss +49 -49
- package/src/themes/theme-base/components/input/_togglebutton.scss +99 -99
- package/src/themes/theme-base/components/input/_treeselect.scss +151 -151
- package/src/themes/theme-base/components/input/_tristatecheckbox.scss +46 -46
- package/src/themes/theme-base/components/menu/_breadcrumb.scss +42 -42
- package/src/themes/theme-base/components/menu/_contextmenu.scss +39 -39
- package/src/themes/theme-base/components/menu/_dock.scss +109 -109
- package/src/themes/theme-base/components/menu/_megamenu.scss +141 -141
- package/src/themes/theme-base/components/menu/_menu.scss +33 -33
- package/src/themes/theme-base/components/menu/_menubar.scss +216 -216
- package/src/themes/theme-base/components/menu/_panelmenu.scss +153 -153
- package/src/themes/theme-base/components/menu/_slidemenu.scss +60 -60
- package/src/themes/theme-base/components/menu/_steps.scss +57 -57
- package/src/themes/theme-base/components/menu/_tabmenu.scss +50 -50
- package/src/themes/theme-base/components/menu/_tieredmenu.scss +43 -43
- package/src/themes/theme-base/components/messages/_inlinemessage.scss +69 -69
- package/src/themes/theme-base/components/messages/_message.scss +107 -107
- package/src/themes/theme-base/components/messages/_toast.scss +100 -100
- package/src/themes/theme-base/components/misc/_avatar.scss +33 -33
- package/src/themes/theme-base/components/misc/_badge.scss +76 -76
- package/src/themes/theme-base/components/misc/_chip.scss +38 -38
- package/src/themes/theme-base/components/misc/_inplace.scss +17 -17
- package/src/themes/theme-base/components/misc/_metergroup.scss +80 -80
- package/src/themes/theme-base/components/misc/_progressbar.scss +17 -17
- package/src/themes/theme-base/components/misc/_scrolltop.scss +24 -24
- package/src/themes/theme-base/components/misc/_skeleton.scss +7 -7
- package/src/themes/theme-base/components/misc/_tag.scss +39 -39
- package/src/themes/theme-base/components/misc/_terminal.scss +12 -12
- package/src/themes/theme-base/components/multimedia/_galleria.scss +153 -153
- package/src/themes/theme-base/components/multimedia/_image.scss +53 -53
- package/src/themes/theme-base/components/overlay/_confirmpopup.scss +72 -72
- package/src/themes/theme-base/components/overlay/_dialog.scss +78 -78
- package/src/themes/theme-base/components/overlay/_overlaypanel.scss +64 -64
- package/src/themes/theme-base/components/overlay/_sidebar.scss +23 -23
- package/src/themes/theme-base/components/overlay/_tooltip.scss +33 -33
- package/src/themes/theme-base/components/panel/_accordion.scss +118 -118
- package/src/themes/theme-base/components/panel/_card.scss +30 -30
- package/src/themes/theme-base/components/panel/_divider.scss +30 -30
- package/src/themes/theme-base/components/panel/_fieldset.scss +47 -47
- package/src/themes/theme-base/components/panel/_panel.scss +47 -47
- package/src/themes/theme-base/components/panel/_scrollpanel.scss +10 -10
- package/src/themes/theme-base/components/panel/_splitter.scss +23 -23
- package/src/themes/theme-base/components/panel/_stepper.scss +136 -136
- package/src/themes/theme-base/components/panel/_tabview.scss +147 -147
- package/src/themes/theme-base/components/panel/_toolbar.scss +11 -11
- package/terser.config.cjs +25 -25
- package/todo.md +18 -18
- package/tools/build-themes.cjs +65 -65
- package/tools/copy-distribution-files.cjs +77 -77
- package/tools/minify.cjs +55 -55
- package/tsconfig.json +48 -48
- package/typedoc.json +12 -12
- package/.claude/settings.local.json +0 -7
|
@@ -1,390 +1,390 @@
|
|
|
1
|
-
/*
|
|
2
|
-
* Copyright (C) 2024 Automated Design Corp.. All Rights Reserved.
|
|
3
|
-
* Created Date: 2024-04-24 16:01:53
|
|
4
|
-
* -----
|
|
5
|
-
* Last Modified: 2025-09-05 14:53:22
|
|
6
|
-
* -----
|
|
7
|
-
*
|
|
8
|
-
*/
|
|
9
|
-
|
|
10
|
-
/** @file FileList
|
|
11
|
-
* FileList allows a user to view the contents of a DataStore in the autocore-server.
|
|
12
|
-
* Files can be downloaded, deleted and optionally uploaded (if enabled).
|
|
13
|
-
*
|
|
14
|
-
* The FileList requires the autocore-server to be the backend, as files are transferred
|
|
15
|
-
* using specific commands via websockets.
|
|
16
|
-
*/
|
|
17
|
-
|
|
18
|
-
import React, { useState, useContext, useEffect } from 'react';
|
|
19
|
-
import { DataTable } from 'primereact/datatable';
|
|
20
|
-
import { Column } from 'primereact/column';
|
|
21
|
-
import { Toolbar } from 'primereact/toolbar';
|
|
22
|
-
import { Button } from 'primereact/button';
|
|
23
|
-
import { confirmPopup } from 'primereact/confirmpopup';
|
|
24
|
-
import { FileUpload, type FileUploadHandlerEvent} from 'primereact/fileupload';
|
|
25
|
-
|
|
26
|
-
import { EventEmitterContext } from '../core/EventEmitterContext';
|
|
27
|
-
import { MessageType } from '../hub/CommandMessage';
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
/**
|
|
31
|
-
* Defines properties for the file list.
|
|
32
|
-
*/
|
|
33
|
-
/**
|
|
34
|
-
* Defines properties for the file list.
|
|
35
|
-
*/
|
|
36
|
-
type FileListProps = {
|
|
37
|
-
/// The domain name assigned to the DATASTORE servelet containing the data.
|
|
38
|
-
/// Default: DATASTORE
|
|
39
|
-
domain?: string,
|
|
40
|
-
/// Enable the upload button so that files can be uploaded to the datastore.
|
|
41
|
-
/// Default: false
|
|
42
|
-
enableUpload?: boolean,
|
|
43
|
-
|
|
44
|
-
/// The subdirectory of the datastore to list.
|
|
45
|
-
/// If blank, the base directory is listed.
|
|
46
|
-
subdir?: string
|
|
47
|
-
|
|
48
|
-
/**
|
|
49
|
-
* A comma-separated list of file MIME types or file extensions.
|
|
50
|
-
* Default: .json
|
|
51
|
-
*
|
|
52
|
-
* ### Example: Filter by Extension:
|
|
53
|
-
* ```
|
|
54
|
-
* accept=".jpg,.png,.pdf" // Restricts uploads to JPG, PNG, and PDF files only
|
|
55
|
-
* ```
|
|
56
|
-
*
|
|
57
|
-
* ### Example: Filter by mime type.
|
|
58
|
-
* ```
|
|
59
|
-
* accept="image/*,application/pdf" // Allows any image type and PDF files
|
|
60
|
-
* ```
|
|
61
|
-
*
|
|
62
|
-
* ### Example: All files
|
|
63
|
-
* ```
|
|
64
|
-
* accept="/*"
|
|
65
|
-
* ```
|
|
66
|
-
*
|
|
67
|
-
*/
|
|
68
|
-
filter?: string,
|
|
69
|
-
|
|
70
|
-
/**
|
|
71
|
-
* Callback when an operation completes successfully.
|
|
72
|
-
* @returns void
|
|
73
|
-
*/
|
|
74
|
-
onSuccess? : (message:string) => void;
|
|
75
|
-
|
|
76
|
-
/***
|
|
77
|
-
* Callback when an operation results in an error.
|
|
78
|
-
*/
|
|
79
|
-
onError? : (message:string) => void;
|
|
80
|
-
}
|
|
81
|
-
|
|
82
|
-
/**
|
|
83
|
-
* Defines the information for every row item in the file list.
|
|
84
|
-
*/
|
|
85
|
-
type FileItem = {
|
|
86
|
-
id: number;
|
|
87
|
-
name: string;
|
|
88
|
-
};
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
/**
|
|
92
|
-
* `FileList` is a React functional component that displays a list of files retrieved from a specified domain
|
|
93
|
-
* in an autocore-server.
|
|
94
|
-
* It allows users to download and delete files. The component also supports file uploads, if enabled.
|
|
95
|
-
*
|
|
96
|
-
* The component uses the `EventEmitterContext` to make API calls to a backend to list, download, and delete files.
|
|
97
|
-
* It dynamically handles file operations based on the `domain` prop which determines the API endpoints for these actions.
|
|
98
|
-
*
|
|
99
|
-
* Requires
|
|
100
|
-
* ```tsx
|
|
101
|
-
* <ConfirmPopup />
|
|
102
|
-
* ```
|
|
103
|
-
* somewhere in a top-level page.
|
|
104
|
-
*
|
|
105
|
-
* Props:
|
|
106
|
-
* - `domain` (string): The domain name assigned to the DATASTORE servelet containing the data.
|
|
107
|
-
* Default: "DATASTORE"
|
|
108
|
-
* - `enableUpload` (boolean): If true, enables an upload button allowing files to be uploaded to the datastore.
|
|
109
|
-
* Default: false
|
|
110
|
-
*
|
|
111
|
-
* Example Usage:
|
|
112
|
-
* ```tsx
|
|
113
|
-
* <FileList domain="MyDomain" enableUpload={true} />
|
|
114
|
-
* ```
|
|
115
|
-
*
|
|
116
|
-
* @param {FileListProps} props The properties passed to the component.
|
|
117
|
-
*/
|
|
118
|
-
export const FileList: React.FC<FileListProps> = ({
|
|
119
|
-
domain = "DATASTORE",
|
|
120
|
-
enableUpload = false,
|
|
121
|
-
subdir,
|
|
122
|
-
filter=".json",
|
|
123
|
-
onSuccess,
|
|
124
|
-
onError
|
|
125
|
-
}) => {
|
|
126
|
-
|
|
127
|
-
const [uploadKey, setUploadKey] = useState(0);
|
|
128
|
-
const { invoke } = useContext(EventEmitterContext);
|
|
129
|
-
|
|
130
|
-
const [files, setFiles] = useState<FileItem[]>();
|
|
131
|
-
|
|
132
|
-
const makeTargetName = (s : string) => {
|
|
133
|
-
if (s !== null) {
|
|
134
|
-
if (subdir !== undefined) {
|
|
135
|
-
return `${subdir}/${s}`;
|
|
136
|
-
}
|
|
137
|
-
else {
|
|
138
|
-
return s;
|
|
139
|
-
}
|
|
140
|
-
}
|
|
141
|
-
else {
|
|
142
|
-
return "";
|
|
143
|
-
}
|
|
144
|
-
}
|
|
145
|
-
|
|
146
|
-
/**
|
|
147
|
-
* Retrieve a list of files from an autocore-server DataStoreServelet.
|
|
148
|
-
*/
|
|
149
|
-
const listFiles = async () => {
|
|
150
|
-
try {
|
|
151
|
-
const args = subdir !== undefined ? { "subdir": subdir } : {};
|
|
152
|
-
let res = await invoke(`${domain}.list_files`, MessageType.Request, args);
|
|
153
|
-
|
|
154
|
-
let items = [];
|
|
155
|
-
for (let i = 0; i < res.data.length; ++i) {
|
|
156
|
-
const item = res.data[i];
|
|
157
|
-
items.push({
|
|
158
|
-
id: i + 1,
|
|
159
|
-
name: item
|
|
160
|
-
});
|
|
161
|
-
}
|
|
162
|
-
|
|
163
|
-
setFiles(items);
|
|
164
|
-
}
|
|
165
|
-
catch (error) {
|
|
166
|
-
|
|
167
|
-
if (onError)
|
|
168
|
-
onError(`Failed to upload file list: ${error}`);
|
|
169
|
-
}
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
}
|
|
173
|
-
|
|
174
|
-
/**
|
|
175
|
-
* Handles when the download button is clicked on a list item.
|
|
176
|
-
* @param file The file item selected in the DataTable
|
|
177
|
-
*/
|
|
178
|
-
const handleDownload = async (file: FileItem) => {
|
|
179
|
-
|
|
180
|
-
let target = makeTargetName(file.name);
|
|
181
|
-
|
|
182
|
-
try {
|
|
183
|
-
await invoke(`${domain}.download_file`, MessageType.Request, { file_name: target });
|
|
184
|
-
if (onSuccess)
|
|
185
|
-
onSuccess(`Downloaded file: ${file.name}`);
|
|
186
|
-
} catch (error) {
|
|
187
|
-
|
|
188
|
-
if (onError)
|
|
189
|
-
onError(`Failed downloading file: ${error}`);
|
|
190
|
-
}
|
|
191
|
-
|
|
192
|
-
};
|
|
193
|
-
|
|
194
|
-
/**
|
|
195
|
-
* Sends the command to the autocore-server domain to delete the file.
|
|
196
|
-
* @param file_name Name of the file to delete.
|
|
197
|
-
*/
|
|
198
|
-
const handleDelete = async (file_name: string) => {
|
|
199
|
-
|
|
200
|
-
let target = makeTargetName(file_name);
|
|
201
|
-
|
|
202
|
-
try {
|
|
203
|
-
await invoke(`${domain}.delete_file`, MessageType.Request, { file_name: target });
|
|
204
|
-
if (onSuccess)
|
|
205
|
-
onSuccess(`Deleted file: ${file_name}`);
|
|
206
|
-
|
|
207
|
-
listFiles(); // Refresh the file list after successful upload
|
|
208
|
-
|
|
209
|
-
} catch (error) {
|
|
210
|
-
if (onError)
|
|
211
|
-
onError(`Failed to delete file: ${error}`);
|
|
212
|
-
}
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
listFiles();
|
|
216
|
-
};
|
|
217
|
-
|
|
218
|
-
/**
|
|
219
|
-
* Handles the upload of files selected through the PrimeReact FileUpload component.
|
|
220
|
-
* This function is triggered when a user selects files for upload and it processes each file asynchronously.
|
|
221
|
-
*
|
|
222
|
-
* The function reads the selected file as an ArrayBuffer, converts it to a Base64-encoded string, and then
|
|
223
|
-
* sends it to the server using a custom function `invoke` which interacts with the server via API calls.
|
|
224
|
-
* Upon successful upload, a success message is dispatched to the application's notification system. If the
|
|
225
|
-
* upload fails, an error message is similarly dispatched.
|
|
226
|
-
*
|
|
227
|
-
* Usage of this function requires that it be attached to a FileUpload component's event handler in the React component.
|
|
228
|
-
*
|
|
229
|
-
* @param {FileUploadSelectEvent} event - The event object provided by the FileUpload component, containing the files selected by the user.
|
|
230
|
-
*
|
|
231
|
-
* The `FileUploadSelectEvent` type should include:
|
|
232
|
-
* - `files`: An array of `File` objects that the user has selected for upload.
|
|
233
|
-
*
|
|
234
|
-
* This function utilizes the `FileReader` API to read the contents of the file. It checks if the read result
|
|
235
|
-
* is an instance of `ArrayBuffer` before proceeding to convert it to a Base64 string. Errors during file reading
|
|
236
|
-
* or uploading are caught and appropriate actions are taken (e.g., logging the error, dispatching error notifications).
|
|
237
|
-
*
|
|
238
|
-
* Note:
|
|
239
|
-
* - Ensure that the `invoke` function is properly implemented to handle the API request for file uploading.
|
|
240
|
-
* - Adjust the maximum file size and the types of files accepted by the FileUpload component according to your application's requirements.
|
|
241
|
-
* - This handler assumes a single file handling scenario. If multiple file uploads are needed, modifications to the iteration over `event.files` may be required.
|
|
242
|
-
*/
|
|
243
|
-
const handleUpload = async (event: FileUploadHandlerEvent) => {
|
|
244
|
-
const files = event.files;
|
|
245
|
-
const file = files[0]; // Assuming single file upload
|
|
246
|
-
|
|
247
|
-
let target = makeTargetName(file.name);
|
|
248
|
-
|
|
249
|
-
const reader = new FileReader();
|
|
250
|
-
reader.onload = async (e: ProgressEvent<FileReader>) => {
|
|
251
|
-
|
|
252
|
-
// Convert array buffer to base64
|
|
253
|
-
const arrayBuffer = e.target?.result as ArrayBuffer;
|
|
254
|
-
const base64String = arrayBufferToBase64(arrayBuffer);
|
|
255
|
-
|
|
256
|
-
try {
|
|
257
|
-
await invoke(`${domain}.write_file`, MessageType.Request, { file_name: target, value: base64String, options: { "base64": true } });
|
|
258
|
-
|
|
259
|
-
if (onSuccess)
|
|
260
|
-
onSuccess(`Uploaded file ${file.name}`);
|
|
261
|
-
|
|
262
|
-
// Refresh the file list after successful upload
|
|
263
|
-
listFiles();
|
|
264
|
-
|
|
265
|
-
} catch (error: any) {
|
|
266
|
-
if (onError)
|
|
267
|
-
onError(`Failed to upload file: ${error}`);
|
|
268
|
-
}
|
|
269
|
-
|
|
270
|
-
// Reset upload state of button so it show the file upload dialog again.
|
|
271
|
-
resetUpload();
|
|
272
|
-
};
|
|
273
|
-
|
|
274
|
-
reader.onerror = (error) => {
|
|
275
|
-
if (onError)
|
|
276
|
-
onError(`Error reading file: ${error}`);
|
|
277
|
-
};
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
reader.readAsArrayBuffer(file);
|
|
281
|
-
};
|
|
282
|
-
|
|
283
|
-
function arrayBufferToBase64(buffer: ArrayBuffer): string {
|
|
284
|
-
let binary = '';
|
|
285
|
-
let bytes = new Uint8Array(buffer);
|
|
286
|
-
let len = bytes.byteLength;
|
|
287
|
-
for (let i = 0; i < len; i++) {
|
|
288
|
-
binary += String.fromCharCode(bytes[i]);
|
|
289
|
-
}
|
|
290
|
-
return window.btoa(binary);
|
|
291
|
-
}
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
const resetUpload = () => {
|
|
295
|
-
setUploadKey(prevKey => prevKey + 1); // Increment key to force re-render
|
|
296
|
-
};
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
const title = `File Listing [/${subdir !== undefined ? subdir : ''}]`;
|
|
300
|
-
const toolbarStartContents = (
|
|
301
|
-
<React.Fragment>
|
|
302
|
-
<span style={{ fontWeight: 600 }}>{title}</span>
|
|
303
|
-
</React.Fragment>
|
|
304
|
-
);
|
|
305
|
-
|
|
306
|
-
const toolbarEndContents = (
|
|
307
|
-
<React.Fragment>
|
|
308
|
-
{enableUpload && (
|
|
309
|
-
<FileUpload
|
|
310
|
-
key={uploadKey}
|
|
311
|
-
customUpload={true}
|
|
312
|
-
auto
|
|
313
|
-
uploadHandler={handleUpload}
|
|
314
|
-
accept={filter}
|
|
315
|
-
maxFileSize={25000} // Set maximum file size as needed
|
|
316
|
-
mode="basic"
|
|
317
|
-
chooseLabel=""
|
|
318
|
-
chooseOptions={{
|
|
319
|
-
icon: 'pi pi-upload',
|
|
320
|
-
className: 'p-button-icon-only p-button-text p-button-rounded p-mr-2'
|
|
321
|
-
}}
|
|
322
|
-
/>
|
|
323
|
-
|
|
324
|
-
)}
|
|
325
|
-
<Button
|
|
326
|
-
icon="pi pi-refresh"
|
|
327
|
-
onClick={() => { listFiles() }}
|
|
328
|
-
className="p-button-rounded p-mr-2"
|
|
329
|
-
aria-label="Refresh"
|
|
330
|
-
size="small"
|
|
331
|
-
rounded text
|
|
332
|
-
/>
|
|
333
|
-
</React.Fragment>
|
|
334
|
-
);
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
/**
|
|
338
|
-
* Confirm that the user really wants to delete.
|
|
339
|
-
* @param event
|
|
340
|
-
*/
|
|
341
|
-
const confirmDelete = (file: FileItem, event: React.MouseEvent<HTMLButtonElement>) => {
|
|
342
|
-
|
|
343
|
-
confirmPopup({
|
|
344
|
-
target: event.currentTarget,
|
|
345
|
-
message: `Are you want to delete file ${file.name}?\nWARNING: This cannot be undone.`,
|
|
346
|
-
icon: 'pi pi-info-circle',
|
|
347
|
-
defaultFocus: 'reject',
|
|
348
|
-
acceptClassName: 'p-button-danger',
|
|
349
|
-
accept: () => handleDelete(file.name)
|
|
350
|
-
});
|
|
351
|
-
};
|
|
352
|
-
|
|
353
|
-
useEffect(() => {
|
|
354
|
-
|
|
355
|
-
listFiles();
|
|
356
|
-
|
|
357
|
-
return () => {
|
|
358
|
-
}
|
|
359
|
-
}, [domain, enableUpload]);
|
|
360
|
-
|
|
361
|
-
return (
|
|
362
|
-
|
|
363
|
-
<div>
|
|
364
|
-
<Toolbar start={toolbarStartContents} end={toolbarEndContents} style={{ padding: "1mm" }} />
|
|
365
|
-
<DataTable value={files}>
|
|
366
|
-
<Column field="name" header="Name"></Column>
|
|
367
|
-
|
|
368
|
-
<Column body={(rowData: FileItem) => (
|
|
369
|
-
<>
|
|
370
|
-
<Button
|
|
371
|
-
icon="pi pi-download"
|
|
372
|
-
onClick={() => handleDownload(rowData)}
|
|
373
|
-
className="p-button-rounded p-button-success p-mr-2"
|
|
374
|
-
style={{ marginRight: "2mm" }}
|
|
375
|
-
size="small"
|
|
376
|
-
/>
|
|
377
|
-
<Button
|
|
378
|
-
icon="pi pi-trash"
|
|
379
|
-
onClick={(e) => confirmDelete(rowData, e)}
|
|
380
|
-
className="p-button-rounded p-button-danger"
|
|
381
|
-
size="small"
|
|
382
|
-
/>
|
|
383
|
-
</>
|
|
384
|
-
)} header="Actions"></Column>
|
|
385
|
-
</DataTable>
|
|
386
|
-
</div>
|
|
387
|
-
);
|
|
388
|
-
};
|
|
389
|
-
|
|
390
|
-
export default FileList;
|
|
1
|
+
/*
|
|
2
|
+
* Copyright (C) 2024 Automated Design Corp.. All Rights Reserved.
|
|
3
|
+
* Created Date: 2024-04-24 16:01:53
|
|
4
|
+
* -----
|
|
5
|
+
* Last Modified: 2025-09-05 14:53:22
|
|
6
|
+
* -----
|
|
7
|
+
*
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
/** @file FileList
|
|
11
|
+
* FileList allows a user to view the contents of a DataStore in the autocore-server.
|
|
12
|
+
* Files can be downloaded, deleted and optionally uploaded (if enabled).
|
|
13
|
+
*
|
|
14
|
+
* The FileList requires the autocore-server to be the backend, as files are transferred
|
|
15
|
+
* using specific commands via websockets.
|
|
16
|
+
*/
|
|
17
|
+
|
|
18
|
+
import React, { useState, useContext, useEffect } from 'react';
|
|
19
|
+
import { DataTable } from 'primereact/datatable';
|
|
20
|
+
import { Column } from 'primereact/column';
|
|
21
|
+
import { Toolbar } from 'primereact/toolbar';
|
|
22
|
+
import { Button } from 'primereact/button';
|
|
23
|
+
import { confirmPopup } from 'primereact/confirmpopup';
|
|
24
|
+
import { FileUpload, type FileUploadHandlerEvent} from 'primereact/fileupload';
|
|
25
|
+
|
|
26
|
+
import { EventEmitterContext } from '../core/EventEmitterContext';
|
|
27
|
+
import { MessageType } from '../hub/CommandMessage';
|
|
28
|
+
|
|
29
|
+
|
|
30
|
+
/**
|
|
31
|
+
* Defines properties for the file list.
|
|
32
|
+
*/
|
|
33
|
+
/**
|
|
34
|
+
* Defines properties for the file list.
|
|
35
|
+
*/
|
|
36
|
+
type FileListProps = {
|
|
37
|
+
/// The domain name assigned to the DATASTORE servelet containing the data.
|
|
38
|
+
/// Default: DATASTORE
|
|
39
|
+
domain?: string,
|
|
40
|
+
/// Enable the upload button so that files can be uploaded to the datastore.
|
|
41
|
+
/// Default: false
|
|
42
|
+
enableUpload?: boolean,
|
|
43
|
+
|
|
44
|
+
/// The subdirectory of the datastore to list.
|
|
45
|
+
/// If blank, the base directory is listed.
|
|
46
|
+
subdir?: string
|
|
47
|
+
|
|
48
|
+
/**
|
|
49
|
+
* A comma-separated list of file MIME types or file extensions.
|
|
50
|
+
* Default: .json
|
|
51
|
+
*
|
|
52
|
+
* ### Example: Filter by Extension:
|
|
53
|
+
* ```
|
|
54
|
+
* accept=".jpg,.png,.pdf" // Restricts uploads to JPG, PNG, and PDF files only
|
|
55
|
+
* ```
|
|
56
|
+
*
|
|
57
|
+
* ### Example: Filter by mime type.
|
|
58
|
+
* ```
|
|
59
|
+
* accept="image/*,application/pdf" // Allows any image type and PDF files
|
|
60
|
+
* ```
|
|
61
|
+
*
|
|
62
|
+
* ### Example: All files
|
|
63
|
+
* ```
|
|
64
|
+
* accept="/*"
|
|
65
|
+
* ```
|
|
66
|
+
*
|
|
67
|
+
*/
|
|
68
|
+
filter?: string,
|
|
69
|
+
|
|
70
|
+
/**
|
|
71
|
+
* Callback when an operation completes successfully.
|
|
72
|
+
* @returns void
|
|
73
|
+
*/
|
|
74
|
+
onSuccess? : (message:string) => void;
|
|
75
|
+
|
|
76
|
+
/***
|
|
77
|
+
* Callback when an operation results in an error.
|
|
78
|
+
*/
|
|
79
|
+
onError? : (message:string) => void;
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
/**
|
|
83
|
+
* Defines the information for every row item in the file list.
|
|
84
|
+
*/
|
|
85
|
+
type FileItem = {
|
|
86
|
+
id: number;
|
|
87
|
+
name: string;
|
|
88
|
+
};
|
|
89
|
+
|
|
90
|
+
|
|
91
|
+
/**
|
|
92
|
+
* `FileList` is a React functional component that displays a list of files retrieved from a specified domain
|
|
93
|
+
* in an autocore-server.
|
|
94
|
+
* It allows users to download and delete files. The component also supports file uploads, if enabled.
|
|
95
|
+
*
|
|
96
|
+
* The component uses the `EventEmitterContext` to make API calls to a backend to list, download, and delete files.
|
|
97
|
+
* It dynamically handles file operations based on the `domain` prop which determines the API endpoints for these actions.
|
|
98
|
+
*
|
|
99
|
+
* Requires
|
|
100
|
+
* ```tsx
|
|
101
|
+
* <ConfirmPopup />
|
|
102
|
+
* ```
|
|
103
|
+
* somewhere in a top-level page.
|
|
104
|
+
*
|
|
105
|
+
* Props:
|
|
106
|
+
* - `domain` (string): The domain name assigned to the DATASTORE servelet containing the data.
|
|
107
|
+
* Default: "DATASTORE"
|
|
108
|
+
* - `enableUpload` (boolean): If true, enables an upload button allowing files to be uploaded to the datastore.
|
|
109
|
+
* Default: false
|
|
110
|
+
*
|
|
111
|
+
* Example Usage:
|
|
112
|
+
* ```tsx
|
|
113
|
+
* <FileList domain="MyDomain" enableUpload={true} />
|
|
114
|
+
* ```
|
|
115
|
+
*
|
|
116
|
+
* @param {FileListProps} props The properties passed to the component.
|
|
117
|
+
*/
|
|
118
|
+
export const FileList: React.FC<FileListProps> = ({
|
|
119
|
+
domain = "DATASTORE",
|
|
120
|
+
enableUpload = false,
|
|
121
|
+
subdir,
|
|
122
|
+
filter=".json",
|
|
123
|
+
onSuccess,
|
|
124
|
+
onError
|
|
125
|
+
}) => {
|
|
126
|
+
|
|
127
|
+
const [uploadKey, setUploadKey] = useState(0);
|
|
128
|
+
const { invoke } = useContext(EventEmitterContext);
|
|
129
|
+
|
|
130
|
+
const [files, setFiles] = useState<FileItem[]>();
|
|
131
|
+
|
|
132
|
+
const makeTargetName = (s : string) => {
|
|
133
|
+
if (s !== null) {
|
|
134
|
+
if (subdir !== undefined) {
|
|
135
|
+
return `${subdir}/${s}`;
|
|
136
|
+
}
|
|
137
|
+
else {
|
|
138
|
+
return s;
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
else {
|
|
142
|
+
return "";
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
/**
|
|
147
|
+
* Retrieve a list of files from an autocore-server DataStoreServelet.
|
|
148
|
+
*/
|
|
149
|
+
const listFiles = async () => {
|
|
150
|
+
try {
|
|
151
|
+
const args = subdir !== undefined ? { "subdir": subdir } : {};
|
|
152
|
+
let res = await invoke(`${domain}.list_files`, MessageType.Request, args);
|
|
153
|
+
|
|
154
|
+
let items = [];
|
|
155
|
+
for (let i = 0; i < res.data.length; ++i) {
|
|
156
|
+
const item = res.data[i];
|
|
157
|
+
items.push({
|
|
158
|
+
id: i + 1,
|
|
159
|
+
name: item
|
|
160
|
+
});
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
setFiles(items);
|
|
164
|
+
}
|
|
165
|
+
catch (error) {
|
|
166
|
+
|
|
167
|
+
if (onError)
|
|
168
|
+
onError(`Failed to upload file list: ${error}`);
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
/**
|
|
175
|
+
* Handles when the download button is clicked on a list item.
|
|
176
|
+
* @param file The file item selected in the DataTable
|
|
177
|
+
*/
|
|
178
|
+
const handleDownload = async (file: FileItem) => {
|
|
179
|
+
|
|
180
|
+
let target = makeTargetName(file.name);
|
|
181
|
+
|
|
182
|
+
try {
|
|
183
|
+
await invoke(`${domain}.download_file`, MessageType.Request, { file_name: target });
|
|
184
|
+
if (onSuccess)
|
|
185
|
+
onSuccess(`Downloaded file: ${file.name}`);
|
|
186
|
+
} catch (error) {
|
|
187
|
+
|
|
188
|
+
if (onError)
|
|
189
|
+
onError(`Failed downloading file: ${error}`);
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
};
|
|
193
|
+
|
|
194
|
+
/**
|
|
195
|
+
* Sends the command to the autocore-server domain to delete the file.
|
|
196
|
+
* @param file_name Name of the file to delete.
|
|
197
|
+
*/
|
|
198
|
+
const handleDelete = async (file_name: string) => {
|
|
199
|
+
|
|
200
|
+
let target = makeTargetName(file_name);
|
|
201
|
+
|
|
202
|
+
try {
|
|
203
|
+
await invoke(`${domain}.delete_file`, MessageType.Request, { file_name: target });
|
|
204
|
+
if (onSuccess)
|
|
205
|
+
onSuccess(`Deleted file: ${file_name}`);
|
|
206
|
+
|
|
207
|
+
listFiles(); // Refresh the file list after successful upload
|
|
208
|
+
|
|
209
|
+
} catch (error) {
|
|
210
|
+
if (onError)
|
|
211
|
+
onError(`Failed to delete file: ${error}`);
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
|
|
215
|
+
listFiles();
|
|
216
|
+
};
|
|
217
|
+
|
|
218
|
+
/**
|
|
219
|
+
* Handles the upload of files selected through the PrimeReact FileUpload component.
|
|
220
|
+
* This function is triggered when a user selects files for upload and it processes each file asynchronously.
|
|
221
|
+
*
|
|
222
|
+
* The function reads the selected file as an ArrayBuffer, converts it to a Base64-encoded string, and then
|
|
223
|
+
* sends it to the server using a custom function `invoke` which interacts with the server via API calls.
|
|
224
|
+
* Upon successful upload, a success message is dispatched to the application's notification system. If the
|
|
225
|
+
* upload fails, an error message is similarly dispatched.
|
|
226
|
+
*
|
|
227
|
+
* Usage of this function requires that it be attached to a FileUpload component's event handler in the React component.
|
|
228
|
+
*
|
|
229
|
+
* @param {FileUploadSelectEvent} event - The event object provided by the FileUpload component, containing the files selected by the user.
|
|
230
|
+
*
|
|
231
|
+
* The `FileUploadSelectEvent` type should include:
|
|
232
|
+
* - `files`: An array of `File` objects that the user has selected for upload.
|
|
233
|
+
*
|
|
234
|
+
* This function utilizes the `FileReader` API to read the contents of the file. It checks if the read result
|
|
235
|
+
* is an instance of `ArrayBuffer` before proceeding to convert it to a Base64 string. Errors during file reading
|
|
236
|
+
* or uploading are caught and appropriate actions are taken (e.g., logging the error, dispatching error notifications).
|
|
237
|
+
*
|
|
238
|
+
* Note:
|
|
239
|
+
* - Ensure that the `invoke` function is properly implemented to handle the API request for file uploading.
|
|
240
|
+
* - Adjust the maximum file size and the types of files accepted by the FileUpload component according to your application's requirements.
|
|
241
|
+
* - This handler assumes a single file handling scenario. If multiple file uploads are needed, modifications to the iteration over `event.files` may be required.
|
|
242
|
+
*/
|
|
243
|
+
const handleUpload = async (event: FileUploadHandlerEvent) => {
|
|
244
|
+
const files = event.files;
|
|
245
|
+
const file = files[0]; // Assuming single file upload
|
|
246
|
+
|
|
247
|
+
let target = makeTargetName(file.name);
|
|
248
|
+
|
|
249
|
+
const reader = new FileReader();
|
|
250
|
+
reader.onload = async (e: ProgressEvent<FileReader>) => {
|
|
251
|
+
|
|
252
|
+
// Convert array buffer to base64
|
|
253
|
+
const arrayBuffer = e.target?.result as ArrayBuffer;
|
|
254
|
+
const base64String = arrayBufferToBase64(arrayBuffer);
|
|
255
|
+
|
|
256
|
+
try {
|
|
257
|
+
await invoke(`${domain}.write_file`, MessageType.Request, { file_name: target, value: base64String, options: { "base64": true } });
|
|
258
|
+
|
|
259
|
+
if (onSuccess)
|
|
260
|
+
onSuccess(`Uploaded file ${file.name}`);
|
|
261
|
+
|
|
262
|
+
// Refresh the file list after successful upload
|
|
263
|
+
listFiles();
|
|
264
|
+
|
|
265
|
+
} catch (error: any) {
|
|
266
|
+
if (onError)
|
|
267
|
+
onError(`Failed to upload file: ${error}`);
|
|
268
|
+
}
|
|
269
|
+
|
|
270
|
+
// Reset upload state of button so it show the file upload dialog again.
|
|
271
|
+
resetUpload();
|
|
272
|
+
};
|
|
273
|
+
|
|
274
|
+
reader.onerror = (error) => {
|
|
275
|
+
if (onError)
|
|
276
|
+
onError(`Error reading file: ${error}`);
|
|
277
|
+
};
|
|
278
|
+
|
|
279
|
+
|
|
280
|
+
reader.readAsArrayBuffer(file);
|
|
281
|
+
};
|
|
282
|
+
|
|
283
|
+
function arrayBufferToBase64(buffer: ArrayBuffer): string {
|
|
284
|
+
let binary = '';
|
|
285
|
+
let bytes = new Uint8Array(buffer);
|
|
286
|
+
let len = bytes.byteLength;
|
|
287
|
+
for (let i = 0; i < len; i++) {
|
|
288
|
+
binary += String.fromCharCode(bytes[i]);
|
|
289
|
+
}
|
|
290
|
+
return window.btoa(binary);
|
|
291
|
+
}
|
|
292
|
+
|
|
293
|
+
|
|
294
|
+
const resetUpload = () => {
|
|
295
|
+
setUploadKey(prevKey => prevKey + 1); // Increment key to force re-render
|
|
296
|
+
};
|
|
297
|
+
|
|
298
|
+
|
|
299
|
+
const title = `File Listing [/${subdir !== undefined ? subdir : ''}]`;
|
|
300
|
+
const toolbarStartContents = (
|
|
301
|
+
<React.Fragment>
|
|
302
|
+
<span style={{ fontWeight: 600 }}>{title}</span>
|
|
303
|
+
</React.Fragment>
|
|
304
|
+
);
|
|
305
|
+
|
|
306
|
+
const toolbarEndContents = (
|
|
307
|
+
<React.Fragment>
|
|
308
|
+
{enableUpload && (
|
|
309
|
+
<FileUpload
|
|
310
|
+
key={uploadKey}
|
|
311
|
+
customUpload={true}
|
|
312
|
+
auto
|
|
313
|
+
uploadHandler={handleUpload}
|
|
314
|
+
accept={filter}
|
|
315
|
+
maxFileSize={25000} // Set maximum file size as needed
|
|
316
|
+
mode="basic"
|
|
317
|
+
chooseLabel=""
|
|
318
|
+
chooseOptions={{
|
|
319
|
+
icon: 'pi pi-upload',
|
|
320
|
+
className: 'p-button-icon-only p-button-text p-button-rounded p-mr-2'
|
|
321
|
+
}}
|
|
322
|
+
/>
|
|
323
|
+
|
|
324
|
+
)}
|
|
325
|
+
<Button
|
|
326
|
+
icon="pi pi-refresh"
|
|
327
|
+
onClick={() => { listFiles() }}
|
|
328
|
+
className="p-button-rounded p-mr-2"
|
|
329
|
+
aria-label="Refresh"
|
|
330
|
+
size="small"
|
|
331
|
+
rounded text
|
|
332
|
+
/>
|
|
333
|
+
</React.Fragment>
|
|
334
|
+
);
|
|
335
|
+
|
|
336
|
+
|
|
337
|
+
/**
|
|
338
|
+
* Confirm that the user really wants to delete.
|
|
339
|
+
* @param event
|
|
340
|
+
*/
|
|
341
|
+
const confirmDelete = (file: FileItem, event: React.MouseEvent<HTMLButtonElement>) => {
|
|
342
|
+
|
|
343
|
+
confirmPopup({
|
|
344
|
+
target: event.currentTarget,
|
|
345
|
+
message: `Are you want to delete file ${file.name}?\nWARNING: This cannot be undone.`,
|
|
346
|
+
icon: 'pi pi-info-circle',
|
|
347
|
+
defaultFocus: 'reject',
|
|
348
|
+
acceptClassName: 'p-button-danger',
|
|
349
|
+
accept: () => handleDelete(file.name)
|
|
350
|
+
});
|
|
351
|
+
};
|
|
352
|
+
|
|
353
|
+
useEffect(() => {
|
|
354
|
+
|
|
355
|
+
listFiles();
|
|
356
|
+
|
|
357
|
+
return () => {
|
|
358
|
+
}
|
|
359
|
+
}, [domain, enableUpload]);
|
|
360
|
+
|
|
361
|
+
return (
|
|
362
|
+
|
|
363
|
+
<div>
|
|
364
|
+
<Toolbar start={toolbarStartContents} end={toolbarEndContents} style={{ padding: "1mm" }} />
|
|
365
|
+
<DataTable value={files}>
|
|
366
|
+
<Column field="name" header="Name"></Column>
|
|
367
|
+
|
|
368
|
+
<Column body={(rowData: FileItem) => (
|
|
369
|
+
<>
|
|
370
|
+
<Button
|
|
371
|
+
icon="pi pi-download"
|
|
372
|
+
onClick={() => handleDownload(rowData)}
|
|
373
|
+
className="p-button-rounded p-button-success p-mr-2"
|
|
374
|
+
style={{ marginRight: "2mm" }}
|
|
375
|
+
size="small"
|
|
376
|
+
/>
|
|
377
|
+
<Button
|
|
378
|
+
icon="pi pi-trash"
|
|
379
|
+
onClick={(e) => confirmDelete(rowData, e)}
|
|
380
|
+
className="p-button-rounded p-button-danger"
|
|
381
|
+
size="small"
|
|
382
|
+
/>
|
|
383
|
+
</>
|
|
384
|
+
)} header="Actions"></Column>
|
|
385
|
+
</DataTable>
|
|
386
|
+
</div>
|
|
387
|
+
);
|
|
388
|
+
};
|
|
389
|
+
|
|
390
|
+
export default FileList;
|