Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Migrate react-scripts to vite #696

Open
wants to merge 46 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
46 commits
Select commit Hold shift + click to select a range
bc896fa
Converted react-scripts to vite
mfechner Oct 13, 2024
289f100
Use plugin-react instead of plugin-react-swc, as that will not work o…
mfechner Oct 13, 2024
96d09ef
Small fixes on state management and vite configuration to make websoc…
mfechner Oct 13, 2024
a488460
Started to fix issues with state management (mobx)
mfechner Oct 14, 2024
45821b4
Generate a `build/asset-manifest.json`
mfechner Oct 14, 2024
7a778b5
Fix problem in change password and some other state management problems
mfechner Oct 15, 2024
1ec8b23
Clean up changes to be consistent
mfechner Oct 15, 2024
1200f7c
Make it possible to run tests with vitest
mfechner Oct 15, 2024
560e3d9
Define global as it is required by react-codemirror2
mfechner Oct 16, 2024
122ef6a
Upgrade react to 18.3.1
mfechner Oct 16, 2024
1a5ca1f
Fix rimraf api changes
mfechner Jan 1, 2025
8596883
Update all packages to current version including react 19
mfechner Jan 1, 2025
df5dd66
Fix problem with failed auto-login
mfechner Jan 1, 2025
d36a476
Fixed change password and logout in e2e tests
mfechner Jan 1, 2025
921a488
Use a robuster way to determine the base url in production mode.
mfechner Jan 1, 2025
b2b7820
Simplified the auth reducer by defining a initial state for the user …
mfechner Jan 1, 2025
bb6292b
Use URL to construct the url for e2e tests
mfechner Jan 1, 2025
6ec7e0b
Fixed most of the e2e tests
mfechner Jan 1, 2025
10f2b73
Move the code to terminate the gotify application after an e2e test i…
mfechner Jan 1, 2025
68e54d8
Fixed last failing tests for messages
mfechner Jan 2, 2025
011160f
Fix automatic logout if client was removed
mfechner Jan 2, 2025
4d5aabe
Do not load an image if it is null or undefined
mfechner Jan 2, 2025
df9a000
Fixed wrong display of messages (filter of selected App was not applied)
mfechner Jan 2, 2025
1d30cd6
Display a snack message if a single message was deleted
mfechner Jan 2, 2025
dbed184
Hide the loading indicator if the fetch of messages fails, e.g. due t…
mfechner Jan 2, 2025
0e4cf73
Finished rewrite of the Plugin details view to a functional component
mfechner Jan 3, 2025
8f4982e
Make sure, the websocket is a singleton that message are not added to…
mfechner Jan 3, 2025
932a521
Fixed Register user feature and use react 19 action instead of form o…
mfechner Jan 3, 2025
f1ff3f2
Removed unused code
mfechner Jan 3, 2025
71709db
let vite listen not only on localhost so it can be started in a WSL2 …
mfechner Jan 3, 2025
57383cc
Fixed direct loading of sub-pages like `/#/messages/3`
mfechner Jan 6, 2025
f25df9b
Make sure new Material uses some colors like the old material theme did
mfechner Jan 6, 2025
70c8900
Fixed layout problem caused from Material upgrade
mfechner Jan 6, 2025
a055be0
Fixed passing of build related information to the react ui (like vers…
mfechner Jan 6, 2025
3eb2848
Removed not need options due to vite usage
mfechner Jan 6, 2025
d8b1e9f
Replace the application that it does not change the order (which shou…
mfechner Jan 6, 2025
23e5fde
Do not inline sourcemaps anymore to reduce the file size for producti…
mfechner Jan 6, 2025
5fb3854
Remove TODO, we keep the name of the component like it is
mfechner Jan 6, 2025
8d613bc
Use the same url while working in dev mode compared to production mode
mfechner Jan 6, 2025
53f5ced
Fixed loading and refreshing of messages
mfechner Jan 6, 2025
e2c5fa0
Fix typo in test
mfechner Jan 6, 2025
4952391
Reenable React Strict Mode
mfechner Jan 7, 2025
adf75a4
Remove the async sendRequest method
mfechner Jan 7, 2025
decfd41
Moved state/action definition from directory `store` into directory o…
mfechner Jan 7, 2025
daecf32
Remove obsolete files
mfechner Jan 7, 2025
4d0f9bf
Added loading indicators
mfechner Jan 7, 2025
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 3 additions & 4 deletions ui/public/index.html → ui/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
<meta name="theme-color" content="#3f51b5">
<link rel="manifest" href="%PUBLIC_URL%/manifest.json">
<link rel="manifest" href="manifest.json">
<title>Gotify</title>

<link rel="apple-touch-icon-precomposed" sizes="57x57" href="static/apple-touch-icon-57x57.png" />
Expand Down Expand Up @@ -35,8 +35,7 @@
Gotify requires JavaScript.
</noscript>
<div id="root"></div>
<% if (process.env.NODE_ENV === 'production') { %>
<script>window.config = %CONFIG%;</script>
<% } %>
mfechner marked this conversation as resolved.
Show resolved Hide resolved
<script>window.config = %CONFIG%;</script>
<script type="module" src="/src/index.tsx"></script>
</body>
</html>
121 changes: 62 additions & 59 deletions ui/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,72 +2,71 @@
"name": "gotify-ui",
"version": "0.2.0",
"private": true,
"homepage": ".",
"proxy": "http://localhost:80",
"dependencies": {
"@material-ui/core": "^4.11.4",
"@material-ui/icons": "^4.9.1",
"axios": "^0.21.1",
"codemirror": "^5.61.1",
"detect-browser": "^5.2.0",
"js-base64": "^3.6.1",
"mobx": "^5.15.6",
"mobx-react": "^6.3.0",
"mobx-utils": "^5.6.1",
"notifyjs": "^3.0.0",
"prop-types": "^15.6.2",
"react": "^16.4.2",
"react-codemirror2": "^7.2.1",
"react-dom": "^16.4.2",
"react-infinite": "^0.13.0",
"react-markdown": "^6.0.2",
"react-router": "^5.2.0",
"react-router-dom": "^5.2.0",
"react-timeago": "^6.2.1",
"remark-gfm": "^1.0.0",
"remove-markdown": "^0.3.0",
"typeface-roboto": "1.1.13"
"@emotion/react": "11.14.0",
"@emotion/styled": "11.14.0",
"@fontsource/roboto": "5.1.1",
"@mui/icons-material": "6.3.0",
"@mui/material": "6.3.0",
"@uiw/codemirror-extensions-langs": "^4.23.7",
"@uiw/codemirror-theme-material": "^4.23.7",
"@uiw/react-codemirror": "^4.23.7",
"axios": "1.7.9",
"detect-browser": "5.3.0",
"install": "^0.13.0",
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

is this dep used somewhere?

"js-base64": "3.7.7",
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This dep shouldn't be needed, base64 encoding/decoding can be done natively.

"notifyjs": "3.0.0",
"prop-types": "15.8.1",
"react": "19.0.0",
"react-dom": "19.0.0",
"react-markdown": "9.0.1",
"react-redux": "9.2.0",
"react-router": "7.1.1",
"react-router-dom": "7.1.1",
"react-timeago": "7.2.0",
"react-window": "1.8.11",
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

unused

"remark-gfm": "4.0.0",
"remove-markdown": "0.6.0",
"tss-react": "4.9.14"
},
"scripts": {
"start": "react-scripts start",
"build": "react-scripts build",
"test": "react-scripts test --env=node",
"eject": "react-scripts eject",
"start": "vite",
"build": "vite build",
"preview": "vite preview",
"test": "vitest",
"lint": "eslint \"src/**/*.{ts,tsx}\"",
"format": "prettier \"src/**/*.{ts,tsx}\" --write",
"testformat": "prettier \"src/**/*.{ts,tsx}\" --list-different"
},
"devDependencies": {
"@types/codemirror": "5.60.0",
"@types/detect-browser": "^4.0.0",
"@types/get-port": "^4.0.0",
"@types/jest": "^26.0.23",
"@types/js-base64": "^3.3.1",
"@types/node": "^15.12.2",
"@types/notifyjs": "^3.0.2",
"@types/puppeteer": "^5.4.6",
"@types/react": "^16.9.49",
"@types/react-dom": "^16.9.8",
"@types/react-infinite": "0.0.35",
"@types/react-router-dom": "^5.1.7",
"@types/remove-markdown": "^0.3.0",
"@types/rimraf": "^3.0.0",
"@typescript-eslint/eslint-plugin": "^4.1.0",
"@typescript-eslint/parser": "^4.1.0",
"eslint-config-prettier": "^6.11.0",
"eslint-plugin-import": "^2.22.0",
"eslint-plugin-jest": "^24.0.0",
"eslint-plugin-prefer-arrow": "^1.2.2",
"eslint-plugin-react": "^7.20.6",
"eslint-plugin-unicorn": "^21.0.0",
"get-port": "^5.1.1",
"prettier": "^2.3.1",
"puppeteer": "^17.1.3",
"react-scripts": "^4.0.3",
"rimraf": "^3.0.2",
"tree-kill": "^1.2.0",
"typescript": "4.0.2",
"wait-on": "^5.3.0"
"@reduxjs/toolkit": "2.5.0",
"@types/codemirror": "5.60.15",
"@types/detect-browser": "4.0.3",
"@types/js-base64": "3.3.1",
"@types/node": "22.10.3",
"@types/notifyjs": "3.0.5",
"@types/puppeteer": "7.0.4",
"@types/react": "19.0.2",
"@types/react-dom": "19.0.2",
"@types/react-router-dom": "5.3.3",
"@types/remove-markdown": "0.3.4",
"@typescript-eslint/eslint-plugin": "8.19.0",
"@typescript-eslint/parser": "8.19.0",
"@vitejs/plugin-react": "4.3.4",
"eslint-config-prettier": "9.1.0",
"eslint-plugin-import": "2.31.0",
"eslint-plugin-prefer-arrow": "1.2.3",
"eslint-plugin-react": "7.37.3",
"eslint-plugin-unicorn": "56.0.1",
"get-port": "7.1.0",
"prettier": "3.4.2",
"puppeteer": "17.1.3",
"rimraf": "6.0.1",
"tree-kill": "1.2.2",
"typescript": "5.7.2",
"vite": "6.0.6",
"vitest": "2.1.8",
"wait-on": "8.0.1"
},
"eslintConfig": {
"extends": "react-app"
Expand All @@ -83,5 +82,9 @@
"last 1 firefox version",
"last 1 safari version"
]
}
},
"resolutions": {
"rollup": "npm:@rollup/wasm-node"
},
"packageManager": "[email protected]+sha1.ac34549e6aa8e7ead463a7407e1c7390f61a6610"
}
1 change: 1 addition & 0 deletions ui/serve.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import (

"github.com/gin-contrib/gzip"
"github.com/gin-gonic/gin"

"github.com/gotify/server/v2/model"
)

