Skip to content

Commit

Permalink
feat: Support previewing helicorder in frontend
Browse files Browse the repository at this point in the history
  • Loading branch information
bclswl0827 committed Oct 12, 2024
1 parent d8da3dd commit 4b100cd
Show file tree
Hide file tree
Showing 9 changed files with 103 additions and 5 deletions.
16 changes: 16 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,22 @@

Starting from v2.2.5, all notable changes to this project will be documented in this file.

## v3.4.1

### New Features

- Support previewing helicorder images in frontend.
- Added earthquake event source API of KNDC.

### Bug Fixes

- Fixed channel names in inventory response.

### Refactor

- Cache parsed results instead of crawler response.
- Return nil directly for API endpoints if miniSEED or helicorder service is disabled.

## v3.4.0

### New Features
Expand Down
2 changes: 1 addition & 1 deletion VERSION
Original file line number Diff line number Diff line change
@@ -1 +1 @@
v3.4.0
v3.4.1
6 changes: 6 additions & 0 deletions frontend/src/package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions frontend/src/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
"dependencies": {
"@emotion/react": "^11.11.4",
"@emotion/styled": "^11.11.0",
"@fancyapps/ui": "^5.0.36",
"@mdi/js": "^7.4.47",
"@mdi/react": "^1.6.1",
"@mui/material": "^5.14.14",
Expand Down
9 changes: 6 additions & 3 deletions frontend/src/src/helpers/request/requestRestApi.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,8 @@ interface Options<APIRequest, APICommonResponse, APIErrorResponse> {
readonly abortController?: AbortController;
readonly endpoint: Endpoint<APIRequest, APICommonResponse, APIErrorResponse>;
readonly blobOptions?: {
readonly fileName: string;
readonly fileName?: string;
readonly onComplete?: (response: Blob) => void;
readonly onDownload?: (progressEvent: AxiosProgressEvent) => void;
};
}
Expand Down Expand Up @@ -87,7 +88,7 @@ export const requestRestApi = async <APIRequest, APICommonResponse, APIErrorResp
responseType: blobOptions ? "blob" : "json",
data: endpoint.method === "post" ? payload : {}
});
if (blobOptions) {
if (blobOptions?.fileName) {
const { "content-disposition": contentDisposition } = headers;
let fileName = blobOptions.fileName;
if (contentDisposition) {
Expand All @@ -97,8 +98,10 @@ export const requestRestApi = async <APIRequest, APICommonResponse, APIErrorResp
?.split("=")[1];
}

saveAs(data, !fileName.length ? "stream" : fileName);
saveAs(data, fileName);
return response.common;
} else if (blobOptions?.onComplete) {
blobOptions.onComplete(data);
}

return { ...response.common, ...data };
Expand Down
4 changes: 4 additions & 0 deletions frontend/src/src/locales/en-US.json
Original file line number Diff line number Diff line change
Expand Up @@ -304,6 +304,7 @@
"actions": "Actions"
},
"actions": {
"preview": "Preview",
"export": "Export",
"download": "Download"
}
Expand All @@ -317,6 +318,9 @@
"search_filter_reset": "Filter reset successfully",
"is_exporting_mseed": "Exporting MiniSEED file, this may take a while",
"export_mseed_success": "MiniSEED file exported successfully",
"is_previewing_helicorder": "Loading helicorder preview, please wait...",
"preview_helicorder_success": "Helicorder preview loaded successfully",
"preview_helicorder_error": "Failed to load helicorder preview",
"is_downloading_helicorder": "Downloading Helicorder scroll file, this may take a while",
"download_helicorder_success": "Helicorder scroll file downloaded successfully",
"download_helicorder_error": "Failed to download Helicorder scroll file"
Expand Down
4 changes: 4 additions & 0 deletions frontend/src/src/locales/zh-CN.json
Original file line number Diff line number Diff line change
Expand Up @@ -304,6 +304,7 @@
"actions": "操作"
},
"actions": {
"preview": "预览",
"export": "导出",
"download": "下载"
}
Expand All @@ -317,6 +318,9 @@
"search_filter_reset": "已重置筛选器",
"is_exporting_mseed": "正在导出 MiniSEED 格式文件,这可能需要一些时间",
"export_mseed_success": "MiniSEED 格式文件导出成功",
"is_previewing_helicorder": "正在加载预览图片,请稍等...",
"preview_helicorder_success": "预览图片加载成功",
"preview_helicorder_error": "预览图片加载失败",
"is_downloading_helicorder": "正在下载 Helicorder 滚筒文件,这可能需要一些时间",
"download_helicorder_success": "Helicorder 滚筒文件下载成功",
"download_helicorder_error": "Helicorder 滚筒文件下载失败"
Expand Down
4 changes: 4 additions & 0 deletions frontend/src/src/locales/zh-TW.json
Original file line number Diff line number Diff line change
Expand Up @@ -305,6 +305,7 @@
},
"actions": {
"export": "匯出",
"preview": "預覽",
"download": "下載"
}
},
Expand All @@ -317,6 +318,9 @@
"search_filter_reset": "已重設篩選條件",
"is_exporting_mseed": "正在匯出 MiniSEED 格式檔案,這可能需要一些時間",
"export_mseed_success": "MiniSEED 格式檔案匯出成功",
"is_previewing_helicorder": "正在加載預覽圖像,請稍候...",
"preview_helicorder_success": "預覽圖像加載成功",
"preview_helicorder_error": "預覽圖像加載失敗",
"is_downloading_helicorder": "正在下載 Helicorder 捲筒檔案,這可能需要一些時間",
"download_helicorder_success": "Helicorder 捲筒檔案下載成功",
"download_helicorder_error": "Helicorder 捲筒檔案下載失敗"
Expand Down
62 changes: 61 additions & 1 deletion frontend/src/src/views/Export/index.tsx
Original file line number Diff line number Diff line change
@@ -1,3 +1,6 @@
import "@fancyapps/ui/dist/fancybox/fancybox.css";

