UI Refactor.
This commit is contained in:
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -1,6 +1,6 @@
|
||||
appId: com.imex.esdp
|
||||
copyright: ImEX Systems Inc.
|
||||
productName: EMS Uploader
|
||||
productName: EMS Data Pump
|
||||
generateUpdatesFilesForAllChannels: true
|
||||
|
||||
directories:
|
||||
@@ -17,7 +17,7 @@ files:
|
||||
asarUnpack:
|
||||
- resources/**
|
||||
win:
|
||||
executableName: EMSUploader
|
||||
executableName: EMSDP
|
||||
icon: resources/icon.png
|
||||
azureSignOptions:
|
||||
endpoint: https://eus.codesigning.azure.net
|
||||
|
||||
Binary file not shown.
|
Before Width: | Height: | Size: 320 KiB After Width: | Height: | Size: 190 KiB |
@@ -1,5 +1,5 @@
|
||||
import "@ant-design/v5-patch-for-react-19";
|
||||
import { Badge, ConfigProvider, Layout, Skeleton } from "antd";
|
||||
import { ConfigProvider, Layout, Space } from "antd";
|
||||
import { FC } from "react";
|
||||
import { ErrorBoundary } from "react-error-boundary";
|
||||
import { Provider } from "react-redux";
|
||||
@@ -11,17 +11,15 @@ import reduxStore from "./redux/redux-store";
|
||||
import { NotificationProvider } from "./util/notificationContext";
|
||||
|
||||
const App: FC = () => {
|
||||
const isTest = window.api.isTest();
|
||||
|
||||
return (
|
||||
<ConfigProvider
|
||||
theme={{
|
||||
token: {},
|
||||
token: {
|
||||
borderRadius: 8,
|
||||
},
|
||||
components: {
|
||||
Card: {
|
||||
borderRadius: 8,
|
||||
colorBgBase: "#ffaacc",
|
||||
boxShadow: "0 4px 12px rgba(0, 0, 0, 0.15)",
|
||||
boxShadow: "0 2px 8px rgba(0, 0, 0, 0.1)",
|
||||
},
|
||||
},
|
||||
}}
|
||||
@@ -30,21 +28,14 @@ const App: FC = () => {
|
||||
<HashRouter>
|
||||
<ErrorBoundary FallbackComponent={ErrorBoundaryFallback}>
|
||||
<NotificationProvider>
|
||||
<Skeleton loading={false} active>
|
||||
<Layout style={{ minHeight: "100vh" }}>
|
||||
<Badge.Ribbon
|
||||
text={isTest && "Connected to Test"}
|
||||
color={isTest ? "red" : undefined}
|
||||
>
|
||||
<Layout.Content style={{ padding: "0 24px" }}>
|
||||
<UpdateAvailable />
|
||||
<Routes>
|
||||
<Route path="/" element={<Settings />} />
|
||||
</Routes>
|
||||
</Layout.Content>
|
||||
</Badge.Ribbon>
|
||||
</Layout>
|
||||
</Skeleton>
|
||||
<Layout style={{ minHeight: "100vh", background: "#f0f2f5" }}>
|
||||
<Layout.Content style={{ padding: "24px" }}>
|
||||
<UpdateAvailable />
|
||||
<Routes>
|
||||
<Route path="/" element={<Settings />} />
|
||||
</Routes>
|
||||
</Layout.Content>
|
||||
</Layout>
|
||||
</NotificationProvider>
|
||||
</ErrorBoundary>
|
||||
</HashRouter>
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { Card, Form, Input } from "antd";
|
||||
import { Card, Form, Input, Space } from "antd";
|
||||
import { FC, useEffect } from "react";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import ipcTypes from "../../../../util/ipcTypes.json";
|
||||
@@ -11,9 +11,11 @@ const SettingsConfig: FC = () => {
|
||||
{
|
||||
name: "esApiKey",
|
||||
label: t("settings.labels.esApiKey"),
|
||||
component: Input,
|
||||
component: Input.Password,
|
||||
hasFeedback: true,
|
||||
componentProps: {},
|
||||
componentProps: {
|
||||
placeholder: "Enter your API key",
|
||||
},
|
||||
},
|
||||
];
|
||||
|
||||
@@ -52,24 +54,30 @@ const SettingsConfig: FC = () => {
|
||||
|
||||
return (
|
||||
<Card title={t("settings.labels.config")}>
|
||||
<Form form={form} onFieldsChange={handleFieldChange} layout="vertical">
|
||||
{settingFields.map((field) => (
|
||||
<Form.Item
|
||||
key={field.name}
|
||||
label={t(`settings.labels.${field.name}`, field.label)}
|
||||
name={field.name}
|
||||
hasFeedback={field.hasFeedback}
|
||||
validateStatus="validating"
|
||||
rules={[
|
||||
{
|
||||
required: true,
|
||||
message: t(`settings.validation.${field.name}Required`),
|
||||
},
|
||||
]}
|
||||
>
|
||||
<field.component {...field.componentProps} />
|
||||
</Form.Item>
|
||||
))}
|
||||
<Form
|
||||
form={form}
|
||||
onFieldsChange={handleFieldChange}
|
||||
layout="vertical"
|
||||
size="large"
|
||||
>
|
||||
<Space direction="vertical" size="middle" style={{ width: "100%" }}>
|
||||
{settingFields.map((field) => (
|
||||
<Form.Item
|
||||
key={field.name}
|
||||
label={t(`settings.labels.${field.name}`, field.label)}
|
||||
name={field.name}
|
||||
hasFeedback={field.hasFeedback}
|
||||
rules={[
|
||||
{
|
||||
required: true,
|
||||
message: t(`settings.validation.${field.name}Required`),
|
||||
},
|
||||
]}
|
||||
>
|
||||
<field.component {...field.componentProps} />
|
||||
</Form.Item>
|
||||
))}
|
||||
</Space>
|
||||
</Form>
|
||||
</Card>
|
||||
);
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { DeleteFilled, FileAddFilled } from "@ant-design/icons";
|
||||
import { Button, Card, Space, Timeline } from "antd";
|
||||
import { DeleteOutlined, FolderAddOutlined } from "@ant-design/icons";
|
||||
import { Button, Card, Empty, List, Space, Typography } from "antd";
|
||||
import { useEffect, useState, FC } from "react";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import ipcTypes from "../../../../util/ipcTypes.json";
|
||||
@@ -33,32 +33,46 @@ const SettingsWatchedPaths: FC = () => {
|
||||
};
|
||||
|
||||
return (
|
||||
<Card
|
||||
title={t("settings.labels.watchedpaths")}
|
||||
extra={
|
||||
<Button onClick={handleAddPath} icon={<FileAddFilled />}>
|
||||
{t("settings.actions.addpath")}
|
||||
</Button>
|
||||
}
|
||||
>
|
||||
<Timeline
|
||||
items={watchedPaths.map((path, index) => ({
|
||||
key: index,
|
||||
children: (
|
||||
<Space align="baseline">
|
||||
{path}
|
||||
<>
|
||||
<List
|
||||
locale={{
|
||||
emptyText: (
|
||||
<Empty
|
||||
description={"No watched paths configured"}
|
||||
image={Empty.PRESENTED_IMAGE_SIMPLE}
|
||||
/>
|
||||
),
|
||||
}}
|
||||
dataSource={watchedPaths}
|
||||
renderItem={(path) => (
|
||||
<List.Item
|
||||
actions={[
|
||||
<Button
|
||||
size="small"
|
||||
key="delete"
|
||||
danger
|
||||
type="text"
|
||||
icon={<DeleteFilled />}
|
||||
icon={<DeleteOutlined />}
|
||||
onClick={() => handleRemovePath(path)}
|
||||
/>
|
||||
</Space>
|
||||
),
|
||||
}))}
|
||||
>
|
||||
Remove
|
||||
</Button>,
|
||||
]}
|
||||
>
|
||||
<Typography.Text code copyable>
|
||||
{path}
|
||||
</Typography.Text>
|
||||
</List.Item>
|
||||
)}
|
||||
/>
|
||||
</Card>
|
||||
<Button
|
||||
type="dashed"
|
||||
style={{ width: "100%", marginTop: 16 }}
|
||||
onClick={handleAddPath}
|
||||
icon={<FolderAddOutlined />}
|
||||
>
|
||||
{t("settings.actions.addpath")}
|
||||
</Button>
|
||||
</>
|
||||
);
|
||||
};
|
||||
export default SettingsWatchedPaths;
|
||||
|
||||
@@ -14,20 +14,19 @@ import {
|
||||
Badge,
|
||||
Button,
|
||||
Card,
|
||||
Col,
|
||||
Divider,
|
||||
Flex,
|
||||
InputNumber,
|
||||
Row,
|
||||
Radio,
|
||||
RadioChangeEvent,
|
||||
Space,
|
||||
Switch,
|
||||
Typography,
|
||||
} from "antd";
|
||||
import { FC, useEffect, useState } from "react";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import ipcTypes from "../../../../util/ipcTypes.json";
|
||||
|
||||
const colSpans = {
|
||||
md: 12,
|
||||
sm: 24,
|
||||
};
|
||||
import SettingsWatchedPaths from "./Settings.WatchedPaths";
|
||||
|
||||
const SettingsWatcher: FC = () => {
|
||||
const { t } = useTranslation();
|
||||
@@ -63,10 +62,10 @@ const SettingsWatcher: FC = () => {
|
||||
window.electron.ipcRenderer.send(ipcTypes.toMain.watcher.stop);
|
||||
};
|
||||
|
||||
const toggleWatcherMode = (checked: boolean): void => {
|
||||
const toggleWatcherMode = (e: RadioChangeEvent): void => {
|
||||
window.electron.ipcRenderer
|
||||
.invoke(ipcTypes.toMain.settings.watcher.setpolling, {
|
||||
enabled: !checked,
|
||||
enabled: !e.target.value,
|
||||
interval: pollingState.interval,
|
||||
})
|
||||
.then((storePollingState: { enabled: boolean; interval: number }) => {
|
||||
@@ -89,69 +88,70 @@ const SettingsWatcher: FC = () => {
|
||||
};
|
||||
|
||||
return (
|
||||
<Badge.Ribbon
|
||||
text={
|
||||
<Card
|
||||
title={t("settings.labels.watcherstatus")}
|
||||
extra={
|
||||
isWatcherStarted ? (
|
||||
<Space>
|
||||
<CheckCircleFilled />
|
||||
{t("settings.labels.started")}
|
||||
</Space>
|
||||
<Button
|
||||
danger
|
||||
block
|
||||
icon={<PauseCircleOutlined />}
|
||||
onClick={handleStop}
|
||||
>
|
||||
{t("settings.actions.stopwatcher")}
|
||||
</Button>
|
||||
) : (
|
||||
<Space>
|
||||
<ExclamationCircleFilled />
|
||||
{t("settings.labels.stopped")}
|
||||
</Space>
|
||||
<Button
|
||||
type="primary"
|
||||
block
|
||||
icon={<PlayCircleOutlined />}
|
||||
onClick={handleStart}
|
||||
>
|
||||
{t("settings.actions.startwatcher")}
|
||||
</Button>
|
||||
)
|
||||
}
|
||||
color={isWatcherStarted ? "green" : "red"}
|
||||
>
|
||||
<Card title={t("settings.labels.watcherstatus")}>
|
||||
<Row gutter={[16, 16]}>
|
||||
<Col {...colSpans}>
|
||||
{isWatcherStarted ? (
|
||||
<Button
|
||||
danger
|
||||
icon={<PauseCircleOutlined />}
|
||||
onClick={handleStop}
|
||||
>
|
||||
{t("settings.actions.stopwatcher")}
|
||||
</Button>
|
||||
) : (
|
||||
<Button
|
||||
type="primary"
|
||||
icon={<PlayCircleOutlined />}
|
||||
onClick={handleStart}
|
||||
>
|
||||
{t("settings.actions.startwatcher")}
|
||||
</Button>
|
||||
)}
|
||||
</Col>
|
||||
<Col {...colSpans}>
|
||||
<Space direction="vertical" wrap>
|
||||
<Switch
|
||||
checked={!pollingState.enabled}
|
||||
onChange={toggleWatcherMode}
|
||||
checkedChildren={t("settings.labels.watchermoderealtime")}
|
||||
unCheckedChildren={t("settings.labels.watchermodepolling")}
|
||||
/>
|
||||
{pollingState.enabled && (
|
||||
<Space size="small" direction="vertical" wrap>
|
||||
<span>{t("settings.labels.pollinginterval")}</span>
|
||||
<InputNumber
|
||||
title={t("settings.labels.pollinginterval")}
|
||||
disabled={!pollingState.enabled}
|
||||
min={1000}
|
||||
value={pollingState.interval}
|
||||
onChange={handlePollingIntervalChange}
|
||||
/>
|
||||
</Space>
|
||||
)}
|
||||
{watcherError && <Alert message={watcherError} />}
|
||||
</Space>
|
||||
</Col>
|
||||
</Row>
|
||||
</Card>
|
||||
</Badge.Ribbon>
|
||||
<Space orientation="vertical" size="middle" style={{ width: "100%" }}>
|
||||
<SettingsWatchedPaths />
|
||||
<Radio.Group
|
||||
block
|
||||
options={[
|
||||
{ label: "Real-time", value: true },
|
||||
{ label: "Polling", value: false },
|
||||
]}
|
||||
value={!pollingState.enabled}
|
||||
onChange={toggleWatcherMode}
|
||||
optionType="button"
|
||||
buttonStyle="solid"
|
||||
/>
|
||||
|
||||
{pollingState.enabled && (
|
||||
<Flex align="center" gap="middle">
|
||||
<Typography.Text>
|
||||
{t("settings.labels.pollinginterval")}
|
||||
</Typography.Text>
|
||||
|
||||
<InputNumber
|
||||
min={1000}
|
||||
step={1000}
|
||||
value={pollingState.interval}
|
||||
onChange={handlePollingIntervalChange}
|
||||
style={{ width: 150 }}
|
||||
/>
|
||||
</Flex>
|
||||
)}
|
||||
|
||||
{watcherError && (
|
||||
<Alert
|
||||
title="Watcher Error"
|
||||
description={watcherError}
|
||||
type="error"
|
||||
showIcon
|
||||
/>
|
||||
)}
|
||||
</Space>
|
||||
</Card>
|
||||
);
|
||||
};
|
||||
export default SettingsWatcher;
|
||||
|
||||
@@ -1,27 +1,16 @@
|
||||
// renderer/Settings.tsx
|
||||
import { Col, Row } from "antd";
|
||||
import { Space } from "antd";
|
||||
import { FC } from "react";
|
||||
import SettingsWatchedPaths from "./Settings.WatchedPaths";
|
||||
import SettingsWatcher from "./Settings.Watcher";
|
||||
import SettingsConfig from "./Settings.Config";
|
||||
|
||||
const colSpans = {
|
||||
span: 24,
|
||||
};
|
||||
import SettingsWatcher from "./Settings.Watcher";
|
||||
|
||||
const Settings: FC = () => {
|
||||
return (
|
||||
<Row gutter={[16, 16]}>
|
||||
<Col {...colSpans}>
|
||||
<SettingsWatchedPaths />
|
||||
</Col>
|
||||
<Col {...colSpans}>
|
||||
<SettingsWatcher />
|
||||
</Col>
|
||||
<Col {...colSpans}>
|
||||
<SettingsConfig />
|
||||
</Col>
|
||||
</Row>
|
||||
<Space orientation="vertical" size="large" style={{ width: "100%" }}>
|
||||
<SettingsWatcher />
|
||||
|
||||
<SettingsConfig />
|
||||
</Space>
|
||||
);
|
||||
};
|
||||
|
||||
|
||||
@@ -7,14 +7,13 @@ import * as Sentry from "@sentry/electron/renderer";
|
||||
|
||||
// Extend the Window interface to include the api property
|
||||
declare global {
|
||||
interface Window {
|
||||
api: {
|
||||
isTest: () => boolean;
|
||||
};
|
||||
}
|
||||
interface Window {
|
||||
api: {
|
||||
isTest: () => boolean;
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Sentry.init({
|
||||
dsn: "https://ba41d22656999a8c1fd63bcb7df98650@o492140.ingest.us.sentry.io/4509074139447296",
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user