Expand Down
115 changes: 115 additions & 0 deletions ui/src/App.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,115 @@
import React, {useEffect} from 'react';
mfechner marked this conversation as resolved.
Show resolved Hide resolved
import {createHashRouter, RouterProvider} from 'react-router-dom';
import Applications from './application/Applications.tsx';
mfechner marked this conversation as resolved.
Show resolved Hide resolved
import Clients from './client/Clients.tsx';
import {checkAuthLoader} from './common/Auth.ts';
import Messages from './message/Messages.tsx';
import {WebSocketStore} from './message/WebSocketStore.ts';
import PluginsRootLayout from './pages/plugins.tsx';
import RootLayout from './pages/root';
import PluginDetailView from './plugin/PluginDetailView.tsx';
import Plugins from './plugin/Plugins.tsx';
import * as Notifications from './snack/browserNotification.ts';
import {useAppDispatch, useAppSelector} from './store';
import {messageActions} from './message/message-slice.ts';
import Login from './user/Login.tsx';
import Users from './user/Users.tsx';

const router = createHashRouter([
{
path: '/',
element: <RootLayout />,
children: [
{
index: true,
element: <Messages />,
loader: checkAuthLoader,
},
{
path: 'messages',
element: <Messages />,
loader: checkAuthLoader,
children: [
{
path: ':id',
element: <Messages />,
}
]
},
{
path: 'login',
element: <Login />,
},
{
path: 'applications',
element: <Applications />,
loader: checkAuthLoader,
},
{
path: 'users',
element: <Users />,
loader: checkAuthLoader,
},
{
path: 'clients',
element: <Clients />,
loader: checkAuthLoader,
},
{
path: 'plugins',
element: <PluginsRootLayout />,
loader: checkAuthLoader,
children: [
{ index: true, element: <Plugins /> },
{
path: ':id',
element: <PluginDetailView />,
}
],
},
],
},
]);

const ws = new WebSocketStore();

const App = () => {
const dispatch = useAppDispatch();
const loggedIn = useAppSelector((state) => state.auth.loggedIn);

useEffect(() => {
if (loggedIn) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this really the way to react to changes in the state, it there a native way in redux to subscribe to changes in the state and do stuff? Doing this in react seems weird, and having the global state besides redux store (the websocket store varibale in this case, or reconnectTimeoutId in the auth-actions.ts) seems weird to. The redux actions shouldn't have side effects with other global variables.

ws.listen((message) => {
dispatch(messageActions.loading(true));
dispatch(messageActions.add(message));
Notifications.notifyNewMessage(message);
if (message.priority >= 4) {
const src = 'static/notification.ogg';
const audio = new Audio(src);
audio.play();
}
});
window.onbeforeunload = () => {
ws.close();
};
} else {
ws.close();
}
}, [dispatch, loggedIn]);


return (
<RouterProvider router={router} />
);
};

export default App;

/*
<Routes>
{authenticating ? (<Route path="/" element={<LoadingSpinner />} />) : null}
<Route path="/" element={<Messages />} />
<Route path="messages/:id" element={<Messages />} />

</Routes>
*/
Loading
Loading