import { Fancybox } from "@fancyapps/ui";
import { mdiMagnify } from "@mdi/js";
import { Icon } from "@mdi/react";
import { GridValidRowModel } from "@mui/x-data-grid";
Expand Down Expand Up @@ -26,6 +29,7 @@ const Export = ({ locale }: RouterComponentProps) => {
const { endpoints, backend } = apiConfig;
const miniSeedRes = await requestRestApi({
backend,
throwError: true,
endpoint: endpoints.miniseed,
payload: { action: "list", name: "" }
});
Expand Down Expand Up @@ -63,6 +67,7 @@ const Export = ({ locale }: RouterComponentProps) => {
const { endpoints, backend } = apiConfig;
const heliCorderRes = await requestRestApi({
backend,
throwError: true,
endpoint: endpoints.helicorder,
payload: { action: "list", name: "" }
});
Expand Down Expand Up @@ -186,6 +191,43 @@ const Export = ({ locale }: RouterComponentProps) => {
forceUpdateComponent();
};

// Handler for previewing helicorder
const handlePreviewHeliCorder = async (fileName: string) => {
const { backend, endpoints } = apiConfig;
await sendPromiseAlert(
requestRestApi<
typeof endpoints.helicorder.model.request,
typeof endpoints.helicorder.model.response.common,
typeof endpoints.helicorder.model.response.error
>({
throwError: true,
payload: { action: "export", name: fileName },
endpoint: endpoints.helicorder,
timeout: 3600,
backend,
blobOptions: {
onComplete: async (response) => {
const imageData = await response.text();
const blob = new Blob([imageData], { type: "image/svg+xml" });
const blobUrl = URL.createObjectURL(blob);
Fancybox.show([{ src: blobUrl, type: "image" }], {
on: { close: () => URL.revokeObjectURL(blobUrl) }
});
}
}
}),
t("views.export.toasts.is_previewing_helicorder"),
t("views.export.toasts.preview_helicorder_success"),
t("views.export.toasts.preview_helicorder_error")
);
};
useEffect(
() => () => {
Fancybox.destroy();
},
[]
);

// Handler for downloading helicorder
const handleDownloadHeliCorder = async (fileName: string) => {
const { backend, endpoints } = apiConfig;
Expand All @@ -195,6 +237,7 @@ const Export = ({ locale }: RouterComponentProps) => {
typeof endpoints.helicorder.model.response.common,
typeof endpoints.helicorder.model.response.error
>({
throwError: true,
blobOptions: { fileName },
payload: { action: "export", name: fileName },
endpoint: endpoints.helicorder,
Expand Down Expand Up @@ -421,7 +464,16 @@ const Export = ({ locale }: RouterComponentProps) => {
headerName: t("views.export.table.columns.ttl"),
hideable: true,
sortable: false,
minWidth: 200
minWidth: 200,
renderCell: ({ value }) => {
if (value === -1) {
return "∞";
}
if (value < 0) {
return "0";
}
return String(value);
}
},
{
field: "actions",
Expand All @@ -431,6 +483,14 @@ const Export = ({ locale }: RouterComponentProps) => {
minWidth: 150,
renderCell: ({ row }) => (
<div className="flex flex-row space-x-4 w-full">
<button
className="text-blue-700 dark:text-blue-400 hover:opacity-50"
onClick={() => {
handlePreviewHeliCorder(row.name);
}}
>
{t("views.export.table.actions.preview")}
</button>
<button
className="text-blue-700 dark:text-blue-400 hover:opacity-50"
onClick={() => {
Expand Down

0 comments on commit 4b100cd

Please sign in to comment.