Skip to content
Snippets Groups Projects
Commit 17d13aa4 authored by Matthias Feyll's avatar Matthias Feyll :cookie:
Browse files

Ui refactor style


See merge request !1161

Co-authored-by: default avatarrenovate_bot <group_8045_bot_08826d7c233c44435d2dae5013b96892@noreply.code.fbi.h-da.de>
Co-authored-by: default avatarFabian Seidl <fabian.seidl@h-da.de>
Co-authored-by: Matthias Feyll <matthias.feyll@@stud.h-da.de>
Co-authored-by: default avatarGhost User <ghost@example.com>
parent c11b1bca
No related branches found
No related tags found
2 merge requests!1162Draft: Ui integration,!1161Ui refactor style
Pipeline #249661 passed
Showing
with 487 additions and 166 deletions
import { BasicProp } from "@helper/interfaces"; import { BasicProp } from "@shared/types/interfaces.type";
import React, { createContext, useContext, useMemo } from "react"; import React, { createContext, useContext, useMemo } from "react";
import { useTranslation } from "react-i18next"; import { useTranslation } from "react-i18next";
import { toast } from "react-toastify"; import { toast } from "react-toastify";
......
import { PayloadAction, createSlice } from '@reduxjs/toolkit' import { PayloadAction, createSlice } from '@reduxjs/toolkit'
import { CategoryType } from '@shared/types/category.type'
import { ThunkDTO, ThunkPersist } from '@shared/types/thunk.type'
import { RoutineManager } from '@utils/routine.manager' import { RoutineManager } from '@utils/routine.manager'
import { RootState } from '../../stores' import { RootState } from '../../stores'
import { startListening } from '../../stores/middleware/listener.middleware' import { startListening } from '../../stores/middleware/listener.middleware'
import { setToken } from './user.reducer' import { setToken } from './user.reducer'
interface ThunkEntityDTO {
thunk: any
payload: Object
/**
* Only one subscription per category is allowed. New subscription will unsubscribe and overwrite the old one
*/
category: CATEGORIES
}
interface ThunkEntity extends ThunkEntityDTO {
id?: number
locked: boolean
}
export interface ReducerState { export interface ReducerState {
thunks: { [key in keyof typeof CATEGORIES]: ThunkEntity | null } thunks: Record<CategoryType, ThunkPersist | null>
}
export enum CATEGORIES {
TABLE,
TAB,
} }
const initialState: ReducerState = { const initialState: ReducerState = {
thunks: { thunks: {
DEVICE: null,
TABLE: null, TABLE: null,
TAB: null, TAB: null
}, },
} }
const RoutineSlice = createSlice({ const RoutineSlice = createSlice({
name: 'routine', name: 'routine',
initialState, initialState,
reducers: { reducers: {
addRoutine: (state: any, { payload }: PayloadAction<ThunkEntityDTO>) => { addRoutine: (state: any, { payload }: PayloadAction<ThunkDTO>) => {
const newThunk: ThunkEntity = { ...payload, locked: true } const thunk: ThunkPersist = {
state.thunks[CATEGORIES[payload.category]] = newThunk category: payload.category,
}, payload: payload.payload,
thunkId: payload.thunk.id,
setThunkId: (state, { payload }: PayloadAction<{ id: number; category: CATEGORIES }>) => { lastupdate: Date.now()
const thunk = state.thunks[CATEGORIES[payload.category] as any]
if (!thunk) {
// TODO
throw new Error('Thunk not found')
} }
state.thunks[CATEGORIES[payload.category] as any] = { ...thunk, id: payload.id, locked: false } state.thunks[payload.category] = thunk
},
refreshUpdateTimer: (state: any, { payload }: PayloadAction<CategoryType>) => {
state.thunks[payload].lastupdate = Date.now()
}, },
removeAll: (state) => { removeAll: (state) => {
...@@ -61,7 +45,7 @@ const RoutineSlice = createSlice({ ...@@ -61,7 +45,7 @@ const RoutineSlice = createSlice({
}, },
}) })
export const { addRoutine } = RoutineSlice.actions export const { addRoutine, refreshUpdateTimer } = RoutineSlice.actions
// on logout remove all routine // on logout remove all routine
startListening({ startListening({
...@@ -72,49 +56,37 @@ startListening({ ...@@ -72,49 +56,37 @@ startListening({
}, },
}) })
// on rehydrate add all persistet routines /**
// TODO -> thunk does not have the thunk function object due to its coming from the store that ignores the value. * Add new routine
// at this point we have to figure out how to get the thunk function out of the "string" name *
// startListening({ * This listener handles the connection between the RoutingManager that
// predicate: ({ type }) => type === REHYDRATE, * stores the non persistable thunk object and the peristable thunk information.
// effect: async (_, listenerApi) => { * The persistable information are stored in this reducer
// const { routine } = listenerApi.getState() as RootState */
// for (const [_, thunk] of Object.entries<ThunkEntity>(routine.thunks)) {
// if (!thunk) {
// continue
// }
// const dto: ThunkEntityDTO = thunk
// listenerApi.dispatch(addRoutine(dto))
// }
// },
// })
// add new routine
startListening({ startListening({
predicate: (action) => addRoutine.match(action), predicate: (action) => addRoutine.match(action),
effect: async (action, listenerApi) => { effect: async (action, listenerApi) => {
const { thunk } = action.payload as ThunkEntity const { thunk } = action.payload as ThunkDTO
const subscription = await listenerApi.dispatch(thunk(action.payload.payload)) const subscription = await listenerApi.dispatch(thunk(action.payload.payload))
const thunkId = await RoutineManager.add(subscription.payload)
listenerApi.dispatch( if (subscription.error) {
RoutineSlice.actions.setThunkId({ id: thunkId, category: action.payload.category }) throw new Error('Error during routine execution: ' + subscription.error.message)
) }
RoutineManager.add(subscription.payload, action.payload.category)
}, },
}) })
// unsubscribe old routine // unsubscribe old routine that is in the same category
startListening({ startListening({
predicate: (action) => addRoutine.match(action), predicate: (action) => addRoutine.match(action),
effect: async (action, listenerApi) => { effect: async (action, listenerApi) => {
const { routine } = listenerApi.getOriginalState() as RootState const { routine } = listenerApi.getOriginalState() as RootState
const lastThunk = routine.thunks[CATEGORIES[action.payload.category] as any] const category = action.payload.category;
if (lastThunk) {
if (!lastThunk.id) {
throw new Error()
// TODO
}
RoutineManager.unsubscribe(lastThunk.id) const lastThunk = routine.thunks[category as CategoryType]
if (lastThunk) {
RoutineManager.unsubscribe(category)
} }
}, },
}) })
......
import { api, RbacUser, UserServiceGetUsersApiArg } from '@api/api' import { RbacUser } from '@api/api'
import { setCookieValue } from '@helper/coookie' import { setCookieValue } from '@helper/coookie'
import { createAsyncThunk, createSlice, PayloadAction } from '@reduxjs/toolkit' import { createSlice, PayloadAction } from '@reduxjs/toolkit'
import { RootState } from '..'
export interface UserSliceState { export interface UserSliceState {
// defined by the frontend user input. This value is getting compared with the backend response // defined by the frontend user input. This value is getting compared with the backend response
...@@ -34,27 +33,4 @@ export const { setToken } = userSlice.actions ...@@ -34,27 +33,4 @@ export const { setToken } = userSlice.actions
export const { setUser } = userSlice.actions export const { setUser } = userSlice.actions
export default userSlice.reducer export default userSlice.reducer
export const userReducerPath = userSlice.reducerPath export const userReducerPath = userSlice.reducerPath
\ No newline at end of file
export const fetchUser = createAsyncThunk('user/fetchUser', (_, thunkAPI) => {
const payload: UserServiceGetUsersApiArg = {}
thunkAPI.dispatch(api.endpoints.userServiceGetUsers.initiate(payload)).then((response) => {
if (response.error || !response.data?.user?.length) {
// TODO proper error handling
throw new Error('Fetching the pnd list after successful login failed')
}
const { user } = thunkAPI.getState() as RootState
// TODO ask if this is the correct approach
const matchedUser = response.data.user.find((_user) => _user.name === user.username)
if (!matchedUser) {
// TODO proper error handling
throw new Error('No user found with the provided username')
}
thunkAPI.dispatch(setUser(matchedUser))
})
})
import { api, PndServiceGetPndListApiArg, UserServiceGetUsersApiArg } from "@api/api"
import { setPnds } from "@component/devices/reducer/device.reducer"
import { createAsyncThunk } from "@reduxjs/toolkit"
import { setUser } from "@shared/reducer/user.reducer"
import { RootState } from "src/stores"
export const fetchUser = createAsyncThunk('user/fetchUser', (_, thunkAPI) => {
const payload: UserServiceGetUsersApiArg = {}
thunkAPI.dispatch(api.endpoints.userServiceGetUsers.initiate(payload)).then((response) => {
if (response.error || !response.data?.user?.length) {
// TODO proper error handling
throw new Error('Fetching the pnd list after successful login failed')
}
const { user } = thunkAPI.getState() as RootState
const matchedUser = response.data.user.find((_user) => _user.name === user.username)
if (!matchedUser) {
// TODO proper error handling => logout
throw new Error('No user found with the provided username')
}
thunkAPI.dispatch(setUser(matchedUser))
})
})
export const fetchPnds = createAsyncThunk('device/fetchPnds', (_, thunkApi) => {
const payload: PndServiceGetPndListApiArg = {
timestamp: new Date().getTime().toString(),
}
const subscription = thunkApi.dispatch(api.endpoints.pndServiceGetPndList.initiate(payload))
subscription.unwrap().then((response) => {
thunkApi.dispatch(setPnds(response.pnd))
})
})
\ No newline at end of file
@import './colors.scss'; @import "./colors.scss";
$box-padding: 10px; $box-padding: 10px;
$border-radius: 20px; $border-radius: 0.25em;
$border-width: 2px;
$transition-duration: 0.3s;
.c-box { .c-box {
padding: $box-padding; padding: $box-padding;
background-color: white; background-color: white;
box-shadow: 0px 4px 4px rgba(0,0,0, .35); position: relative;
border-radius: $border-radius; border-radius: $border-radius;
transition: box-shadow $transition-duration ease-in-out;
background:
linear-gradient(white, white) padding-box,
linear-gradient(
180deg,
rgba(map-get($theme-colors, "primary"), 0.4) 0%,
rgba(map-get($theme-colors, "primary"), 0.2) 40%,
rgba(map-get($theme-colors, "primary"), 0.1) 100%
)
border-box;
border: $border-width solid transparent;
box-shadow: $box-shadow;
&::before {
content: "";
position: absolute;
top: -$border-width;
left: -$border-width;
right: -$border-width;
bottom: -$border-width;
background: linear-gradient(
180deg,
rgba(map-get($theme-colors, "primary"), 0.4) 0%,
rgba(map-get($theme-colors, "primary"), 0.2) 60%,
rgba(map-get($theme-colors, "primary"), 0.1) 100%
);
border-radius: inherit;
z-index: -1;
opacity: 0;
transition: opacity $transition-duration ease-in-out;
}
&:hover {
box-shadow: 0 0.5rem 1rem rgba(map-get($theme-colors, "primary"), 0.2);
&::before {
opacity: 1;
}
}
} }
.abstract-box { .abstract-box {
padding: 16px $box-padding; padding: $box-padding;
font-size: .90em; font-size: 0.9em;
border-radius: calc($border-radius / 2); border-radius: calc($border-radius / 2);
} }
// @each $color, $value in $theme-colors {
// .#{$color}-box {
// @extend .abstract-box;
// background-color: $value !important;
// }
// }
$theme-colors: ( $theme-colors: (
'primary': #b350e0, "primary": #b350e0,
'primary::hover': #ddaff3af, "primary::hover": #ddaff3af,
'bg-primary': #E1E1E1, "bg-primary": #ededed,
'danger': #ffdcdc, "danger": #ff0000,
'warning': #dbd116, "warning": #dbd116,
'dark': #595959, "dark": #595959,
'black': #000000, "black": #000000
); );
@import '/node_modules/bootstrap/scss/bootstrap'; $box-shadow: 0px 4px 8px rgba(map-get($theme-colors, "primary"), 0.2);
@import "/node_modules/bootstrap/scss/bootstrap";
@font-face { @font-face {
font-family: Inter; font-family: Inter;
src: url("/fonts/Inter.ttf"); src:
url("/fonts/inter-webfont.woff2") format("woff2"),
url("/fonts/inter-webfont.woff") format("woff");
font-weight: normal;
font-style: normal;
} }
* { * {
font-family: Inter; font-family: Inter;
} }
\ No newline at end of file
...@@ -7,7 +7,3 @@ ...@@ -7,7 +7,3 @@
cursor: pointer; cursor: pointer;
} }
} }
.icon {
font-size: 1.75em;
}
const DeviceListView = {
TABLE: "device_list/table",
TAB: "device_list/tab",
}
const Shared = {
DEVICE: 'objects/device'
}
export const Category = {
...DeviceListView,
...Shared
}
export type CategoryType = keyof typeof Category
\ No newline at end of file
import { CategoryType } from "./category.type"
// The actual Thunk type is hard to determine because is very generic
export type ThunkFunc = any
export interface ThunkDTO {
thunk: ThunkFunc
payload: Object
/**
* Only one subscription per category is allowed.
* New subscription will unsubscribe and overwrite the old one
*/
category: CategoryType
}
export interface ThunkPersist {
thunkId: number,
payload: Object
category: CategoryType,
lastupdate: number
}
import React, { useEffect, useState } from 'react';
import { Col, Container, Row } from 'react-bootstrap';
import logo from '/public/logo.png';
interface DelayedRenderProps {
children: React.ReactNode;
loading?: {
minimumLoadingTime: number;
component: () => JSX.Element
}
}
export const SplashScreen = () => {
const [dots, setDots] = useState('');
useEffect(() => {
const dotsInterval = setInterval(() => {
setDots(prev => prev.length >= 3 ? '' : prev + '.');
}, 500);
return () => clearInterval(dotsInterval);
}, []);
return (
<div className="splash-screen-overlay">
<Container fluid className="h-100 d-flex align-items-center justify-content-center bg-bg-primary">
<Row>
<Col className="text-center">
<div className="loading-bounce mb-4">
<img
src={logo}
alt="Logo"
className="img-fluid"
style={{ width: '120px', height: '120px', objectFit: 'contain' }}
/>
</div>
<div className="loading-text">
<span className="h4 text-secondary">Loading</span>
<span className="h4 text-secondary dots-width">{dots}</span>
</div>
</Col>
</Row>
</Container>
<style>
{`
.splash-screen-overlay {
position: fixed;
top: 0;
left: 0;
width: 100%;
height: 100%;
background-color: #f8f9fa;
z-index: 0;
display: flex;
align-items: center;
justify-content: center;
}
.loading-bounce {
animation: bounce 1s infinite;
}
@keyframes bounce {
0%, 100% {
transform: translateY(0);
}
50% {
transform: translateY(-20px);
}
}
.loading-text {
display: flex;
justify-content: center;
align-items: center;
}
.dots-width {
min-width: 24px;
text-align: left;
margin-left: 2px;
}
`}
</style>
</div>
);
};
export const DelayedRender: React.FC<DelayedRenderProps> = ({
children,
loading
}) => {
const [shouldRender, setShouldRender] = useState(false);
useEffect(() => {
if (!loading) {
setShouldRender(true);
return;
}
const timer = setTimeout(() => {
setShouldRender(true);
}, loading.minimumLoadingTime);
return () => clearTimeout(timer);
}, [loading]);
if (!shouldRender && loading) {
const LoadingComponent = loading.component;
return <LoadingComponent />;
}
return <>{children}</>;
};
export default DelayedRender;
\ No newline at end of file
import { infoMessage, warnMessage } from '@helper/debug'
import { QueryActionCreatorResult } from '@reduxjs/toolkit/query' import { QueryActionCreatorResult } from '@reduxjs/toolkit/query'
import { Category, CategoryType } from '@shared/types/category.type'
type Routine = QueryActionCreatorResult<any> type Routine = QueryActionCreatorResult<any>
interface Entity { interface Entity {
routine: Routine routine: Routine
id: number
} }
const initialState = {
routines: [] as Entity[], interface RoutineState {
routines: Record<CategoryType, Entity | null>
}
const initalState: RoutineState = {
routines: {
DEVICE: null,
TABLE: null,
TAB: null
}
} }
/** /**
* Routine manager is a singleton that holds all running routines. * Routine manager is a singleton that holds all running routines.
* The redux store holds any persistable information about the routines. * The redux store holds any persistable information about the routines.
* The routines objects itself are stored in the RoutineManager. * The routine objects itself are stored in the RoutineManager.
*/ */
export const RoutineManager = (() => { export const RoutineManager = (() => {
const state = initialState let state = initalState
const add = (routine: Routine): number => {
const id = state.routines.length
const newEntity: Entity = { const add = (routine: Routine, category: CategoryType): boolean => {
const entity: Entity = {
routine: routine, routine: routine,
id,
} }
state.routines = [...state.routines, newEntity] state.routines = {
...state.routines,
[category]: entity
}
infoMessage("Routine subscribed to category " + category)
return id return true
} }
const unsubscribeAll = () => { const unsubscribeAll = () => {
state.routines.forEach(({ routine: subscription }) => { Object.keys(state.routines)
_unsubscribe(subscription) .forEach((category) => {
}) unsubscribe(category as CategoryType)
})
state.routines = initialState.routines state = initalState
} }
/** /**
* @param id * @param id
* @returns returns true if the routine was stopped, false if it was not found * @returns returns true if the routine was stopped, false if it was not found
*/ */
const unsubscribe = (id: number): boolean => { const unsubscribe = (category: CategoryType): boolean => {
const routine = state.routines.find(({ id: routineId }) => routineId === id) const entity = state.routines[category]
if (routine) { if (entity) {
_unsubscribe(routine.routine) entity.routine.unsubscribe()
state.routines[category] = null
infoMessage("Routine unsubscribed from category " + category)
} }
return !!routine if (!!entity) {
} warnMessage("Desired routine to unsubscribe does not exist in category " + Category[category])
}
/** return !!entity
* Actual unsubscribe process.
* This process is extracted to have a single process of unsubscribing.
*
* @param subscription
*/
const _unsubscribe = (subscription: Routine) => {
subscription.unsubscribe()
// TODO remove from state
} }
return { return {
...@@ -69,4 +77,4 @@ export const RoutineManager = (() => { ...@@ -69,4 +77,4 @@ export const RoutineManager = (() => {
unsubscribe, unsubscribe,
unsubscribeAll, unsubscribeAll,
} }
})() })()
\ No newline at end of file
...@@ -22,7 +22,6 @@ ...@@ -22,7 +22,6 @@
"baseUrl": ".", "baseUrl": ".",
"paths": { "paths": {
"@assets/*": ["assets/*"],
"@api/*": ["src/shared/api/*"], "@api/*": ["src/shared/api/*"],
"@reducer/*": ["src/stores/reducer/*"], "@reducer/*": ["src/stores/reducer/*"],
"@provider/*": ["src/shared/provider/*"], "@provider/*": ["src/shared/provider/*"],
......
import react from '@vitejs/plugin-react' import react from '@vitejs/plugin-react';
import { defineConfig } from 'vite' import { defineConfig } from 'vite';
export default defineConfig({ export default defineConfig({
plugins: [react()], plugins: [react()],
build: { build: {
sourcemap: true, sourcemap: false,
rollupOptions: {
output: {
manualChunks: {
'required': [
'bootstrap', 'react-bootstrap',
'react', 'react-dom', 'react-router-dom',
'redux', '@reduxjs/toolkit', 'react-redux', 'redux-observable', 'redux-persist',
'i18next', 'react-i18next',
'@fortawesome/fontawesome-svg-core',
'@fortawesome/free-regular-svg-icons',
'@fortawesome/free-solid-svg-icons',
'@fortawesome/react-fontawesome'
],
'lazy': [
'react-toastify'
]
}
}
}
}, },
// develop server // develop server
server: { server: {
sourcemap: true,
host: true,
port: 3000, port: 3000,
proxy: { proxy: {
'/api': { '/api': {
target: 'http://127.0.0.1:8080', target: 'http://clab-gosdn_csbi_arista_base-gosdn:8080',
changeOrigin: true, changeOrigin: true,
secure: false, secure: false,
rewrite: (path) => path.replace(/^\/api/, ''), rewrite: (path) => path.replace(/^\/api/, ''),
...@@ -35,7 +57,6 @@ export default defineConfig({ ...@@ -35,7 +57,6 @@ export default defineConfig({
}, },
resolve: { resolve: {
alias: { alias: {
'@assets': '/assets',
'@api': '/src/shared/api', '@api': '/src/shared/api',
'@reducer': '/src/stores/reducer', '@reducer': '/src/stores/reducer',
'@provider': '/src/shared/provider', '@provider': '/src/shared/provider',
......
...@@ -1486,6 +1486,13 @@ ...@@ -1486,6 +1486,13 @@
dependencies: dependencies:
prop-types "^15.8.1" prop-types "^15.8.1"
   
"@fullhuman/postcss-purgecss@^7.0.2":
version "7.0.2"
resolved "https://registry.yarnpkg.com/@fullhuman/postcss-purgecss/-/postcss-purgecss-7.0.2.tgz#ccacdbc312248c76c42cfac359f4ca5121001e67"
integrity sha512-U4zAXNaVztbDxO9EdcLp51F3UxxYsb/7DN89rFxFJhfk2Wua2pvw2Kf3HdspbPhW/wpHjSjsxWYoIlbTgRSjbQ==
dependencies:
purgecss "^7.0.2"
"@humanfs/core@^0.19.1": "@humanfs/core@^0.19.1":
version "0.19.1" version "0.19.1"
resolved "https://registry.yarnpkg.com/@humanfs/core/-/core-0.19.1.tgz#17c55ca7d426733fe3c561906b8173c336b40a77" resolved "https://registry.yarnpkg.com/@humanfs/core/-/core-0.19.1.tgz#17c55ca7d426733fe3c561906b8173c336b40a77"
...@@ -2586,6 +2593,13 @@ ...@@ -2586,6 +2593,13 @@
resolved "https://registry.yarnpkg.com/@types/react-dom/-/react-dom-18.3.3.tgz#3654138d0da1b0c7916f6ed0dc1cc2b576d47650" resolved "https://registry.yarnpkg.com/@types/react-dom/-/react-dom-18.3.3.tgz#3654138d0da1b0c7916f6ed0dc1cc2b576d47650"
integrity sha512-uTYkxTLkYp41nq/ULXyXMtkNT1vu5fXJoqad6uTNCOGat5t9cLgF4vMNLBXsTOXpdOI44XzKPY1M5RRm0bQHuw== integrity sha512-uTYkxTLkYp41nq/ULXyXMtkNT1vu5fXJoqad6uTNCOGat5t9cLgF4vMNLBXsTOXpdOI44XzKPY1M5RRm0bQHuw==
   
"@types/react-grid-layout@^1.3.5":
version "1.3.5"
resolved "https://registry.yarnpkg.com/@types/react-grid-layout/-/react-grid-layout-1.3.5.tgz#f4b52bf27775290ee0523214be0987be14e66823"
integrity sha512-WH/po1gcEcoR6y857yAnPGug+ZhkF4PaTUxgAbwfeSH/QOgVSakKHBXoPGad/sEznmkiaK3pqHk+etdWisoeBQ==
dependencies:
"@types/react" "*"
"@types/react-transition-group@^4.4.6": "@types/react-transition-group@^4.4.6":
version "4.4.11" version "4.4.11"
resolved "https://registry.yarnpkg.com/@types/react-transition-group/-/react-transition-group-4.4.11.tgz#d963253a611d757de01ebb241143b1017d5d63d5" resolved "https://registry.yarnpkg.com/@types/react-transition-group/-/react-transition-group-4.4.11.tgz#d963253a611d757de01ebb241143b1017d5d63d5"
...@@ -3836,7 +3850,12 @@ cliui@^8.0.1: ...@@ -3836,7 +3850,12 @@ cliui@^8.0.1:
strip-ansi "^6.0.1" strip-ansi "^6.0.1"
wrap-ansi "^7.0.0" wrap-ansi "^7.0.0"
   
clsx@^2.1.0: clsx@^1.1.1:
version "1.2.1"
resolved "https://registry.yarnpkg.com/clsx/-/clsx-1.2.1.tgz#0ddc4a20a549b59c93a4116bb26f5294ca17dc12"
integrity sha512-EcR6r5a8bj6pu3ycsa/E/cKVGuTgZJZdsyUYHOksG/UHIiKfjxzRxYJpyVBwYaQeOvghal9fcc4PidlgzugAQg==
clsx@^2.0.0, clsx@^2.1.0:
version "2.1.1" version "2.1.1"
resolved "https://registry.yarnpkg.com/clsx/-/clsx-2.1.1.tgz#eed397c9fd8bd882bfb18deab7102049a2f32999" resolved "https://registry.yarnpkg.com/clsx/-/clsx-2.1.1.tgz#eed397c9fd8bd882bfb18deab7102049a2f32999"
integrity sha512-eYm0QWBtUrBWZWG0d386OGAw16Z995PiOVo2B7bjWSbHedGl5e0ZWaq65kOGgUSNesEIDkB9ISbTg/JK9dhCZA== integrity sha512-eYm0QWBtUrBWZWG0d386OGAw16Z995PiOVo2B7bjWSbHedGl5e0ZWaq65kOGgUSNesEIDkB9ISbTg/JK9dhCZA==
...@@ -3906,6 +3925,11 @@ combined-stream@^1.0.8: ...@@ -3906,6 +3925,11 @@ combined-stream@^1.0.8:
dependencies: dependencies:
delayed-stream "~1.0.0" delayed-stream "~1.0.0"
   
commander@^12.1.0:
version "12.1.0"
resolved "https://registry.yarnpkg.com/commander/-/commander-12.1.0.tgz#01423b36f501259fdaac4d0e4d60c96c991585d3"
integrity sha512-Vw8qHK3bZM9y/P10u3Vib8o/DdkvA2OtPtZvD871QKjy74Wj1WSKFILMPRPSdUSx5RFK1arlJzEtA4PkFgnbuA==
commander@^2.20.0: commander@^2.20.0:
version "2.20.3" version "2.20.3"
resolved "https://registry.yarnpkg.com/commander/-/commander-2.20.3.tgz#fd485e84c03eb4881c20722ba48035e8531aeb33" resolved "https://registry.yarnpkg.com/commander/-/commander-2.20.3.tgz#fd485e84c03eb4881c20722ba48035e8531aeb33"
...@@ -4061,6 +4085,11 @@ cross-spawn@^7.0.0, cross-spawn@^7.0.2, cross-spawn@^7.0.3, cross-spawn@^7.0.5: ...@@ -4061,6 +4085,11 @@ cross-spawn@^7.0.0, cross-spawn@^7.0.2, cross-spawn@^7.0.3, cross-spawn@^7.0.5:
shebang-command "^2.0.0" shebang-command "^2.0.0"
which "^2.0.1" which "^2.0.1"
   
crypto-js@^4.2.0:
version "4.2.0"
resolved "https://registry.yarnpkg.com/crypto-js/-/crypto-js-4.2.0.tgz#4d931639ecdfd12ff80e8186dba6af2c2e856631"
integrity sha512-KALDyEYgpY+Rlob/iriUtjV6d5Eq+Y191A5g4UqLAi8CyGP9N1+FdVbkc1SxKc2r4YAYqG8JzO2KGL+AizD70Q==
crypto-random-string@^2.0.0: crypto-random-string@^2.0.0:
version "2.0.0" version "2.0.0"
resolved "https://registry.yarnpkg.com/crypto-random-string/-/crypto-random-string-2.0.0.tgz#ef2a7a966ec11083388369baa02ebead229b30d5" resolved "https://registry.yarnpkg.com/crypto-random-string/-/crypto-random-string-2.0.0.tgz#ef2a7a966ec11083388369baa02ebead229b30d5"
...@@ -5334,6 +5363,11 @@ fast-diff@^1.1.2: ...@@ -5334,6 +5363,11 @@ fast-diff@^1.1.2:
resolved "https://registry.yarnpkg.com/fast-diff/-/fast-diff-1.3.0.tgz#ece407fa550a64d638536cd727e129c61616e0f0" resolved "https://registry.yarnpkg.com/fast-diff/-/fast-diff-1.3.0.tgz#ece407fa550a64d638536cd727e129c61616e0f0"
integrity sha512-VxPP4NqbUjj6MaAOafWeUn2cXWLcCtljklUtZf0Ind4XQ+QPtmA0b18zZy0jIQx+ExRVCR/ZQpBmik5lXshNsw== integrity sha512-VxPP4NqbUjj6MaAOafWeUn2cXWLcCtljklUtZf0Ind4XQ+QPtmA0b18zZy0jIQx+ExRVCR/ZQpBmik5lXshNsw==
   
fast-equals@^4.0.3:
version "4.0.3"
resolved "https://registry.yarnpkg.com/fast-equals/-/fast-equals-4.0.3.tgz#72884cc805ec3c6679b99875f6b7654f39f0e8c7"
integrity sha512-G3BSX9cfKttjr+2o1O22tYMLq0DPluZnYtq1rXumE1SpL/F/SLIfHx08WYQoWSIpeMYf8sRbJ8++71+v6Pnxfg==
fast-glob@^3.2.9, fast-glob@^3.3.2: fast-glob@^3.2.9, fast-glob@^3.3.2:
version "3.3.2" version "3.3.2"
resolved "https://registry.yarnpkg.com/fast-glob/-/fast-glob-3.3.2.tgz#a904501e57cfdd2ffcded45e99a54fef55e46129" resolved "https://registry.yarnpkg.com/fast-glob/-/fast-glob-3.3.2.tgz#a904501e57cfdd2ffcded45e99a54fef55e46129"
...@@ -5690,6 +5724,18 @@ glob@^10.3.10: ...@@ -5690,6 +5724,18 @@ glob@^10.3.10:
package-json-from-dist "^1.0.0" package-json-from-dist "^1.0.0"
path-scurry "^1.11.1" path-scurry "^1.11.1"
   
glob@^11.0.0:
version "11.0.0"
resolved "https://registry.yarnpkg.com/glob/-/glob-11.0.0.tgz#6031df0d7b65eaa1ccb9b29b5ced16cea658e77e"
integrity sha512-9UiX/Bl6J2yaBbxKoEBRm4Cipxgok8kQYcOPEhScPwebu2I0HoQOuYdIO6S3hLuWoZgpDpwQZMzTFxgpkyT76g==
dependencies:
foreground-child "^3.1.0"
jackspeak "^4.0.1"
minimatch "^10.0.0"
minipass "^7.1.2"
package-json-from-dist "^1.0.0"
path-scurry "^2.0.0"
glob@^7.1.1, glob@^7.1.2, glob@^7.1.3, glob@^7.1.4, glob@^7.1.6: glob@^7.1.1, glob@^7.1.2, glob@^7.1.3, glob@^7.1.4, glob@^7.1.6:
version "7.2.3" version "7.2.3"
resolved "https://registry.yarnpkg.com/glob/-/glob-7.2.3.tgz#b8df0fb802bbfa8e89bd1d938b4e16578ed44f2b" resolved "https://registry.yarnpkg.com/glob/-/glob-7.2.3.tgz#b8df0fb802bbfa8e89bd1d938b4e16578ed44f2b"
...@@ -6469,6 +6515,13 @@ jackspeak@^3.1.2: ...@@ -6469,6 +6515,13 @@ jackspeak@^3.1.2:
optionalDependencies: optionalDependencies:
"@pkgjs/parseargs" "^0.11.0" "@pkgjs/parseargs" "^0.11.0"
   
jackspeak@^4.0.1:
version "4.0.2"
resolved "https://registry.yarnpkg.com/jackspeak/-/jackspeak-4.0.2.tgz#11f9468a3730c6ff6f56823a820d7e3be9bef015"
integrity sha512-bZsjR/iRjl1Nk1UkjGpAzLNfQtzuijhn2g+pbZb98HQ1Gk8vM9hfbxeMBP+M2/UUdwj0RqGG3mlvk2MsAqwvEw==
dependencies:
"@isaacs/cliui" "^8.0.2"
jake@^10.8.5: jake@^10.8.5:
version "10.9.2" version "10.9.2"
resolved "https://registry.yarnpkg.com/jake/-/jake-10.9.2.tgz#6ae487e6a69afec3a5e167628996b59f35ae2b7f" resolved "https://registry.yarnpkg.com/jake/-/jake-10.9.2.tgz#6ae487e6a69afec3a5e167628996b59f35ae2b7f"
...@@ -7277,6 +7330,11 @@ lru-cache@^10.2.0: ...@@ -7277,6 +7330,11 @@ lru-cache@^10.2.0:
resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-10.4.3.tgz#410fc8a17b70e598013df257c2446b7f3383f119" resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-10.4.3.tgz#410fc8a17b70e598013df257c2446b7f3383f119"
integrity sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ== integrity sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ==
   
lru-cache@^11.0.0:
version "11.0.2"
resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-11.0.2.tgz#fbd8e7cf8211f5e7e5d91905c415a3f55755ca39"
integrity sha512-123qHRfJBmo2jXDbo/a5YOQrJoHF/GNQTLzQ5+IdK5pWpceK17yRc6ozlWd25FxvGKQbIUs91fDFkXmDHTKcyA==
lru-cache@^5.1.1: lru-cache@^5.1.1:
version "5.1.1" version "5.1.1"
resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-5.1.1.tgz#1da27e6710271947695daf6848e847f01d84b920" resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-5.1.1.tgz#1da27e6710271947695daf6848e847f01d84b920"
...@@ -7407,6 +7465,13 @@ minimalistic-assert@^1.0.0: ...@@ -7407,6 +7465,13 @@ minimalistic-assert@^1.0.0:
resolved "https://registry.yarnpkg.com/minimalistic-assert/-/minimalistic-assert-1.0.1.tgz#2e194de044626d4a10e7f7fbc00ce73e83e4d5c7" resolved "https://registry.yarnpkg.com/minimalistic-assert/-/minimalistic-assert-1.0.1.tgz#2e194de044626d4a10e7f7fbc00ce73e83e4d5c7"
integrity sha512-UtJcAD4yEaGtjPezWuO9wC4nwUnVH/8/Im3yEHQP4b67cXlD/Qr9hdITCU1xDbSEXg2XKNaP8jsReV7vQd00/A== integrity sha512-UtJcAD4yEaGtjPezWuO9wC4nwUnVH/8/Im3yEHQP4b67cXlD/Qr9hdITCU1xDbSEXg2XKNaP8jsReV7vQd00/A==
   
minimatch@^10.0.0:
version "10.0.1"
resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-10.0.1.tgz#ce0521856b453c86e25f2c4c0d03e6ff7ddc440b"
integrity sha512-ethXTt3SGGR+95gudmqJ1eNhRO7eGEGIgYA9vnPatK4/etz2MEVDno5GMCibdMTuBMyElzIlgxMna3K94XDIDQ==
dependencies:
brace-expansion "^2.0.1"
minimatch@^3.0.4, minimatch@^3.0.5, minimatch@^3.1.1, minimatch@^3.1.2: minimatch@^3.0.4, minimatch@^3.0.5, minimatch@^3.1.1, minimatch@^3.1.2:
version "3.1.2" version "3.1.2"
resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-3.1.2.tgz#19cd194bfd3e428f049a70817c038d89ab4be35b" resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-3.1.2.tgz#19cd194bfd3e428f049a70817c038d89ab4be35b"
...@@ -7923,6 +7988,14 @@ path-scurry@^1.11.1: ...@@ -7923,6 +7988,14 @@ path-scurry@^1.11.1:
lru-cache "^10.2.0" lru-cache "^10.2.0"
minipass "^5.0.0 || ^6.0.2 || ^7.0.0" minipass "^5.0.0 || ^6.0.2 || ^7.0.0"
   
path-scurry@^2.0.0:
version "2.0.0"
resolved "https://registry.yarnpkg.com/path-scurry/-/path-scurry-2.0.0.tgz#9f052289f23ad8bf9397a2a0425e7b8615c58580"
integrity sha512-ypGJsmGtdXUOeM5u93TyeIEfEhM6s+ljAhrk5vAvSx8uyY/02OvrZnA0YNGUrPXfpJMgI1ODd3nwz8Npx4O4cg==
dependencies:
lru-cache "^11.0.0"
minipass "^7.1.2"
path-to-regexp@0.1.12: path-to-regexp@0.1.12:
version "0.1.12" version "0.1.12"
resolved "https://registry.yarnpkg.com/path-to-regexp/-/path-to-regexp-0.1.12.tgz#d5e1a12e478a976d432ef3c58d534b9923164bb7" resolved "https://registry.yarnpkg.com/path-to-regexp/-/path-to-regexp-0.1.12.tgz#d5e1a12e478a976d432ef3c58d534b9923164bb7"
...@@ -8624,7 +8697,7 @@ prop-types-extra@^1.1.0: ...@@ -8624,7 +8697,7 @@ prop-types-extra@^1.1.0:
react-is "^16.3.2" react-is "^16.3.2"
warning "^4.0.0" warning "^4.0.0"
   
prop-types@^15.6.2, prop-types@^15.8.1: prop-types@15.x, prop-types@^15.6.2, prop-types@^15.8.1:
version "15.8.1" version "15.8.1"
resolved "https://registry.yarnpkg.com/prop-types/-/prop-types-15.8.1.tgz#67d87bf1a694f48435cf332c24af10214a3140b5" resolved "https://registry.yarnpkg.com/prop-types/-/prop-types-15.8.1.tgz#67d87bf1a694f48435cf332c24af10214a3140b5"
integrity sha512-oj87CgZICdulUohogVAR7AjlC0327U4el4L6eAvOqCeudMDVU0NThNaV+b9Df4dXgSP1gXMTnPdhfe/2qDH5cg== integrity sha512-oj87CgZICdulUohogVAR7AjlC0327U4el4L6eAvOqCeudMDVU0NThNaV+b9Df4dXgSP1gXMTnPdhfe/2qDH5cg==
...@@ -8653,6 +8726,16 @@ punycode@^2.1.0, punycode@^2.1.1, punycode@^2.3.1: ...@@ -8653,6 +8726,16 @@ punycode@^2.1.0, punycode@^2.1.1, punycode@^2.3.1:
resolved "https://registry.yarnpkg.com/punycode/-/punycode-2.3.1.tgz#027422e2faec0b25e1549c3e1bd8309b9133b6e5" resolved "https://registry.yarnpkg.com/punycode/-/punycode-2.3.1.tgz#027422e2faec0b25e1549c3e1bd8309b9133b6e5"
integrity sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg== integrity sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==
   
purgecss@^7.0.2:
version "7.0.2"
resolved "https://registry.yarnpkg.com/purgecss/-/purgecss-7.0.2.tgz#b7dccc3ead65a4301eed98e014793719a511c633"
integrity sha512-4Ku8KoxNhOWi9X1XJ73XY5fv+I+hhTRedKpGs/2gaBKU8ijUiIKF/uyyIyh7Wo713bELSICF5/NswjcuOqYouQ==
dependencies:
commander "^12.1.0"
glob "^11.0.0"
postcss "^8.4.47"
postcss-selector-parser "^6.1.2"
q@^1.1.2: q@^1.1.2:
version "1.5.1" version "1.5.1"
resolved "https://registry.yarnpkg.com/q/-/q-1.5.1.tgz#7e32f75b41381291d04611f1bf14109ac00651d7" resolved "https://registry.yarnpkg.com/q/-/q-1.5.1.tgz#7e32f75b41381291d04611f1bf14109ac00651d7"
...@@ -8772,6 +8855,14 @@ react-dom@^18.3.1: ...@@ -8772,6 +8855,14 @@ react-dom@^18.3.1:
loose-envify "^1.1.0" loose-envify "^1.1.0"
scheduler "^0.23.2" scheduler "^0.23.2"
   
react-draggable@^4.0.3, react-draggable@^4.4.5:
version "4.4.6"
resolved "https://registry.yarnpkg.com/react-draggable/-/react-draggable-4.4.6.tgz#63343ee945770881ca1256a5b6fa5c9f5983fe1e"
integrity sha512-LtY5Xw1zTPqHkVmtM3X8MUOxNDOUhv/khTgBgrUvwaS064bwVvxT+q5El0uUFNx5IEPKXuRejr7UqLwBIg5pdw==
dependencies:
clsx "^1.1.1"
prop-types "^15.8.1"
react-error-boundary@^4.1.2: react-error-boundary@^4.1.2:
version "4.1.2" version "4.1.2"
resolved "https://registry.yarnpkg.com/react-error-boundary/-/react-error-boundary-4.1.2.tgz#bc750ad962edb8b135d6ae922c046051eb58f289" resolved "https://registry.yarnpkg.com/react-error-boundary/-/react-error-boundary-4.1.2.tgz#bc750ad962edb8b135d6ae922c046051eb58f289"
...@@ -8784,6 +8875,18 @@ react-error-overlay@^6.0.11: ...@@ -8784,6 +8875,18 @@ react-error-overlay@^6.0.11:
resolved "https://registry.yarnpkg.com/react-error-overlay/-/react-error-overlay-6.0.11.tgz#92835de5841c5cf08ba00ddd2d677b6d17ff9adb" resolved "https://registry.yarnpkg.com/react-error-overlay/-/react-error-overlay-6.0.11.tgz#92835de5841c5cf08ba00ddd2d677b6d17ff9adb"
integrity sha512-/6UZ2qgEyH2aqzYZgQPxEnz33NJ2gNsnHA2o5+o4wW9bLM/JYQitNP9xPhsXwC08hMMovfGe/8retsdDsczPRg== integrity sha512-/6UZ2qgEyH2aqzYZgQPxEnz33NJ2gNsnHA2o5+o4wW9bLM/JYQitNP9xPhsXwC08hMMovfGe/8retsdDsczPRg==
   
react-grid-layout@^1.5.0:
version "1.5.0"
resolved "https://registry.yarnpkg.com/react-grid-layout/-/react-grid-layout-1.5.0.tgz#b6cc9412b58cf8226aebc0df7673d6fa782bdee2"
integrity sha512-WBKX7w/LsTfI99WskSu6nX2nbJAUD7GD6nIXcwYLyPpnslojtmql2oD3I2g5C3AK8hrxIarYT8awhuDIp7iQ5w==
dependencies:
clsx "^2.0.0"
fast-equals "^4.0.3"
prop-types "^15.8.1"
react-draggable "^4.4.5"
react-resizable "^3.0.5"
resize-observer-polyfill "^1.5.1"
react-i18next@^15.0.0: react-i18next@^15.0.0:
version "15.1.4" version "15.1.4"
resolved "https://registry.yarnpkg.com/react-i18next/-/react-i18next-15.1.4.tgz#65c03c31a5e42202000652e163f22f23a9306a60" resolved "https://registry.yarnpkg.com/react-i18next/-/react-i18next-15.1.4.tgz#65c03c31a5e42202000652e163f22f23a9306a60"
...@@ -8830,6 +8933,14 @@ react-refresh@^0.14.2: ...@@ -8830,6 +8933,14 @@ react-refresh@^0.14.2:
resolved "https://registry.yarnpkg.com/react-refresh/-/react-refresh-0.14.2.tgz#3833da01ce32da470f1f936b9d477da5c7028bf9" resolved "https://registry.yarnpkg.com/react-refresh/-/react-refresh-0.14.2.tgz#3833da01ce32da470f1f936b9d477da5c7028bf9"
integrity sha512-jCvmsr+1IUSMUyzOkRcvnVbX3ZYC6g9TDrDbFuFmRDq7PD4yaGbLKNQL6k2jnArV8hjYxh7hVhAZB6s9HDGpZA== integrity sha512-jCvmsr+1IUSMUyzOkRcvnVbX3ZYC6g9TDrDbFuFmRDq7PD4yaGbLKNQL6k2jnArV8hjYxh7hVhAZB6s9HDGpZA==
   
react-resizable@^3.0.5:
version "3.0.5"
resolved "https://registry.yarnpkg.com/react-resizable/-/react-resizable-3.0.5.tgz#362721f2efbd094976f1780ae13f1ad7739786c1"
integrity sha512-vKpeHhI5OZvYn82kXOs1bC8aOXktGU5AmKAgaZS4F5JPburCtbmDPqE7Pzp+1kN4+Wb81LlF33VpGwWwtXem+w==
dependencies:
prop-types "15.x"
react-draggable "^4.0.3"
react-router-dom@^6.23.1: react-router-dom@^6.23.1:
version "6.28.0" version "6.28.0"
resolved "https://registry.yarnpkg.com/react-router-dom/-/react-router-dom-6.28.0.tgz#f73ebb3490e59ac9f299377062ad1d10a9f579e6" resolved "https://registry.yarnpkg.com/react-router-dom/-/react-router-dom-6.28.0.tgz#f73ebb3490e59ac9f299377062ad1d10a9f579e6"
...@@ -9123,6 +9234,11 @@ reselect@^5.1.0: ...@@ -9123,6 +9234,11 @@ reselect@^5.1.0:
resolved "https://registry.yarnpkg.com/reselect/-/reselect-5.1.1.tgz#c766b1eb5d558291e5e550298adb0becc24bb72e" resolved "https://registry.yarnpkg.com/reselect/-/reselect-5.1.1.tgz#c766b1eb5d558291e5e550298adb0becc24bb72e"
integrity sha512-K/BG6eIky/SBpzfHZv/dd+9JBFiS4SWV7FIujVyJRux6e45+73RaUHXLmIR1f7WOMaQ0U1km6qwklRQxpJJY0w== integrity sha512-K/BG6eIky/SBpzfHZv/dd+9JBFiS4SWV7FIujVyJRux6e45+73RaUHXLmIR1f7WOMaQ0U1km6qwklRQxpJJY0w==
   
resize-observer-polyfill@^1.5.1:
version "1.5.1"
resolved "https://registry.yarnpkg.com/resize-observer-polyfill/-/resize-observer-polyfill-1.5.1.tgz#0e9020dd3d21024458d4ebd27e23e40269810464"
integrity sha512-LwZrotdHOo12nQuZlHEmtuXdqGoOD0OhaxopaNFxWzInpEgaLWoVuAMbTzixuosCx2nEG58ngzW3vxdWoxIgdg==
resolve-cwd@^3.0.0: resolve-cwd@^3.0.0:
version "3.0.0" version "3.0.0"
resolved "https://registry.yarnpkg.com/resolve-cwd/-/resolve-cwd-3.0.0.tgz#0f0075f1bb2544766cf73ba6a6e2adfebcb13f2d" resolved "https://registry.yarnpkg.com/resolve-cwd/-/resolve-cwd-3.0.0.tgz#0f0075f1bb2544766cf73ba6a6e2adfebcb13f2d"
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment