- {build.changes?.map((change, index) => (
-
-
- {change.name}
- {change.message && (
- : {change.message}
- )}
-
-
- ))}
-
- );
-};
-
-const Labels = ({ build }: { build: CIBuild }) => {
- return (
-
-
+
);
};
diff --git a/src/components/serviceThumbnails/serviceThumbnails.css b/src/components/serviceThumbnails/serviceThumbnails.css
index 09d37c22..ebe46d33 100644
--- a/src/components/serviceThumbnails/serviceThumbnails.css
+++ b/src/components/serviceThumbnails/serviceThumbnails.css
@@ -1,30 +1,32 @@
.thumbnails {
- padding: 10px;
-
.thumbnail {
+ border-radius: 5px;
+ border: 1px solid #ddd;
+ cursor: pointer;
display: inline-block;
height: 140px;
margin: 5px 0px 5px 5px;
- text-align: center;
- width: 150px;
+ padding: 10px;
&.active {
background-color: #d1d5e4;
+ border: 1px solid #777;
}
&:hover {
text-decoration: none;
+ border: 1px solid blue;
}
+ transition: border 0.2s ease-in-out;
}
.thumbnail-image {
- height: 110px;
- line-height: 130px;
+ line-height: 100px;
img {
- max-width: 140px;
+ width: 140px;
}
}
.caption {
- padding: 0;
+ text-align: center;
font-weight: bold;
}
}
diff --git a/src/components/serviceThumbnails/serviceThumbnails.tsx b/src/components/serviceThumbnails/serviceThumbnails.tsx
index 46b3ce53..d229bc45 100644
--- a/src/components/serviceThumbnails/serviceThumbnails.tsx
+++ b/src/components/serviceThumbnails/serviceThumbnails.tsx
@@ -18,11 +18,11 @@ export default ({
};
return (
-
+
{serviceTypes.map(serviceType => (
{
diff --git a/src/components/sidebar/sidebar.css b/src/components/sidebar/sidebar.css
index c253ab38..6d1fa6fb 100644
--- a/src/components/sidebar/sidebar.css
+++ b/src/components/sidebar/sidebar.css
@@ -1,21 +1,16 @@
-.scrollable {
- overflow: auto;
- height: 100%;
- width: 100%;
-}
-
.sidebar-nav {
border-right: 1px solid #bbb;
bottom: 0;
left: 0;
position: fixed;
text-align: center;
- top: 52px;
+ top: 57px;
width: 240px;
.scrollable {
- padding: 10px;
- box-sizing: border-box;
+ height: 100%;
+ overflow: auto;
+ padding: 5px;
}
.sortable-placeholder {
@@ -24,52 +19,34 @@
width: 100%;
}
- .handle {
- display: none;
- left: 3px;
- position: absolute;
- top: 23px;
+ .nav-link {
+ display: flex;
+ align-items: center;
+ &:not(.active):hover {
+ background-color: #ddd;
+ }
+ &.service-disabled {
+ opacity: 0.6;
+ }
+ &:hover .handle {
+ visibility: visible;
+ }
}
- .nav-pills {
- li {
- a {
- height: 70px;
- }
- img.pill-icon {
- margin-top: 0;
- margin-bottom: 0;
- float: left;
- width: 48px;
- height: 48px;
- }
- i.pill-icon {
- margin-top: 6px;
- float: left;
- }
+ .handle {
+ visibility: hidden;
+ left: -10px;
+ position: relative;
+ }
- .pill-name {
- padding-top: 18px;
- float: right;
- text-align: right;
- width: 125px;
- }
- &.muted span {
- color: #999;
- }
- &.active {
- a {
- color: #fff;
- }
- }
- }
- .active.muted span {
- color: #ccc;
- }
+ .pill-icon {
+ width: 48px;
+ height: 48px;
}
- .nav-pill:hover .handle {
- display: inline;
+ .pill-name {
+ text-align: right;
+ width: 100%;
}
.actions {
diff --git a/src/components/sidebar/sidebar.tsx b/src/components/sidebar/sidebar.tsx
index fb234d38..db34ae53 100644
--- a/src/components/sidebar/sidebar.tsx
+++ b/src/components/sidebar/sidebar.tsx
@@ -1,8 +1,8 @@
import { CIServiceSettings } from 'common/types';
import { ServiceTypesContext, SettingsContext } from 'components/react-types';
import React, { useContext } from 'react';
-import { Nav, NavItem } from 'react-bootstrap';
-import { Link } from 'react-router-dom';
+import { Nav } from 'react-bootstrap';
+import { NavLink } from 'react-router-dom';
import './sidebar.css';
export default ({ service, view }: { service?: CIServiceSettings; view?: string }) => {
@@ -17,70 +17,59 @@ export default ({ service, view }: { service?: CIServiceSettings; view?: string
return (
diff --git a/src/components/toastAlert/toastAlert.css b/src/components/toastAlert/toastAlert.css
index 5772ec51..a78a4fa0 100644
--- a/src/components/toastAlert/toastAlert.css
+++ b/src/components/toastAlert/toastAlert.css
@@ -1,17 +1,14 @@
.alert-message {
- bottom: 10px;
- border: 1px solid green;
+ bottom: 0;
font-size: larger;
opacity: 0.75;
- margin: 0;
- padding-left: 30px;
position: fixed;
right: 10px;
z-index: 2000;
- -webkit-transition: all 500ms cubic-bezier(0.175, 0.885, 0.32, 1.275);
+ transition: all 500ms cubic-bezier(0.175, 0.885, 0.32, 1.275);
&.alert-hide {
opacity: 0;
- -webkit-transition: all 500ms cubic-bezier(0.6, -0.28, 0.735, 0.045);
- -webkit-transform: translate(200px, 0);
+ transition: all 500ms cubic-bezier(0.6, -0.28, 0.735, 0.045);
+ transform: translate(200px, 0);
}
}
diff --git a/src/components/toastAlert/toastAlert.tsx b/src/components/toastAlert/toastAlert.tsx
index df9d8bd3..b36ad1a9 100644
--- a/src/components/toastAlert/toastAlert.tsx
+++ b/src/components/toastAlert/toastAlert.tsx
@@ -15,12 +15,13 @@ export default ({ text }: { text: string }) => {
});
return (
-
- {text}
-
+
+ {text}
+
+
);
};
diff --git a/src/dashboard/components/dashboardTheme.tsx b/src/dashboard/components/dashboardTheme.tsx
new file mode 100644
index 00000000..8d78a4d4
--- /dev/null
+++ b/src/dashboard/components/dashboardTheme.tsx
@@ -0,0 +1,23 @@
+import { Theme, ViewConfigContext } from 'components/react-types';
+import React, { useContext } from 'react';
+import darkTheme from '../themes/dark/dark';
+import lightTheme from '../themes/light/light';
+
+const themes: Record
= {
+ dark: darkTheme,
+ light: lightTheme,
+};
+
+const DashboardTheme = ({ popup }: { popup: boolean }) => {
+ const viewConfig = useContext(ViewConfigContext);
+
+ const themeName = viewConfig.theme ?? 'dark';
+ const DashboardActiveTheme = themes[themeName];
+ return (
+
+
+
+ );
+};
+
+export default DashboardTheme;
diff --git a/src/components/pipelines/build.css b/src/dashboard/components/pipelines/build.css
similarity index 94%
rename from src/components/pipelines/build.css
rename to src/dashboard/components/pipelines/build.css
index dd3e38f4..8a94a9f4 100644
--- a/src/components/pipelines/build.css
+++ b/src/dashboard/components/pipelines/build.css
@@ -1,12 +1,12 @@
.build {
- padding-left: 2px;
- padding-right: 2px;
- padding-bottom: 5px;
+ padding: 5px 5px 0 0;
+ .progress {
+ height: auto;
+ }
a {
border-radius: 5px;
cursor: pointer;
- margin-top: 5px;
padding: 5px 10px 5px 5px;
position: relative;
white-space: nowrap;
diff --git a/src/dashboard/components/pipelines/build.tsx b/src/dashboard/components/pipelines/build.tsx
new file mode 100644
index 00000000..d78c9925
--- /dev/null
+++ b/src/dashboard/components/pipelines/build.tsx
@@ -0,0 +1,114 @@
+import { CIBuild } from 'common/types';
+import React, { useContext, useEffect, useState } from 'react';
+import { Badge, OverlayTrigger, Tooltip } from 'react-bootstrap';
+import { ViewConfigContext } from '../../../components/react-types';
+import './build.css';
+
+const Changes = ({ build }: { build: CIBuild }) => {
+ const viewConfig = useContext(ViewConfigContext);
+ if (!viewConfig.showCommits) return;
+ const [changeIndex, setChangeIndex] = useState(0);
+ const changesLength = build.changes?.length ?? 0;
+ if (changesLength > 1) {
+ useEffect(() => {
+ const interval = setInterval(() => {
+ setChangeIndex((changeIndex + 1) % changesLength);
+ }, 7000);
+ return () => {
+ clearInterval(interval);
+ };
+ });
+ }
+ const commitsVisible =
+ viewConfig.showCommitsWhenGreen ??
+ build.isBroken ??
+ build.isRunning ??
+ build.isWaiting;
+ return (
+
+ {build.changes?.map((change, index) => (
+
+
+ {change.name}
+ {change.message && (
+ : {change.message}
+ )}
+
+
+ ))}
+
+ );
+};
+
+const Labels = ({ build }: { build: CIBuild }) => {
+ return (
+
+ {build.error && (
+
+ Offline
+ ({build.error.message})
+
+ )}
+ {build.isDisabled && Disabled}
+ {build.tags?.map(tag => {
+ const bgColor = tag.type === 'warning' ? 'warning' : 'secondary';
+ const textColor = tag.type === 'warning' ? 'dark' : '';
+ const badge = (
+
+ {tag.name}
+
+ );
+ return tag.description ? (
+ {tag.description}}
+ >
+ {badge}
+
+ ) : (
+ badge
+ );
+ })}
+
+ );
+};
+
+const Build = ({ build, width }: { build: CIBuild; width: number }) => {
+ return (
+
+ );
+};
+
+export default Build;
diff --git a/src/components/pipelines/pipelines.css b/src/dashboard/components/pipelines/pipelines.css
similarity index 100%
rename from src/components/pipelines/pipelines.css
rename to src/dashboard/components/pipelines/pipelines.css
diff --git a/src/components/pipelines/pipelines.tsx b/src/dashboard/components/pipelines/pipelines.tsx
similarity index 100%
rename from src/components/pipelines/pipelines.tsx
rename to src/dashboard/components/pipelines/pipelines.tsx
diff --git a/src/components/popupNavbar/popupNavbar.css b/src/dashboard/components/popupNavbar.css
similarity index 100%
rename from src/components/popupNavbar/popupNavbar.css
rename to src/dashboard/components/popupNavbar.css
diff --git a/src/dashboard/components/popupNavbar.tsx b/src/dashboard/components/popupNavbar.tsx
new file mode 100644
index 00000000..8982809d
--- /dev/null
+++ b/src/dashboard/components/popupNavbar.tsx
@@ -0,0 +1,31 @@
+import React from 'react';
+import { Container, Nav, Navbar, OverlayTrigger, Tooltip } from 'react-bootstrap';
+import './popupNavbar.css';
+
+export default ({ dark = false }: { dark: boolean }) => {
+ const settingsTooltip = Settings;
+ const dashboardTooltip = Dashboard;
+ return (
+
+
+
+
+
+
+ );
+};
diff --git a/src/dashboard/dashboard.css b/src/dashboard/dashboard.css
index 3f50a369..60d31a5e 100644
--- a/src/dashboard/dashboard.css
+++ b/src/dashboard/dashboard.css
@@ -1,7 +1,4 @@
-@import 'font-awesome/scss/font-awesome.scss';
-
body {
- font-family: 'Helvetica Neue', Helvetica, Arial, sans-serif;
margin: 0;
}
diff --git a/src/dashboard/dashboard.tsx b/src/dashboard/dashboard.tsx
index d8bbac34..3265449f 100644
--- a/src/dashboard/dashboard.tsx
+++ b/src/dashboard/dashboard.tsx
@@ -1,9 +1,11 @@
import 'bootstrap/dist/css/bootstrap.css';
import core from 'common/core';
import logger from 'common/logger';
+import PageContext from 'components/pageContext';
+import 'font-awesome/scss/font-awesome.scss';
import * as React from 'react';
import { createRoot } from 'react-dom/client';
-import DashboardTheme from '../components/dashboardTheme';
+import DashboardTheme from './components/dashboardTheme';
import './dashboard.css';
core.init({ test: false });
@@ -11,4 +13,8 @@ logger.init({ prefix: 'dashboard', debug: false });
const container = document.getElementById('app');
if (!container) throw new Error("Could not find 'app' element");
-createRoot(container).render();
+createRoot(container).render(
+
+
+ ,
+);
diff --git a/src/dashboard/popup.css b/src/dashboard/popup.css
index f80c966d..936a8eda 100644
--- a/src/dashboard/popup.css
+++ b/src/dashboard/popup.css
@@ -1,11 +1,8 @@
-@import 'font-awesome/scss/font-awesome.scss';
-
body {
- font-family: 'Helvetica Neue', Helvetica, Arial, sans-serif;
+ margin: 0;
}
.theme {
- min-height: 100vh;
min-width: 350px;
padding-top: 45px;
}
diff --git a/src/dashboard/popup.tsx b/src/dashboard/popup.tsx
index 79d80ba9..7e7d58d8 100644
--- a/src/dashboard/popup.tsx
+++ b/src/dashboard/popup.tsx
@@ -1,9 +1,11 @@
import 'bootstrap/dist/css/bootstrap.css';
import core from 'common/core';
import logger from 'common/logger';
+import PageContext from 'components/pageContext';
+import 'font-awesome/scss/font-awesome.scss';
import * as React from 'react';
import { createRoot } from 'react-dom/client';
-import DashboardTheme from '../components/dashboardTheme';
+import DashboardTheme from './components/dashboardTheme';
import './popup.css';
core.init({ test: false });
@@ -11,4 +13,8 @@ logger.init({ prefix: 'popup', debug: true });
const container = document.getElementById('app');
if (!container) throw new Error("Could not find 'app' element");
-createRoot(container).render();
+createRoot(container).render(
+
+
+ ,
+);
diff --git a/src/dashboard/themes/dark/dark.tsx b/src/dashboard/themes/dark/dark.tsx
index b41837b2..0f68459c 100644
--- a/src/dashboard/themes/dark/dark.tsx
+++ b/src/dashboard/themes/dark/dark.tsx
@@ -1,5 +1,5 @@
-import Pipelines from 'components/pipelines/pipelines';
-import Navbar from 'components/popupNavbar/popupNavbar';
+import Pipelines from 'dashboard/components/pipelines/pipelines';
+import Navbar from 'dashboard/components/popupNavbar';
import { ThemeProps } from 'components/react-types';
import React from 'react';
import './dark.css';
diff --git a/src/dashboard/themes/light/light.tsx b/src/dashboard/themes/light/light.tsx
index 8371851f..2b042b3d 100644
--- a/src/dashboard/themes/light/light.tsx
+++ b/src/dashboard/themes/light/light.tsx
@@ -1,5 +1,5 @@
-import Pipelines from 'components/pipelines/pipelines';
-import Navbar from 'components/popupNavbar/popupNavbar';
+import Pipelines from 'dashboard/components/pipelines/pipelines';
+import Navbar from 'dashboard/components/popupNavbar';
import { ThemeProps } from 'components/react-types';
import React from 'react';
import './light.css';
diff --git a/src/options/layout.css b/src/options/layout.css
index 48543347..a68c9b9f 100644
--- a/src/options/layout.css
+++ b/src/options/layout.css
@@ -1,17 +1,7 @@
-a {
- cursor: pointer;
-}
-
.content-container {
bottom: 0;
left: 240px;
position: absolute;
right: 0;
- top: 60px;
-}
-
-.settings-container {
- box-sizing: border-box;
- float: left;
- width: 50%;
+ top: 70px;
}
diff --git a/src/options/layout.tsx b/src/options/layout.tsx
index 4e39e03f..458634af 100644
--- a/src/options/layout.tsx
+++ b/src/options/layout.tsx
@@ -1,3 +1,4 @@
+import 'bootstrap/dist/css/bootstrap.min.css';
import OptionsNavBar from 'components/optionsNavbar/optionsNavBar';
import {
ServiceContext,
@@ -5,6 +6,7 @@ import {
SettingsContext,
} from 'components/react-types';
import Sidebar from 'components/sidebar/sidebar';
+import 'font-awesome/scss/font-awesome.scss';
import React, { useContext } from 'react';
import { Outlet, useLocation, useParams } from 'react-router-dom';
import './layout.css';
@@ -38,6 +40,8 @@ function createServiceConfig(
const serviceType = serviceTypes.find(
serviceType => serviceType.baseUrl === serviceTypeId,
);
- return serviceType ? { ...serviceType.defaultConfig, name: serviceId } : null;
+ return serviceType
+ ? { ...serviceType.defaultConfig, name: serviceId }
+ : undefined;
}
}
diff --git a/src/options/options.tsx b/src/options/options.tsx
index cce2cb24..72bd2b29 100644
--- a/src/options/options.tsx
+++ b/src/options/options.tsx
@@ -1,56 +1,45 @@
-import 'bootstrap/dist/css/bootstrap.css';
import core from 'common/core';
import logger from 'common/logger';
import PageContext from 'components/pageContext';
-import 'font-awesome/scss/font-awesome.scss';
-import * as React from 'react';
-import { createRoot } from 'react-dom/client';
-import {
- createBrowserRouter,
- createRoutesFromElements,
- Route,
- RouterProvider,
-} from 'react-router-dom';
import AddPage from 'options/pages/addPage';
import ConfigurationPage from 'options/pages/configurationPage';
import NotificationsPage from 'options/pages/notificationsPage';
import ViewPage from 'options/pages/viewPage';
+import * as React from 'react';
+import { createRoot } from 'react-dom/client';
+import { HashRouter, Route, Routes } from 'react-router-dom';
import Layout from './layout';
import ServicePage from './pages/servicePage';
core.init({ test: false });
logger.init({ prefix: 'options', debug: false });
-export const router = createBrowserRouter(
- createRoutesFromElements(
- <>
-
-
-
- }
- >
- } />
- } />
- } />
- } />
- } />
- } />
-
- Routing error} />
- >,
- ),
- {
- basename: '/src/options/options.html',
- },
-);
-
const container = document.getElementById('app');
if (!container) throw new Error("Could not find 'app' element");
createRoot(container).render(
-
+
+
+
+
+
+ }
+ >
+ } />
+ }
+ />
+ } />
+ } />
+ } />
+ } />
+
+ Routing error} />
+
+
,
);
diff --git a/src/options/pages/addPage.tsx b/src/options/pages/addPage.tsx
index 999fa800..7aba0416 100644
--- a/src/options/pages/addPage.tsx
+++ b/src/options/pages/addPage.tsx
@@ -5,10 +5,8 @@ import { useNavigate } from 'react-router-dom';
export default ({
onChange,
- prefix,
}: {
onChange?: (serviceTypeId: string, serviceName: string) => void;
- prefix?: string;
}) => {
const navigate = useNavigate();
const [serviceTypeId, setServiceTypeId] = useState('');
@@ -26,7 +24,7 @@ export default ({
};
return (
<>
-
+
{
const settings = useContext(SettingsContext);
@@ -49,55 +49,63 @@ export default () => {
core.saveConfig(json);
};
return (
-
-
-
-
-
-
-
-
-
+
+
+
+
{toastAlertReset > 0 && (
)}
-
+ >
);
};
diff --git a/src/options/pages/notificationsPage.tsx b/src/options/pages/notificationsPage.tsx
index 0856f90b..a4afa797 100644
--- a/src/options/pages/notificationsPage.tsx
+++ b/src/options/pages/notificationsPage.tsx
@@ -2,7 +2,7 @@ import core from 'common/core';
import { FormBooleanField } from 'components/formFields';
import { ViewConfigContext } from 'components/react-types';
import React, { useContext } from 'react';
-import { Col, Form } from 'react-bootstrap';
+import { Col, Container, Form } from 'react-bootstrap';
export default () => {
const viewConfig = useContext(ViewConfigContext);
@@ -16,62 +16,64 @@ export default () => {
};
return (
-
-
-
+
+
+
+
+
-
+
);
};
diff --git a/src/options/pages/servicePage.tsx b/src/options/pages/servicePage.tsx
index be205547..5f05f3ea 100644
--- a/src/options/pages/servicePage.tsx
+++ b/src/options/pages/servicePage.tsx
@@ -7,60 +7,70 @@ import { ServiceContext } from 'components/react-types';
import SelectedPipelines from 'components/selectedPipelines/selectedPipelines';
import ToastAlert from 'components/toastAlert/toastAlert';
import React, { useContext, useState } from 'react';
-import { Col, Grid } from 'react-bootstrap';
+import { Col, Container, Row } from 'react-bootstrap';
import { useNavigate } from 'react-router-dom';
-// TODO: clear pipelines when serviceId changed
-
export default () => {
const navigate = useNavigate();
const service = useContext(ServiceContext);
- if (!service) return null;
- let updatedService = { ...service };
- const [pipelines, setPipelines] = useState();
+ const [newService, setNewService] = useState();
+ const [allPipelines, setAllPipelines] = useState();
const [filter, setFilter] = useState();
const [toastAlertReset, setToastAlertReset] = useState(0);
- const updateFilter = value => {
- setFilter(value);
- };
- const updateSelected = (selected: string[]) => {
- updatedService.pipelines = selected;
- };
- const showPipelines = piplines => {
- setPipelines(piplines);
+ if (newService?.name !== service?.name) {
+ // reset state
+ setNewService(service);
+ setAllPipelines(undefined);
+ }
+ if (!service || !newService) return null;
+
+ const showPipelines = (pipelines: CIPipelineList, settings: CIServiceSettings) => {
+ setNewService({ ...settings, ...{ pipelines: settings.pipelines } });
+ setAllPipelines(pipelines);
};
const handleSave = (settings: CIServiceSettings) => {
- updatedService = { ...settings, pipelines: updatedService.pipelines };
- core.saveService(updatedService);
+ setNewService(settings);
setToastAlertReset(toastAlertReset + 1);
+ core.saveService(settings);
navigate(`/service/${settings.name}`);
};
+
+ const updateFilter = value => {
+ setFilter(value);
+ };
+ const updateSelected = (selected: string[]) => {
+ setNewService({ ...newService, ...{ pipelines: selected } });
+ };
return (
-
-
-
-
-
-
- {pipelines && }
-
-
+ <>
+
+
+
+
+
+
+
+ {allPipelines && }
+
+
+
+
{toastAlertReset > 0 && (
)}
-
+ >
);
};
diff --git a/src/options/pages/viewPage.tsx b/src/options/pages/viewPage.tsx
index 75873268..07e74465 100644
--- a/src/options/pages/viewPage.tsx
+++ b/src/options/pages/viewPage.tsx
@@ -1,13 +1,13 @@
import core from 'common/core';
-import DashboardTheme from 'components/dashboardTheme';
import {
FormBooleanField,
FormNumberField,
FormSelectField,
} from 'components/formFields';
import { ViewConfigContext } from 'components/react-types';
+import DashboardTheme from 'dashboard/components/dashboardTheme';
import React, { useContext } from 'react';
-import { Col, Form } from 'react-bootstrap';
+import { Col, Container, Form, Row } from 'react-bootstrap';
export default () => {
const viewConfig = useContext(ViewConfigContext);
@@ -17,59 +17,61 @@ export default () => {
};
return (
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
);
};
diff --git a/src/service-worker/request.ts b/src/service-worker/request.ts
index 07889d12..2e74db7c 100644
--- a/src/service-worker/request.ts
+++ b/src/service-worker/request.ts
@@ -1,5 +1,5 @@
import logger from 'common/logger';
-import { parseString } from 'xml2js';
+import * as xml2js from 'xml2js';
import errors from './requestErrors';
interface RequestOptions {
@@ -85,12 +85,11 @@ function createRequest(options: RequestOptions) {
}
async function parseXml(response: Response) {
- return response.text().then(text => {
- let result;
- parseString(text, (err, json) => {
- if (err) throw err;
- result = json;
- });
+ const text = await response.text();
+ try {
+ const result = await xml2js.parseStringPromise(text);
return result;
- });
+ } catch (error: any) {
+ throw new Error(`XML parse error: ${error?.message}`);
+ }
}
diff --git a/src/typings.d.ts b/src/typings.d.ts
new file mode 100644
index 00000000..60260a3a
--- /dev/null
+++ b/src/typings.d.ts
@@ -0,0 +1 @@
+declare module '*.module.css';
diff --git a/vite.config.mts b/vite.config.mts
index 182cb411..71f00357 100644
--- a/vite.config.mts
+++ b/vite.config.mts
@@ -6,6 +6,11 @@ import { defineConfig } from 'vitest/config';
export default defineConfig({
base: './',
+ resolve: {
+ alias: {
+ stream: 'stream-browserify',
+ },
+ },
plugins: [
react(),
copy({