@sparkstudio/storage-ui 1.0.18 → 1.0.19
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/dist/index.cjs +224 -12
- package/dist/index.d.cts +34 -1
- package/dist/index.d.ts +34 -1
- package/dist/index.js +222 -12
- package/package.json +1 -1
package/dist/index.cjs
CHANGED
|
@@ -29,7 +29,9 @@ __export(index_exports, {
|
|
|
29
29
|
Home: () => Home,
|
|
30
30
|
HomeView: () => HomeView,
|
|
31
31
|
S3: () => S3,
|
|
32
|
+
SingleFileProcessUploader: () => SingleFileProcessUploader,
|
|
32
33
|
SparkStudioStorageSDK: () => SparkStudioStorageSDK,
|
|
34
|
+
TemporaryFileDTO: () => TemporaryFileDTO,
|
|
33
35
|
UploadContainer: () => UploadContainer,
|
|
34
36
|
UploadDropzone: () => UploadDropzone,
|
|
35
37
|
UploadFileToS3: () => UploadFileToS3,
|
|
@@ -191,6 +193,21 @@ var S3 = class {
|
|
|
191
193
|
if (!response.ok) throw new Error(await response.text());
|
|
192
194
|
return await response.json();
|
|
193
195
|
}
|
|
196
|
+
async GetTemporaryPreSignedUrl(temporaryFileDTO) {
|
|
197
|
+
const url = `${this.baseUrl}/api/S3/GetTemporaryPreSignedUrl`;
|
|
198
|
+
const token = localStorage.getItem("auth_token");
|
|
199
|
+
const requestOptions = {
|
|
200
|
+
method: "POST",
|
|
201
|
+
headers: {
|
|
202
|
+
"Content-Type": "application/json",
|
|
203
|
+
...token && { Authorization: `Bearer ${token}` }
|
|
204
|
+
},
|
|
205
|
+
body: JSON.stringify(temporaryFileDTO)
|
|
206
|
+
};
|
|
207
|
+
const response = await fetch(url, requestOptions);
|
|
208
|
+
if (!response.ok) throw new Error(await response.text());
|
|
209
|
+
return await response.json();
|
|
210
|
+
}
|
|
194
211
|
};
|
|
195
212
|
|
|
196
213
|
// src/api/SparkStudioStorageSDK.ts
|
|
@@ -241,6 +258,16 @@ var ContainerDTO = class {
|
|
|
241
258
|
}
|
|
242
259
|
};
|
|
243
260
|
|
|
261
|
+
// src/api/DTOs/TemporaryFileDTO.ts
|
|
262
|
+
var TemporaryFileDTO = class {
|
|
263
|
+
Name;
|
|
264
|
+
ContentType;
|
|
265
|
+
constructor(init) {
|
|
266
|
+
this.Name = init.Name;
|
|
267
|
+
this.ContentType = init.ContentType;
|
|
268
|
+
}
|
|
269
|
+
};
|
|
270
|
+
|
|
244
271
|
// src/api/Enums/ContainerType.ts
|
|
245
272
|
var ContainerType = /* @__PURE__ */ ((ContainerType2) => {
|
|
246
273
|
ContainerType2[ContainerType2["File"] = 0] = "File";
|
|
@@ -1003,31 +1030,214 @@ var ContainerUploadPanel = ({
|
|
|
1003
1030
|
);
|
|
1004
1031
|
};
|
|
1005
1032
|
|
|
1033
|
+
// src/components/SingleFileProcessUploader.tsx
|
|
1034
|
+
var import_react8 = require("react");
|
|
1035
|
+
var import_jsx_runtime6 = require("react/jsx-runtime");
|
|
1036
|
+
var SingleFileProcessUploader = ({ getPresignedUrl, onUploadComplete, accept, label, disabled }) => {
|
|
1037
|
+
const [selectedFile, setSelectedFile] = (0, import_react8.useState)(null);
|
|
1038
|
+
const [isDragging, setIsDragging] = (0, import_react8.useState)(false);
|
|
1039
|
+
const [progress, setProgress] = (0, import_react8.useState)(null);
|
|
1040
|
+
const [status, setStatus] = (0, import_react8.useState)("idle");
|
|
1041
|
+
const [errorMessage, setErrorMessage] = (0, import_react8.useState)(null);
|
|
1042
|
+
const fileInputRef = (0, import_react8.useRef)(null);
|
|
1043
|
+
const handleFilesSelected = (0, import_react8.useCallback)((files) => {
|
|
1044
|
+
if (!files || files.length === 0) return;
|
|
1045
|
+
const file = files[0];
|
|
1046
|
+
setSelectedFile(file);
|
|
1047
|
+
setStatus("idle");
|
|
1048
|
+
setProgress(null);
|
|
1049
|
+
setErrorMessage(null);
|
|
1050
|
+
}, []);
|
|
1051
|
+
const handleBrowseClick = () => {
|
|
1052
|
+
if (disabled) return;
|
|
1053
|
+
fileInputRef.current?.click();
|
|
1054
|
+
};
|
|
1055
|
+
const handleInputChange = (e) => {
|
|
1056
|
+
handleFilesSelected(e.target.files);
|
|
1057
|
+
e.target.value = "";
|
|
1058
|
+
};
|
|
1059
|
+
const handleDragOver = (e) => {
|
|
1060
|
+
e.preventDefault();
|
|
1061
|
+
if (disabled) return;
|
|
1062
|
+
setIsDragging(true);
|
|
1063
|
+
};
|
|
1064
|
+
const handleDragLeave = (e) => {
|
|
1065
|
+
e.preventDefault();
|
|
1066
|
+
setIsDragging(false);
|
|
1067
|
+
};
|
|
1068
|
+
const handleDrop = (e) => {
|
|
1069
|
+
e.preventDefault();
|
|
1070
|
+
if (disabled) return;
|
|
1071
|
+
setIsDragging(false);
|
|
1072
|
+
const files = e.dataTransfer.files;
|
|
1073
|
+
handleFilesSelected(files);
|
|
1074
|
+
};
|
|
1075
|
+
const handleProcessClick = async () => {
|
|
1076
|
+
if (!selectedFile || disabled) return;
|
|
1077
|
+
try {
|
|
1078
|
+
setStatus("uploading");
|
|
1079
|
+
setProgress(0);
|
|
1080
|
+
setErrorMessage(null);
|
|
1081
|
+
const presignedUrl = await getPresignedUrl(selectedFile);
|
|
1082
|
+
await UploadFileToS3(selectedFile, presignedUrl, (p) => setProgress(p));
|
|
1083
|
+
setStatus("success");
|
|
1084
|
+
onUploadComplete?.(selectedFile, presignedUrl);
|
|
1085
|
+
} catch (err) {
|
|
1086
|
+
const message = getErrorMessage(err);
|
|
1087
|
+
console.error("Upload failed:", message);
|
|
1088
|
+
setStatus("error");
|
|
1089
|
+
setErrorMessage(message);
|
|
1090
|
+
}
|
|
1091
|
+
};
|
|
1092
|
+
function getErrorMessage(err) {
|
|
1093
|
+
if (err instanceof Error) return err.message;
|
|
1094
|
+
if (typeof err === "string") return err;
|
|
1095
|
+
return "Unknown error during upload.";
|
|
1096
|
+
}
|
|
1097
|
+
const isUploading = status === "uploading";
|
|
1098
|
+
return /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("div", { style: { display: "flex", flexDirection: "column", gap: 8 }, children: [
|
|
1099
|
+
label && /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("label", { style: { fontWeight: 600 }, children: label }),
|
|
1100
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(
|
|
1101
|
+
"div",
|
|
1102
|
+
{
|
|
1103
|
+
onDragOver: handleDragOver,
|
|
1104
|
+
onDragLeave: handleDragLeave,
|
|
1105
|
+
onDrop: handleDrop,
|
|
1106
|
+
onClick: handleBrowseClick,
|
|
1107
|
+
style: {
|
|
1108
|
+
border: "2px dashed #ccc",
|
|
1109
|
+
borderRadius: 8,
|
|
1110
|
+
padding: 16,
|
|
1111
|
+
textAlign: "center",
|
|
1112
|
+
cursor: disabled ? "not-allowed" : "pointer",
|
|
1113
|
+
backgroundColor: isDragging ? "#f0f8ff" : "#fafafa"
|
|
1114
|
+
},
|
|
1115
|
+
children: [
|
|
1116
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
|
|
1117
|
+
"input",
|
|
1118
|
+
{
|
|
1119
|
+
ref: fileInputRef,
|
|
1120
|
+
type: "file",
|
|
1121
|
+
accept,
|
|
1122
|
+
style: { display: "none" },
|
|
1123
|
+
onChange: handleInputChange,
|
|
1124
|
+
disabled
|
|
1125
|
+
}
|
|
1126
|
+
),
|
|
1127
|
+
selectedFile ? /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("div", { children: [
|
|
1128
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("div", { children: [
|
|
1129
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)("strong", { children: "Selected file:" }),
|
|
1130
|
+
" ",
|
|
1131
|
+
selectedFile.name
|
|
1132
|
+
] }),
|
|
1133
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)("div", { style: { fontSize: 12, color: "#666" }, children: "Click here to change file or drag a new one." })
|
|
1134
|
+
] }) : /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("div", { children: [
|
|
1135
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)("div", { children: "Drag & drop a file here" }),
|
|
1136
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)("div", { style: { fontSize: 12, color: "#666" }, children: "or click to browse" })
|
|
1137
|
+
] })
|
|
1138
|
+
]
|
|
1139
|
+
}
|
|
1140
|
+
),
|
|
1141
|
+
isUploading && /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("div", { style: { fontSize: 12 }, children: [
|
|
1142
|
+
"Uploading... ",
|
|
1143
|
+
progress ?? 0,
|
|
1144
|
+
"%",
|
|
1145
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
|
|
1146
|
+
"div",
|
|
1147
|
+
{
|
|
1148
|
+
style: {
|
|
1149
|
+
marginTop: 4,
|
|
1150
|
+
height: 6,
|
|
1151
|
+
borderRadius: 999,
|
|
1152
|
+
backgroundColor: "#eee",
|
|
1153
|
+
overflow: "hidden"
|
|
1154
|
+
},
|
|
1155
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
|
|
1156
|
+
"div",
|
|
1157
|
+
{
|
|
1158
|
+
style: {
|
|
1159
|
+
height: "100%",
|
|
1160
|
+
width: `${progress ?? 0}%`,
|
|
1161
|
+
backgroundColor: "#007bff",
|
|
1162
|
+
transition: "width 0.2s ease-out"
|
|
1163
|
+
}
|
|
1164
|
+
}
|
|
1165
|
+
)
|
|
1166
|
+
}
|
|
1167
|
+
)
|
|
1168
|
+
] }),
|
|
1169
|
+
status === "success" && /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("div", { style: { fontSize: 12, color: "green" }, children: "Upload complete \u2705" }),
|
|
1170
|
+
status === "error" && /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("div", { style: { fontSize: 12, color: "red" }, children: [
|
|
1171
|
+
"Upload failed: ",
|
|
1172
|
+
errorMessage
|
|
1173
|
+
] }),
|
|
1174
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
|
|
1175
|
+
"button",
|
|
1176
|
+
{
|
|
1177
|
+
type: "button",
|
|
1178
|
+
onClick: handleProcessClick,
|
|
1179
|
+
disabled: !selectedFile || isUploading || disabled,
|
|
1180
|
+
style: {
|
|
1181
|
+
padding: "8px 16px",
|
|
1182
|
+
borderRadius: 4,
|
|
1183
|
+
border: "none",
|
|
1184
|
+
backgroundColor: !selectedFile || isUploading || disabled ? "#ccc" : "#007bff",
|
|
1185
|
+
color: "#fff",
|
|
1186
|
+
fontWeight: 600,
|
|
1187
|
+
cursor: !selectedFile || isUploading || disabled ? "not-allowed" : "pointer"
|
|
1188
|
+
},
|
|
1189
|
+
children: isUploading ? "Processing..." : "Process"
|
|
1190
|
+
}
|
|
1191
|
+
)
|
|
1192
|
+
] });
|
|
1193
|
+
};
|
|
1194
|
+
|
|
1006
1195
|
// src/views/HomeView.tsx
|
|
1007
1196
|
var import_authentication_ui = require("@sparkstudio/authentication-ui");
|
|
1008
|
-
var
|
|
1197
|
+
var import_jsx_runtime7 = require("react/jsx-runtime");
|
|
1009
1198
|
function HomeView() {
|
|
1010
|
-
return /* @__PURE__ */ (0,
|
|
1199
|
+
return /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
|
|
1011
1200
|
import_authentication_ui.AuthenticatorProvider,
|
|
1012
1201
|
{
|
|
1013
1202
|
googleClientId: import_authentication_ui.AppSettings.GoogleClientId,
|
|
1014
1203
|
authenticationUrl: import_authentication_ui.AppSettings.AuthenticationUrl,
|
|
1015
1204
|
accountsUrl: import_authentication_ui.AppSettings.AccountsUrl,
|
|
1016
|
-
children: /* @__PURE__ */ (0,
|
|
1205
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(HomeContent, {})
|
|
1017
1206
|
}
|
|
1018
1207
|
);
|
|
1019
1208
|
}
|
|
1020
1209
|
function HomeContent() {
|
|
1021
1210
|
const { user } = (0, import_authentication_ui.useUser)();
|
|
1022
|
-
|
|
1023
|
-
|
|
1024
|
-
|
|
1025
|
-
|
|
1026
|
-
|
|
1027
|
-
|
|
1028
|
-
|
|
1029
|
-
|
|
1030
|
-
|
|
1211
|
+
async function getPresignedUrlFromApi(file) {
|
|
1212
|
+
const res = new SparkStudioStorageSDK(
|
|
1213
|
+
// "https://iq0gmcn0pd.execute-api.us-east-2.amazonaws.com/Prod"
|
|
1214
|
+
"https://localhost:5001"
|
|
1215
|
+
);
|
|
1216
|
+
const contentType = file.type || "application/octet-stream";
|
|
1217
|
+
return (await res.s3.GetTemporaryPreSignedUrl(new TemporaryFileDTO({ Name: file.name, ContentType: contentType })))?.PresignedUrl ?? "";
|
|
1218
|
+
}
|
|
1219
|
+
return /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)(import_jsx_runtime7.Fragment, { children: [
|
|
1220
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)(import_authentication_ui.UserInfoCard, {}),
|
|
1221
|
+
user && /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)(import_jsx_runtime7.Fragment, { children: [
|
|
1222
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
|
|
1223
|
+
SingleFileProcessUploader,
|
|
1224
|
+
{
|
|
1225
|
+
label: "Upload a file to process",
|
|
1226
|
+
accept: "*/*",
|
|
1227
|
+
getPresignedUrl: getPresignedUrlFromApi,
|
|
1228
|
+
onUploadComplete: (file, s3Url) => {
|
|
1229
|
+
console.log("Uploaded:", file.name, "S3 URL:", s3Url);
|
|
1230
|
+
}
|
|
1231
|
+
}
|
|
1232
|
+
),
|
|
1233
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
|
|
1234
|
+
ContainerUploadPanel,
|
|
1235
|
+
{
|
|
1236
|
+
containerApiBaseUrl: "https://lf9zyufpuk.execute-api.us-east-2.amazonaws.com/Prod",
|
|
1237
|
+
storageApiBaseUrl: "https://iq0gmcn0pd.execute-api.us-east-2.amazonaws.com/Prod"
|
|
1238
|
+
}
|
|
1239
|
+
)
|
|
1240
|
+
] })
|
|
1031
1241
|
] });
|
|
1032
1242
|
}
|
|
1033
1243
|
// Annotate the CommonJS export names for ESM import in node:
|
|
@@ -1041,7 +1251,9 @@ function HomeContent() {
|
|
|
1041
1251
|
Home,
|
|
1042
1252
|
HomeView,
|
|
1043
1253
|
S3,
|
|
1254
|
+
SingleFileProcessUploader,
|
|
1044
1255
|
SparkStudioStorageSDK,
|
|
1256
|
+
TemporaryFileDTO,
|
|
1045
1257
|
UploadContainer,
|
|
1046
1258
|
UploadDropzone,
|
|
1047
1259
|
UploadFileToS3,
|
package/dist/index.d.cts
CHANGED
|
@@ -75,6 +75,20 @@ declare class AWSPresignedUrlDTO implements IAWSPresignedUrlDTO {
|
|
|
75
75
|
constructor(init: AWSPresignedUrlDTOInit);
|
|
76
76
|
}
|
|
77
77
|
|
|
78
|
+
/**
|
|
79
|
+
* Represents an Auto-generated model for TemporaryFileDTO.
|
|
80
|
+
*/
|
|
81
|
+
interface ITemporaryFileDTO {
|
|
82
|
+
Name?: string;
|
|
83
|
+
ContentType?: string;
|
|
84
|
+
}
|
|
85
|
+
type TemporaryFileDTOInit = Partial<ITemporaryFileDTO>;
|
|
86
|
+
declare class TemporaryFileDTO implements ITemporaryFileDTO {
|
|
87
|
+
Name?: string;
|
|
88
|
+
ContentType?: string;
|
|
89
|
+
constructor(init: TemporaryFileDTOInit);
|
|
90
|
+
}
|
|
91
|
+
|
|
78
92
|
/**
|
|
79
93
|
* Auto-generated client for the S3 controller.
|
|
80
94
|
*/
|
|
@@ -83,6 +97,7 @@ declare class S3 {
|
|
|
83
97
|
constructor(baseUrl: string);
|
|
84
98
|
DeleteS3(containerDTO: ContainerDTO): Promise<ContainerDTO>;
|
|
85
99
|
GetPreSignedUrl(containerDTO: ContainerDTO): Promise<AWSPresignedUrlDTO>;
|
|
100
|
+
GetTemporaryPreSignedUrl(temporaryFileDTO: TemporaryFileDTO): Promise<AWSPresignedUrlDTO>;
|
|
86
101
|
}
|
|
87
102
|
|
|
88
103
|
/**
|
|
@@ -116,6 +131,24 @@ interface DesktopFileIconProps {
|
|
|
116
131
|
}
|
|
117
132
|
declare const DesktopFileIcon: React__default.FC<DesktopFileIconProps>;
|
|
118
133
|
|
|
134
|
+
interface SingleFileProcessUploaderProps {
|
|
135
|
+
/** Called to get a presigned S3 URL for the selected file. */
|
|
136
|
+
getPresignedUrl: (file: File) => Promise<string>;
|
|
137
|
+
/**
|
|
138
|
+
* Called after the upload succeeds.
|
|
139
|
+
* You can use s3Url (the presigned URL you provided) in another component
|
|
140
|
+
* or have your backend process the file from S3.
|
|
141
|
+
*/
|
|
142
|
+
onUploadComplete?: (file: File, s3Url: string) => void;
|
|
143
|
+
/** Optional: restrict file types, e.g. "image/*" or ".png,.jpg" */
|
|
144
|
+
accept?: string;
|
|
145
|
+
/** Optional: label shown above the control */
|
|
146
|
+
label?: string;
|
|
147
|
+
/** Optional: disable the control entirely */
|
|
148
|
+
disabled?: boolean;
|
|
149
|
+
}
|
|
150
|
+
declare const SingleFileProcessUploader: React__default.FC<SingleFileProcessUploaderProps>;
|
|
151
|
+
|
|
119
152
|
interface UploadContainerProps {
|
|
120
153
|
multiple?: boolean;
|
|
121
154
|
accept?: string;
|
|
@@ -192,4 +225,4 @@ declare function UseUploadManager({ autoUpload, getPresignedUrl, onUploadComplet
|
|
|
192
225
|
|
|
193
226
|
declare function HomeView(): react_jsx_runtime.JSX.Element;
|
|
194
227
|
|
|
195
|
-
export { AWSPresignedUrlDTO, Container, ContainerDTO, ContainerType, ContainerUploadPanel, DesktopFileIcon, type DesktopFileIconProps, Home, HomeView, type IAWSPresignedUrlDTO, type IContainerDTO, S3, SparkStudioStorageSDK, UploadContainer, type UploadContainerProps, UploadDropzone, UploadFileToS3, UploadProgressList, type UploadState, type UploadStatus, UseContainers, UseUploadManager };
|
|
228
|
+
export { AWSPresignedUrlDTO, Container, ContainerDTO, ContainerType, ContainerUploadPanel, DesktopFileIcon, type DesktopFileIconProps, Home, HomeView, type IAWSPresignedUrlDTO, type IContainerDTO, type ITemporaryFileDTO, S3, SingleFileProcessUploader, type SingleFileProcessUploaderProps, SparkStudioStorageSDK, TemporaryFileDTO, UploadContainer, type UploadContainerProps, UploadDropzone, UploadFileToS3, UploadProgressList, type UploadState, type UploadStatus, UseContainers, UseUploadManager };
|
package/dist/index.d.ts
CHANGED
|
@@ -75,6 +75,20 @@ declare class AWSPresignedUrlDTO implements IAWSPresignedUrlDTO {
|
|
|
75
75
|
constructor(init: AWSPresignedUrlDTOInit);
|
|
76
76
|
}
|
|
77
77
|
|
|
78
|
+
/**
|
|
79
|
+
* Represents an Auto-generated model for TemporaryFileDTO.
|
|
80
|
+
*/
|
|
81
|
+
interface ITemporaryFileDTO {
|
|
82
|
+
Name?: string;
|
|
83
|
+
ContentType?: string;
|
|
84
|
+
}
|
|
85
|
+
type TemporaryFileDTOInit = Partial<ITemporaryFileDTO>;
|
|
86
|
+
declare class TemporaryFileDTO implements ITemporaryFileDTO {
|
|
87
|
+
Name?: string;
|
|
88
|
+
ContentType?: string;
|
|
89
|
+
constructor(init: TemporaryFileDTOInit);
|
|
90
|
+
}
|
|
91
|
+
|
|
78
92
|
/**
|
|
79
93
|
* Auto-generated client for the S3 controller.
|
|
80
94
|
*/
|
|
@@ -83,6 +97,7 @@ declare class S3 {
|
|
|
83
97
|
constructor(baseUrl: string);
|
|
84
98
|
DeleteS3(containerDTO: ContainerDTO): Promise<ContainerDTO>;
|
|
85
99
|
GetPreSignedUrl(containerDTO: ContainerDTO): Promise<AWSPresignedUrlDTO>;
|
|
100
|
+
GetTemporaryPreSignedUrl(temporaryFileDTO: TemporaryFileDTO): Promise<AWSPresignedUrlDTO>;
|
|
86
101
|
}
|
|
87
102
|
|
|
88
103
|
/**
|
|
@@ -116,6 +131,24 @@ interface DesktopFileIconProps {
|
|
|
116
131
|
}
|
|
117
132
|
declare const DesktopFileIcon: React__default.FC<DesktopFileIconProps>;
|
|
118
133
|
|
|
134
|
+
interface SingleFileProcessUploaderProps {
|
|
135
|
+
/** Called to get a presigned S3 URL for the selected file. */
|
|
136
|
+
getPresignedUrl: (file: File) => Promise<string>;
|
|
137
|
+
/**
|
|
138
|
+
* Called after the upload succeeds.
|
|
139
|
+
* You can use s3Url (the presigned URL you provided) in another component
|
|
140
|
+
* or have your backend process the file from S3.
|
|
141
|
+
*/
|
|
142
|
+
onUploadComplete?: (file: File, s3Url: string) => void;
|
|
143
|
+
/** Optional: restrict file types, e.g. "image/*" or ".png,.jpg" */
|
|
144
|
+
accept?: string;
|
|
145
|
+
/** Optional: label shown above the control */
|
|
146
|
+
label?: string;
|
|
147
|
+
/** Optional: disable the control entirely */
|
|
148
|
+
disabled?: boolean;
|
|
149
|
+
}
|
|
150
|
+
declare const SingleFileProcessUploader: React__default.FC<SingleFileProcessUploaderProps>;
|
|
151
|
+
|
|
119
152
|
interface UploadContainerProps {
|
|
120
153
|
multiple?: boolean;
|
|
121
154
|
accept?: string;
|
|
@@ -192,4 +225,4 @@ declare function UseUploadManager({ autoUpload, getPresignedUrl, onUploadComplet
|
|
|
192
225
|
|
|
193
226
|
declare function HomeView(): react_jsx_runtime.JSX.Element;
|
|
194
227
|
|
|
195
|
-
export { AWSPresignedUrlDTO, Container, ContainerDTO, ContainerType, ContainerUploadPanel, DesktopFileIcon, type DesktopFileIconProps, Home, HomeView, type IAWSPresignedUrlDTO, type IContainerDTO, S3, SparkStudioStorageSDK, UploadContainer, type UploadContainerProps, UploadDropzone, UploadFileToS3, UploadProgressList, type UploadState, type UploadStatus, UseContainers, UseUploadManager };
|
|
228
|
+
export { AWSPresignedUrlDTO, Container, ContainerDTO, ContainerType, ContainerUploadPanel, DesktopFileIcon, type DesktopFileIconProps, Home, HomeView, type IAWSPresignedUrlDTO, type IContainerDTO, type ITemporaryFileDTO, S3, SingleFileProcessUploader, type SingleFileProcessUploaderProps, SparkStudioStorageSDK, TemporaryFileDTO, UploadContainer, type UploadContainerProps, UploadDropzone, UploadFileToS3, UploadProgressList, type UploadState, type UploadStatus, UseContainers, UseUploadManager };
|
package/dist/index.js
CHANGED
|
@@ -150,6 +150,21 @@ var S3 = class {
|
|
|
150
150
|
if (!response.ok) throw new Error(await response.text());
|
|
151
151
|
return await response.json();
|
|
152
152
|
}
|
|
153
|
+
async GetTemporaryPreSignedUrl(temporaryFileDTO) {
|
|
154
|
+
const url = `${this.baseUrl}/api/S3/GetTemporaryPreSignedUrl`;
|
|
155
|
+
const token = localStorage.getItem("auth_token");
|
|
156
|
+
const requestOptions = {
|
|
157
|
+
method: "POST",
|
|
158
|
+
headers: {
|
|
159
|
+
"Content-Type": "application/json",
|
|
160
|
+
...token && { Authorization: `Bearer ${token}` }
|
|
161
|
+
},
|
|
162
|
+
body: JSON.stringify(temporaryFileDTO)
|
|
163
|
+
};
|
|
164
|
+
const response = await fetch(url, requestOptions);
|
|
165
|
+
if (!response.ok) throw new Error(await response.text());
|
|
166
|
+
return await response.json();
|
|
167
|
+
}
|
|
153
168
|
};
|
|
154
169
|
|
|
155
170
|
// src/api/SparkStudioStorageSDK.ts
|
|
@@ -200,6 +215,16 @@ var ContainerDTO = class {
|
|
|
200
215
|
}
|
|
201
216
|
};
|
|
202
217
|
|
|
218
|
+
// src/api/DTOs/TemporaryFileDTO.ts
|
|
219
|
+
var TemporaryFileDTO = class {
|
|
220
|
+
Name;
|
|
221
|
+
ContentType;
|
|
222
|
+
constructor(init) {
|
|
223
|
+
this.Name = init.Name;
|
|
224
|
+
this.ContentType = init.ContentType;
|
|
225
|
+
}
|
|
226
|
+
};
|
|
227
|
+
|
|
203
228
|
// src/api/Enums/ContainerType.ts
|
|
204
229
|
var ContainerType = /* @__PURE__ */ ((ContainerType2) => {
|
|
205
230
|
ContainerType2[ContainerType2["File"] = 0] = "File";
|
|
@@ -972,6 +997,168 @@ var ContainerUploadPanel = ({
|
|
|
972
997
|
);
|
|
973
998
|
};
|
|
974
999
|
|
|
1000
|
+
// src/components/SingleFileProcessUploader.tsx
|
|
1001
|
+
import { useCallback as useCallback2, useRef as useRef2, useState as useState5 } from "react";
|
|
1002
|
+
import { jsx as jsx6, jsxs as jsxs4 } from "react/jsx-runtime";
|
|
1003
|
+
var SingleFileProcessUploader = ({ getPresignedUrl, onUploadComplete, accept, label, disabled }) => {
|
|
1004
|
+
const [selectedFile, setSelectedFile] = useState5(null);
|
|
1005
|
+
const [isDragging, setIsDragging] = useState5(false);
|
|
1006
|
+
const [progress, setProgress] = useState5(null);
|
|
1007
|
+
const [status, setStatus] = useState5("idle");
|
|
1008
|
+
const [errorMessage, setErrorMessage] = useState5(null);
|
|
1009
|
+
const fileInputRef = useRef2(null);
|
|
1010
|
+
const handleFilesSelected = useCallback2((files) => {
|
|
1011
|
+
if (!files || files.length === 0) return;
|
|
1012
|
+
const file = files[0];
|
|
1013
|
+
setSelectedFile(file);
|
|
1014
|
+
setStatus("idle");
|
|
1015
|
+
setProgress(null);
|
|
1016
|
+
setErrorMessage(null);
|
|
1017
|
+
}, []);
|
|
1018
|
+
const handleBrowseClick = () => {
|
|
1019
|
+
if (disabled) return;
|
|
1020
|
+
fileInputRef.current?.click();
|
|
1021
|
+
};
|
|
1022
|
+
const handleInputChange = (e) => {
|
|
1023
|
+
handleFilesSelected(e.target.files);
|
|
1024
|
+
e.target.value = "";
|
|
1025
|
+
};
|
|
1026
|
+
const handleDragOver = (e) => {
|
|
1027
|
+
e.preventDefault();
|
|
1028
|
+
if (disabled) return;
|
|
1029
|
+
setIsDragging(true);
|
|
1030
|
+
};
|
|
1031
|
+
const handleDragLeave = (e) => {
|
|
1032
|
+
e.preventDefault();
|
|
1033
|
+
setIsDragging(false);
|
|
1034
|
+
};
|
|
1035
|
+
const handleDrop = (e) => {
|
|
1036
|
+
e.preventDefault();
|
|
1037
|
+
if (disabled) return;
|
|
1038
|
+
setIsDragging(false);
|
|
1039
|
+
const files = e.dataTransfer.files;
|
|
1040
|
+
handleFilesSelected(files);
|
|
1041
|
+
};
|
|
1042
|
+
const handleProcessClick = async () => {
|
|
1043
|
+
if (!selectedFile || disabled) return;
|
|
1044
|
+
try {
|
|
1045
|
+
setStatus("uploading");
|
|
1046
|
+
setProgress(0);
|
|
1047
|
+
setErrorMessage(null);
|
|
1048
|
+
const presignedUrl = await getPresignedUrl(selectedFile);
|
|
1049
|
+
await UploadFileToS3(selectedFile, presignedUrl, (p) => setProgress(p));
|
|
1050
|
+
setStatus("success");
|
|
1051
|
+
onUploadComplete?.(selectedFile, presignedUrl);
|
|
1052
|
+
} catch (err) {
|
|
1053
|
+
const message = getErrorMessage(err);
|
|
1054
|
+
console.error("Upload failed:", message);
|
|
1055
|
+
setStatus("error");
|
|
1056
|
+
setErrorMessage(message);
|
|
1057
|
+
}
|
|
1058
|
+
};
|
|
1059
|
+
function getErrorMessage(err) {
|
|
1060
|
+
if (err instanceof Error) return err.message;
|
|
1061
|
+
if (typeof err === "string") return err;
|
|
1062
|
+
return "Unknown error during upload.";
|
|
1063
|
+
}
|
|
1064
|
+
const isUploading = status === "uploading";
|
|
1065
|
+
return /* @__PURE__ */ jsxs4("div", { style: { display: "flex", flexDirection: "column", gap: 8 }, children: [
|
|
1066
|
+
label && /* @__PURE__ */ jsx6("label", { style: { fontWeight: 600 }, children: label }),
|
|
1067
|
+
/* @__PURE__ */ jsxs4(
|
|
1068
|
+
"div",
|
|
1069
|
+
{
|
|
1070
|
+
onDragOver: handleDragOver,
|
|
1071
|
+
onDragLeave: handleDragLeave,
|
|
1072
|
+
onDrop: handleDrop,
|
|
1073
|
+
onClick: handleBrowseClick,
|
|
1074
|
+
style: {
|
|
1075
|
+
border: "2px dashed #ccc",
|
|
1076
|
+
borderRadius: 8,
|
|
1077
|
+
padding: 16,
|
|
1078
|
+
textAlign: "center",
|
|
1079
|
+
cursor: disabled ? "not-allowed" : "pointer",
|
|
1080
|
+
backgroundColor: isDragging ? "#f0f8ff" : "#fafafa"
|
|
1081
|
+
},
|
|
1082
|
+
children: [
|
|
1083
|
+
/* @__PURE__ */ jsx6(
|
|
1084
|
+
"input",
|
|
1085
|
+
{
|
|
1086
|
+
ref: fileInputRef,
|
|
1087
|
+
type: "file",
|
|
1088
|
+
accept,
|
|
1089
|
+
style: { display: "none" },
|
|
1090
|
+
onChange: handleInputChange,
|
|
1091
|
+
disabled
|
|
1092
|
+
}
|
|
1093
|
+
),
|
|
1094
|
+
selectedFile ? /* @__PURE__ */ jsxs4("div", { children: [
|
|
1095
|
+
/* @__PURE__ */ jsxs4("div", { children: [
|
|
1096
|
+
/* @__PURE__ */ jsx6("strong", { children: "Selected file:" }),
|
|
1097
|
+
" ",
|
|
1098
|
+
selectedFile.name
|
|
1099
|
+
] }),
|
|
1100
|
+
/* @__PURE__ */ jsx6("div", { style: { fontSize: 12, color: "#666" }, children: "Click here to change file or drag a new one." })
|
|
1101
|
+
] }) : /* @__PURE__ */ jsxs4("div", { children: [
|
|
1102
|
+
/* @__PURE__ */ jsx6("div", { children: "Drag & drop a file here" }),
|
|
1103
|
+
/* @__PURE__ */ jsx6("div", { style: { fontSize: 12, color: "#666" }, children: "or click to browse" })
|
|
1104
|
+
] })
|
|
1105
|
+
]
|
|
1106
|
+
}
|
|
1107
|
+
),
|
|
1108
|
+
isUploading && /* @__PURE__ */ jsxs4("div", { style: { fontSize: 12 }, children: [
|
|
1109
|
+
"Uploading... ",
|
|
1110
|
+
progress ?? 0,
|
|
1111
|
+
"%",
|
|
1112
|
+
/* @__PURE__ */ jsx6(
|
|
1113
|
+
"div",
|
|
1114
|
+
{
|
|
1115
|
+
style: {
|
|
1116
|
+
marginTop: 4,
|
|
1117
|
+
height: 6,
|
|
1118
|
+
borderRadius: 999,
|
|
1119
|
+
backgroundColor: "#eee",
|
|
1120
|
+
overflow: "hidden"
|
|
1121
|
+
},
|
|
1122
|
+
children: /* @__PURE__ */ jsx6(
|
|
1123
|
+
"div",
|
|
1124
|
+
{
|
|
1125
|
+
style: {
|
|
1126
|
+
height: "100%",
|
|
1127
|
+
width: `${progress ?? 0}%`,
|
|
1128
|
+
backgroundColor: "#007bff",
|
|
1129
|
+
transition: "width 0.2s ease-out"
|
|
1130
|
+
}
|
|
1131
|
+
}
|
|
1132
|
+
)
|
|
1133
|
+
}
|
|
1134
|
+
)
|
|
1135
|
+
] }),
|
|
1136
|
+
status === "success" && /* @__PURE__ */ jsx6("div", { style: { fontSize: 12, color: "green" }, children: "Upload complete \u2705" }),
|
|
1137
|
+
status === "error" && /* @__PURE__ */ jsxs4("div", { style: { fontSize: 12, color: "red" }, children: [
|
|
1138
|
+
"Upload failed: ",
|
|
1139
|
+
errorMessage
|
|
1140
|
+
] }),
|
|
1141
|
+
/* @__PURE__ */ jsx6(
|
|
1142
|
+
"button",
|
|
1143
|
+
{
|
|
1144
|
+
type: "button",
|
|
1145
|
+
onClick: handleProcessClick,
|
|
1146
|
+
disabled: !selectedFile || isUploading || disabled,
|
|
1147
|
+
style: {
|
|
1148
|
+
padding: "8px 16px",
|
|
1149
|
+
borderRadius: 4,
|
|
1150
|
+
border: "none",
|
|
1151
|
+
backgroundColor: !selectedFile || isUploading || disabled ? "#ccc" : "#007bff",
|
|
1152
|
+
color: "#fff",
|
|
1153
|
+
fontWeight: 600,
|
|
1154
|
+
cursor: !selectedFile || isUploading || disabled ? "not-allowed" : "pointer"
|
|
1155
|
+
},
|
|
1156
|
+
children: isUploading ? "Processing..." : "Process"
|
|
1157
|
+
}
|
|
1158
|
+
)
|
|
1159
|
+
] });
|
|
1160
|
+
};
|
|
1161
|
+
|
|
975
1162
|
// src/views/HomeView.tsx
|
|
976
1163
|
import {
|
|
977
1164
|
AppSettings,
|
|
@@ -979,29 +1166,50 @@ import {
|
|
|
979
1166
|
UserInfoCard,
|
|
980
1167
|
useUser
|
|
981
1168
|
} from "@sparkstudio/authentication-ui";
|
|
982
|
-
import { Fragment as Fragment2, jsx as
|
|
1169
|
+
import { Fragment as Fragment2, jsx as jsx7, jsxs as jsxs5 } from "react/jsx-runtime";
|
|
983
1170
|
function HomeView() {
|
|
984
|
-
return /* @__PURE__ */
|
|
1171
|
+
return /* @__PURE__ */ jsx7(
|
|
985
1172
|
AuthenticatorProvider,
|
|
986
1173
|
{
|
|
987
1174
|
googleClientId: AppSettings.GoogleClientId,
|
|
988
1175
|
authenticationUrl: AppSettings.AuthenticationUrl,
|
|
989
1176
|
accountsUrl: AppSettings.AccountsUrl,
|
|
990
|
-
children: /* @__PURE__ */
|
|
1177
|
+
children: /* @__PURE__ */ jsx7(HomeContent, {})
|
|
991
1178
|
}
|
|
992
1179
|
);
|
|
993
1180
|
}
|
|
994
1181
|
function HomeContent() {
|
|
995
1182
|
const { user } = useUser();
|
|
996
|
-
|
|
997
|
-
|
|
998
|
-
|
|
999
|
-
|
|
1000
|
-
|
|
1001
|
-
|
|
1002
|
-
|
|
1003
|
-
|
|
1004
|
-
|
|
1183
|
+
async function getPresignedUrlFromApi(file) {
|
|
1184
|
+
const res = new SparkStudioStorageSDK(
|
|
1185
|
+
// "https://iq0gmcn0pd.execute-api.us-east-2.amazonaws.com/Prod"
|
|
1186
|
+
"https://localhost:5001"
|
|
1187
|
+
);
|
|
1188
|
+
const contentType = file.type || "application/octet-stream";
|
|
1189
|
+
return (await res.s3.GetTemporaryPreSignedUrl(new TemporaryFileDTO({ Name: file.name, ContentType: contentType })))?.PresignedUrl ?? "";
|
|
1190
|
+
}
|
|
1191
|
+
return /* @__PURE__ */ jsxs5(Fragment2, { children: [
|
|
1192
|
+
/* @__PURE__ */ jsx7(UserInfoCard, {}),
|
|
1193
|
+
user && /* @__PURE__ */ jsxs5(Fragment2, { children: [
|
|
1194
|
+
/* @__PURE__ */ jsx7(
|
|
1195
|
+
SingleFileProcessUploader,
|
|
1196
|
+
{
|
|
1197
|
+
label: "Upload a file to process",
|
|
1198
|
+
accept: "*/*",
|
|
1199
|
+
getPresignedUrl: getPresignedUrlFromApi,
|
|
1200
|
+
onUploadComplete: (file, s3Url) => {
|
|
1201
|
+
console.log("Uploaded:", file.name, "S3 URL:", s3Url);
|
|
1202
|
+
}
|
|
1203
|
+
}
|
|
1204
|
+
),
|
|
1205
|
+
/* @__PURE__ */ jsx7(
|
|
1206
|
+
ContainerUploadPanel,
|
|
1207
|
+
{
|
|
1208
|
+
containerApiBaseUrl: "https://lf9zyufpuk.execute-api.us-east-2.amazonaws.com/Prod",
|
|
1209
|
+
storageApiBaseUrl: "https://iq0gmcn0pd.execute-api.us-east-2.amazonaws.com/Prod"
|
|
1210
|
+
}
|
|
1211
|
+
)
|
|
1212
|
+
] })
|
|
1005
1213
|
] });
|
|
1006
1214
|
}
|
|
1007
1215
|
export {
|
|
@@ -1014,7 +1222,9 @@ export {
|
|
|
1014
1222
|
Home,
|
|
1015
1223
|
HomeView,
|
|
1016
1224
|
S3,
|
|
1225
|
+
SingleFileProcessUploader,
|
|
1017
1226
|
SparkStudioStorageSDK,
|
|
1227
|
+
TemporaryFileDTO,
|
|
1018
1228
|
UploadContainer,
|
|
1019
1229
|
UploadDropzone,
|
|
1020
1230
|
UploadFileToS3,
|