Compare commits
46 Commits
v0.10.3-et
...
v0.10.3-et
Author | SHA1 | Date | |
---|---|---|---|
![]() |
915e3564f8 | ||
![]() |
1570ca5485 | ||
![]() |
b94b782547 | ||
![]() |
90328a5b19 | ||
![]() |
b42eb07a2f | ||
![]() |
131bfaaece | ||
![]() |
b759d5d5fb | ||
![]() |
003e9da792 | ||
![]() |
908271060b | ||
![]() |
08cd427084 | ||
![]() |
73a1d952b1 | ||
![]() |
1d5511421d | ||
![]() |
b925c63171 | ||
![]() |
6faebaf9df | ||
![]() |
c698f57395 | ||
![]() |
9adc13e722 | ||
![]() |
a04b24a5d5 | ||
![]() |
cd1ca7c039 | ||
![]() |
86b4987b7f | ||
![]() |
a7cf647669 | ||
![]() |
80d40d2fb5 | ||
![]() |
b19e961a35 | ||
![]() |
08f5f8ebd2 | ||
![]() |
1edf196049 | ||
![]() |
1f66b4d14a | ||
![]() |
cec5b0af9a | ||
![]() |
2b0e1e7c0e | ||
![]() |
a613a88232 | ||
![]() |
7afce71bef | ||
![]() |
fe4ba22a03 | ||
![]() |
eb35d9e122 | ||
![]() |
fa79fecc9d | ||
![]() |
61366b3792 | ||
![]() |
b55033d983 | ||
![]() |
b1f42988c8 | ||
![]() |
ef05b366c3 | ||
![]() |
b3d52e7d23 | ||
![]() |
d1c4250b46 | ||
![]() |
8d44077b24 | ||
![]() |
44e8b82412 | ||
![]() |
791ae2c869 | ||
![]() |
ee3753466a | ||
![]() |
b7dc703157 | ||
![]() |
2eca0dcc33 | ||
![]() |
d2219c1667 | ||
![]() |
132ea6f97f |
4
.github/workflows/workflow.yml
vendored
4
.github/workflows/workflow.yml
vendored
@@ -25,10 +25,6 @@ jobs:
|
||||
cache: yarn
|
||||
- name: Install dependencies
|
||||
run: yarn install --immutable --network-timeout=300000
|
||||
- name: Set version into manifest.json
|
||||
run: |
|
||||
TAG=$(git describe --tags --abbrev=0 || echo "latest")
|
||||
sed -i "s|\"icons\"|\"version\": \"$TAG\",\\n \"icons\"|g" public/manifest.json
|
||||
- name: Build
|
||||
run: yarn build --base=${{ env.base_path }}
|
||||
- uses: actions/upload-artifact@v4
|
||||
|
115
README.md
115
README.md
@@ -1,4 +1,16 @@
|
||||
# Synapse Admin UI [](https://github.com/Awesome-Technologies/synapse-admin/blob/master/LICENSE)
|
||||
<p align="center">
|
||||
<img alt="Synapse Admin Logo" src="./public/images/logo.webp" height="140" />
|
||||
<h3 align="center">
|
||||
Synapse Admin<br>
|
||||
<a href="https://matrix.to/#/#synapse-admin:etke.cc">
|
||||
<img alt="Community room" src="https://img.shields.io/badge/room-community_room-green?logo=matrix&label=%23synapse-admin%3Aetke.cc">
|
||||
</a><br>
|
||||
<img alt="License" src="https://img.shields.io/github/license/etkecc/synapse-admin">
|
||||
</h3>
|
||||
<p align="center">Manager your Synapse homeserver with ease</p>
|
||||
</p>
|
||||
|
||||
---
|
||||
|
||||

|
||||
|
||||
@@ -11,6 +23,7 @@ This project is built using [react-admin](https://marmelab.com/react-admin/).
|
||||
* [Changes](#changes)
|
||||
* [Development](#development)
|
||||
* [Configuration](#configuration)
|
||||
* [Prefilling login form](#prefilling-login-form)
|
||||
* [Restricting available homeserver](#restricting-available-homeserver)
|
||||
* [Protecting appservice managed users](#protecting-appservice-managed-users)
|
||||
* [Adding custom menu items](#adding-custom-menu-items)
|
||||
@@ -23,7 +36,7 @@ This project is built using [react-admin](https://marmelab.com/react-admin/).
|
||||
* [Steps for 1)](#steps-for-1)
|
||||
* [Steps for 2)](#steps-for-2)
|
||||
* [Steps for 3)](#steps-for-3)
|
||||
* [Serving Synapse-Admin on a different path](#serving-synapse-admin-on-a-different-path)
|
||||
* [Serving Synapse Admin on a different path](#serving-synapse-admin-on-a-different-path)
|
||||
* [Development](#development-1)
|
||||
|
||||
<!-- vim-markdown-toc -->
|
||||
@@ -54,8 +67,9 @@ The following changes are already implemented:
|
||||
* [Fix redirect URL after user creation](https://github.com/etkecc/synapse-admin/pull/16)
|
||||
* [Display actual Synapse errors](https://github.com/etkecc/synapse-admin/pull/17)
|
||||
* [Fix base_url being undefined on unsuccessful login](https://github.com/etkecc/synapse-admin/pull/18)
|
||||
* [Put the version into manifest.json](https://github.com/Awesome-Technologies/synapse-admin/issues/507) (CI only)
|
||||
* [Federation page improvements](https://github.com/Awesome-Technologies/synapse-admin/pull/583) (using theme colors)
|
||||
* [Put the version into manifest.json](https://github.com/Awesome-Technologies/synapse-admin/issues/507) (later replaced
|
||||
with a proper manifest.json generation on build)
|
||||
* [Federation page improvements](https://github.com/Awesome-Technologies/synapse-admin/pull/583) (using icons)
|
||||
* [Add UI option to block deleted rooms from being rejoined](https://github.com/etkecc/synapse-admin/pull/26)
|
||||
* [Fix required fields check on Bulk registration CSV upload](https://github.com/etkecc/synapse-admin/pull/32)
|
||||
* [Fix requests with invalid MXIDs on Bulk registration](https://github.com/etkecc/synapse-admin/pull/33)
|
||||
@@ -72,6 +86,14 @@ The following changes are already implemented:
|
||||
* [Add user profile to the top menu](https://github.com/etkecc/synapse-admin/pull/80)
|
||||
* [Enable visual customization](https://github.com/etkecc/synapse-admin/pull/81)
|
||||
* [Fix room state events display](https://github.com/etkecc/synapse-admin/pull/100)
|
||||
* [Sanitize CSV on import](https://github.com/etkecc/synapse-admin/pull/101)
|
||||
* Allow setting version using `SYNAPSE_ADMIN_VERSION` environment variable on build (if git is not available)
|
||||
* [Add option to control user's experimental features](https://github.com/etkecc/synapse-admin/pull/111)
|
||||
* [Add random password generation on user create/edit form](https://github.com/etkecc/synapse-admin/pull/123)
|
||||
* [Add option to set user's rate limits](https://github.com/etkecc/synapse-admin/pull/125)
|
||||
* [Support configuration via /.well-known/matrix/client](https://github.com/etkecc/synapse-admin/pull/126)
|
||||
* [Prevent accidental user overwrites](https://github.com/etkecc/synapse-admin/pull/139)
|
||||
* [Allow providing login form details via GET params](https://github.com/etkecc/synapse-admin/pull/140)
|
||||
|
||||
_the list will be updated as new changes are added_
|
||||
|
||||
@@ -88,7 +110,15 @@ After that open `http://localhost:5173` in your browser, login using the followi
|
||||
|
||||
## Configuration
|
||||
|
||||
You can use `config.json` file to configure synapse-admin
|
||||
You can use `config.json` file to configure Synapse Admin instance,
|
||||
and `/.well-known/matrix/client` file to provide Synapse Admin configuration specifically for your homeserver.
|
||||
In the latter case, any instance of Synapse Admin will automatically pick up the configuration from the homeserver.
|
||||
Note that configuration inside the `/.well-known/matrix/client` file should go under the `cc.etke.synapse-admin` key,
|
||||
and it will override the configuration from the `config.json` file.
|
||||
|
||||
In case you use [spantaleev/matrix-docker-ansible-deploy](https://github.com/spantaleev/matrix-docker-ansible-deploy) or
|
||||
[etkecc/ansible](https://github.com/etkecc/ansible),
|
||||
configuration will be automatically added to the `/.well-known/matrix/client` file.
|
||||
|
||||
The `config.json` can be injected into a Docker container using a bind mount.
|
||||
|
||||
@@ -101,6 +131,17 @@ services:
|
||||
...
|
||||
```
|
||||
|
||||
### Prefilling login form
|
||||
|
||||
You can prefill `username` and `homeserver` fields on the login page using GET parameters, example:
|
||||
|
||||
```
|
||||
https://matrix.example.com/synapse-admin/?username=admin&server=matrix.example.com
|
||||
```
|
||||
|
||||
That way `username` and `homeserver` fields will be pre-filled with `admin` and `https://matrix.example.com` respectively.
|
||||
|
||||
|
||||
### Restricting available homeserver
|
||||
|
||||
You can restrict the homeserver(s), so that the user can no longer define it himself.
|
||||
@@ -109,7 +150,17 @@ Edit `config.json` to restrict either to a single homeserver:
|
||||
|
||||
```json
|
||||
{
|
||||
"restrictBaseUrl": "https://your-matrixs-erver.example.com"
|
||||
"restrictBaseUrl": "https://matrix.example.com"
|
||||
}
|
||||
```
|
||||
|
||||
similar for `/.well-known/matrix/client`:
|
||||
|
||||
```json
|
||||
{
|
||||
"cc.etke.synapse-admin": {
|
||||
"restrictBaseUrl": "https://matrix.example.com"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
@@ -121,6 +172,16 @@ or to a list of homeservers:
|
||||
}
|
||||
```
|
||||
|
||||
similar for `/.well-known/matrix/client`:
|
||||
|
||||
```json
|
||||
{
|
||||
"cc.etke.synapse-admin": {
|
||||
"restrictBaseUrl": ["https://your-first-matrix-server.example.com", "https://your-second-matrix-server.example.com"]
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### Protecting appservice managed users
|
||||
|
||||
To avoid accidental adjustments of appservice-managed users (e.g., puppets created by a bridge) and breaking the bridge,
|
||||
@@ -134,6 +195,16 @@ Example for [mautrix-telegram](https://github.com/mautrix/telegram)
|
||||
}
|
||||
```
|
||||
|
||||
similar for `/.well-known/matrix/client`:
|
||||
|
||||
```json
|
||||
{
|
||||
"cc.etke.synapse-admin": {
|
||||
"asManagedUsers": ["^@telegram_[a-zA-Z0-9]+:example\\.com$"]
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### Adding custom menu items
|
||||
|
||||
You can add custom menu items to the main menu by providing a `menu` array in the `config.json`.
|
||||
@@ -150,13 +221,29 @@ You can add custom menu items to the main menu by providing a `menu` array in th
|
||||
}
|
||||
```
|
||||
|
||||
similar for `/.well-known/matrix/client`:
|
||||
|
||||
```json
|
||||
{
|
||||
"cc.etke.synapse-admin": {
|
||||
"menu": [
|
||||
{
|
||||
"label": "Contact support",
|
||||
"icon": "SupportAgent",
|
||||
"url": "https://github.com/etkecc/synapse-admin/issues"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Where `icon` is one of the [preloaded icons](./src/components/icons.ts)
|
||||
|
||||
### Providing support URL
|
||||
|
||||
**Deprecated**: use `menu` config option described above. Automatically migrated to the `menu` if the `supportURL` is present.
|
||||
|
||||
~~Synapse-Admin provides a support link in the main menu - `Contact support`. By default, the link points to the GitHub issues page of the project. You can change this link by providing a `supportURL` in the `config.json`.~~
|
||||
~~Synapse Admin provides a support link in the main menu - `Contact support`. By default, the link points to the GitHub issues page of the project. You can change this link by providing a `supportURL` in the `config.json`.~~
|
||||
|
||||
```json
|
||||
{
|
||||
@@ -164,6 +251,16 @@ Where `icon` is one of the [preloaded icons](./src/components/icons.ts)
|
||||
}
|
||||
```
|
||||
|
||||
similar for `/.well-known/matrix/client`:
|
||||
|
||||
```json
|
||||
{
|
||||
"cc.etke.synapse-admin": {
|
||||
"supportURL": "https://example.com/support"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## Usage
|
||||
|
||||
### Supported Synapse
|
||||
@@ -243,7 +340,7 @@ You have three options:
|
||||
|
||||
- browse to http://localhost:8080
|
||||
|
||||
### Serving Synapse-Admin on a different path
|
||||
### Serving Synapse Admin on a different path
|
||||
|
||||
The path prefix where synapse-admin is served can only be changed during the build step.
|
||||
|
||||
@@ -251,7 +348,7 @@ If you downloaded the source code, use `yarn build --base=/my-prefix` to set a p
|
||||
|
||||
If you want to build your own Docker container, use the `BASE_PATH` argument.
|
||||
|
||||
We do not support directly changing the path where Synapse-Admin is served in the pre-built Docker container. Instead please use a reverse proxy if you need to move Synapse-Admin to a different base path. If you want to serve multiple applications with different paths on the same domain, you need a reverse proxy anyway.
|
||||
We do not support directly changing the path where Synapse Admin is served in the pre-built Docker container. Instead please use a reverse proxy if you need to move Synapse Admin to a different base path. If you want to serve multiple applications with different paths on the same domain, you need a reverse proxy anyway.
|
||||
|
||||
Example for Traefik:
|
||||
|
||||
|
@@ -4,17 +4,14 @@
|
||||
<meta charset="utf-8" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
||||
<meta name="theme-color" content="#000000" />
|
||||
<meta
|
||||
name="description"
|
||||
content="Synapse-Admin"
|
||||
/>
|
||||
<meta name="description" content="Synapse Admin" />
|
||||
<!--
|
||||
manifest.json provides metadata used when your web app is installed on a
|
||||
user's mobile device or desktop. See https://developers.google.com/web/fundamentals/web-app-manifest/
|
||||
-->
|
||||
<link rel="manifest" href="./manifest.json" />
|
||||
<link rel="shortcut icon" href="./favicon.ico" />
|
||||
<title>Synapse-Admin</title>
|
||||
<title>Synapse Admin</title>
|
||||
<style>
|
||||
body {
|
||||
margin: 0;
|
||||
|
30
package.json
30
package.json
@@ -13,21 +13,21 @@
|
||||
"devDependencies": {
|
||||
"@eslint/js": "^9.13.0",
|
||||
"@testing-library/dom": "^10.0.0",
|
||||
"@testing-library/jest-dom": "^6.6.2",
|
||||
"@testing-library/jest-dom": "^6.6.3",
|
||||
"@testing-library/react": "^16.0.0",
|
||||
"@testing-library/user-event": "^14.5.2",
|
||||
"@types/jest": "^29.5.14",
|
||||
"@types/lodash": "^4.17.12",
|
||||
"@types/node": "^22.7.9",
|
||||
"@types/lodash": "^4.17.13",
|
||||
"@types/node": "^22.8.7",
|
||||
"@types/papaparse": "^5.3.15",
|
||||
"@types/react": "^18.3.12",
|
||||
"@typescript-eslint/eslint-plugin": "^8.11.0",
|
||||
"@typescript-eslint/parser": "^8.11.0",
|
||||
"@typescript-eslint/parser": "^8.13.0",
|
||||
"@vitejs/plugin-react": "^4.3.3",
|
||||
"eslint": "^9.13.0",
|
||||
"eslint": "^9.14.0",
|
||||
"eslint-config-prettier": "^9.1.0",
|
||||
"eslint-plugin-import": "^2.31.0",
|
||||
"eslint-plugin-jsx-a11y": "^6.10.1",
|
||||
"eslint-plugin-jsx-a11y": "^6.10.2",
|
||||
"eslint-plugin-prettier": "^5.2.1",
|
||||
"eslint-plugin-unused-imports": "^4.1.4",
|
||||
"eslint-plugin-yaml": "^1.0.3",
|
||||
@@ -39,7 +39,7 @@
|
||||
"ts-jest": "^29.2.5",
|
||||
"ts-node": "^10.9.2",
|
||||
"typescript": "^5.6.3",
|
||||
"typescript-eslint": "^8.11.0",
|
||||
"typescript-eslint": "^8.13.0",
|
||||
"vite": "^5.4.10",
|
||||
"vite-plugin-version-mark": "^0.1.2"
|
||||
},
|
||||
@@ -49,26 +49,26 @@
|
||||
"@haleos/ra-language-german": "^1.0.0",
|
||||
"@haxqer/ra-language-chinese": "^4.16.2",
|
||||
"@mui/icons-material": "^6.1.5",
|
||||
"@mui/material": "^6.1.5",
|
||||
"@mui/material": "^6.1.6",
|
||||
"@mui/utils": "^5.16.6",
|
||||
"@tanstack/react-query": "^5.59.15",
|
||||
"@tanstack/react-query": "^5.59.20",
|
||||
"history": "^5.3.0",
|
||||
"lodash": "^4.17.21",
|
||||
"papaparse": "^5.4.1",
|
||||
"ra-core": "^5.3.0",
|
||||
"ra-i18n-polyglot": "^5.3.0",
|
||||
"ra-language-english": "^5.3.0",
|
||||
"ra-core": "^5.3.2",
|
||||
"ra-i18n-polyglot": "^5.3.2",
|
||||
"ra-language-english": "^5.3.2",
|
||||
"ra-language-farsi": "^5.0.0",
|
||||
"ra-language-french": "^5.3.0",
|
||||
"ra-language-french": "^5.3.3",
|
||||
"ra-language-italian": "^3.13.1",
|
||||
"ra-language-russian": "^4.14.2",
|
||||
"react": "^18.3.1",
|
||||
"react-admin": "^5.3.0",
|
||||
"react-admin": "^5.3.3",
|
||||
"react-dom": "^18.3.1",
|
||||
"react-hook-form": "^7.53.1",
|
||||
"react-is": "^18.3.1",
|
||||
"react-router": "^6.26.2",
|
||||
"react-router-dom": "^6.27.0"
|
||||
"react-router-dom": "^6.28.0"
|
||||
},
|
||||
"scripts": {
|
||||
"start": "vite serve",
|
||||
|
Binary file not shown.
Before Width: | Height: | Size: 1.1 KiB After Width: | Height: | Size: 4.2 KiB |
BIN
public/images/logo.webp
Normal file
BIN
public/images/logo.webp
Normal file
Binary file not shown.
After Width: | Height: | Size: 16 KiB |
@@ -1,15 +0,0 @@
|
||||
{
|
||||
"short_name": "Synapse-Admin",
|
||||
"name": "Synapse-Admin",
|
||||
"icons": [
|
||||
{
|
||||
"src": "favicon.ico",
|
||||
"sizes": "64x64 32x32 24x24 16x16",
|
||||
"type": "image/x-icon"
|
||||
}
|
||||
],
|
||||
"start_url": ".",
|
||||
"display": "standalone",
|
||||
"theme_color": "#000000",
|
||||
"background_color": "#ffffff"
|
||||
}
|
@@ -1,18 +1,6 @@
|
||||
import { createContext, useContext } from "react";
|
||||
|
||||
interface AppContextType {
|
||||
restrictBaseUrl: string | string[];
|
||||
asManagedUsers: string[];
|
||||
supportURL: string;
|
||||
menu: MenuItem[];
|
||||
}
|
||||
|
||||
interface MenuItem {
|
||||
label: string;
|
||||
icon: string;
|
||||
url: string;
|
||||
}
|
||||
import { Config } from "./components/config";
|
||||
|
||||
export const AppContext = createContext({});
|
||||
|
||||
export const useAppContext = () => useContext(AppContext) as AppContextType;
|
||||
export const useAppContext = () => useContext(AppContext) as Config;
|
||||
|
@@ -1,7 +1,8 @@
|
||||
import { AppBar, TitlePortal, InspectorButton, Confirm, Layout, Logout, Menu, useLogout, UserMenu } from "react-admin";
|
||||
import { CheckForApplicationUpdate, AppBar, TitlePortal, InspectorButton, Confirm, Layout, Logout, Menu, useLogout, UserMenu } from "react-admin";
|
||||
import { LoginMethod } from "../pages/LoginPage";
|
||||
import { useEffect, useState, Suspense } from "react";
|
||||
import { Icons, DefaultIcon } from "./icons";
|
||||
import { ClearConfig } from "./config";
|
||||
|
||||
const AdminUserMenu = () => {
|
||||
const [open, setOpen] = useState(false);
|
||||
@@ -21,8 +22,7 @@ const AdminUserMenu = () => {
|
||||
|
||||
const handleDialogClose = () => {
|
||||
setOpen(false);
|
||||
localStorage.removeItem("access_token");
|
||||
localStorage.removeItem("login_type");
|
||||
ClearConfig();
|
||||
window.location.reload();
|
||||
};
|
||||
|
||||
@@ -99,5 +99,6 @@ export const AdminLayout = ({ children }) => (
|
||||
},
|
||||
}}>
|
||||
{children}
|
||||
<CheckForApplicationUpdate />
|
||||
</Layout>
|
||||
);
|
||||
|
95
src/components/ExperimentalFeatures.tsx
Normal file
95
src/components/ExperimentalFeatures.tsx
Normal file
@@ -0,0 +1,95 @@
|
||||
import { useRecordContext } from "react-admin";
|
||||
import { useNotify } from "react-admin";
|
||||
import { useDataProvider } from "react-admin";
|
||||
import { useState, useEffect } from "react";
|
||||
import { Stack, Switch, Typography } from "@mui/material";
|
||||
import { ExperimentalFeaturesModel, SynapseDataProvider } from "../synapse/dataProvider";
|
||||
|
||||
const experimentalFeaturesMap = {
|
||||
msc3881: "enable remotely toggling push notifications for another client",
|
||||
msc3575: "enable experimental sliding sync support",
|
||||
};
|
||||
const ExperimentalFeatureRow = (props: { featureKey: string, featureValue: boolean, updateFeature: (feature_name: string, feature_value: boolean) => void}) => {
|
||||
const featureKey = props.featureKey;
|
||||
const featureValue = props.featureValue;
|
||||
const featureDescription = experimentalFeaturesMap[featureKey] ?? "";
|
||||
const [checked, setChecked] = useState(featureValue);
|
||||
|
||||
const handleChange = (event: React.ChangeEvent<HTMLInputElement>) => {
|
||||
setChecked(event.target.checked);
|
||||
props.updateFeature(featureKey, event.target.checked);
|
||||
};
|
||||
|
||||
return <Stack
|
||||
direction="row"
|
||||
spacing={2}
|
||||
alignItems="start"
|
||||
sx={{
|
||||
padding: 2,
|
||||
}}
|
||||
>
|
||||
<Switch checked={checked} onChange={handleChange} />
|
||||
<Stack>
|
||||
<Typography
|
||||
variant="subtitle1"
|
||||
sx={{
|
||||
fontWeight: "medium",
|
||||
color: "text.primary"
|
||||
}}
|
||||
>
|
||||
{featureKey}
|
||||
</Typography>
|
||||
<Typography
|
||||
variant="body2"
|
||||
color="text.secondary"
|
||||
>
|
||||
{featureDescription}
|
||||
</Typography>
|
||||
</Stack>
|
||||
</Stack>
|
||||
}
|
||||
|
||||
export const ExperimentalFeaturesList = () => {
|
||||
const record = useRecordContext();
|
||||
const notify = useNotify();
|
||||
const dataProvider = useDataProvider() as SynapseDataProvider;
|
||||
const [features, setFeatures] = useState({});
|
||||
if (!record) {
|
||||
return null;
|
||||
}
|
||||
|
||||
useEffect(() => {
|
||||
const fetchFeatures = async () => {
|
||||
const features = await dataProvider.getFeatures(record.id);
|
||||
setFeatures(features);
|
||||
}
|
||||
|
||||
fetchFeatures();
|
||||
}, []);
|
||||
|
||||
const updateFeature = async (feature_name: string, feature_value: boolean) => {
|
||||
const updatedFeatures = {...features, [feature_name]: feature_value} as ExperimentalFeaturesModel;
|
||||
setFeatures(updatedFeatures);
|
||||
const reponse = await dataProvider.updateFeatures(record.id, updatedFeatures);
|
||||
notify("ra.notification.updated", {
|
||||
messageArgs: { smart_count: 1 },
|
||||
type: "success",
|
||||
});
|
||||
};
|
||||
|
||||
return <>
|
||||
<Stack
|
||||
direction="column"
|
||||
spacing={1}
|
||||
>
|
||||
{Object.keys(features).map((featureKey: string) =>
|
||||
<ExperimentalFeatureRow
|
||||
key={featureKey}
|
||||
featureKey={featureKey}
|
||||
featureValue={features[featureKey]}
|
||||
updateFeature={updateFeature}
|
||||
/>
|
||||
)}
|
||||
</Stack>
|
||||
</>
|
||||
}
|
@@ -1,4 +1,4 @@
|
||||
import { Box, Link, Typography } from "@mui/material";
|
||||
import { Avatar, Box, Link, Typography } from "@mui/material";
|
||||
import { useEffect, useState } from "react";
|
||||
|
||||
const Footer = () => {
|
||||
@@ -22,16 +22,17 @@ const Footer = () => {
|
||||
borderColor: '#ddd',
|
||||
p: 1,
|
||||
}}>
|
||||
<Typography variant="body2">
|
||||
<Typography variant="body2" component="div">
|
||||
<Avatar src="./images/logo.webp" sx={{ width: "1rem", height: "1rem", display: "inline-block", verticalAlign: "sub" }} />
|
||||
<Link sx={{ color: "#888", textDecoration: 'none' }} href="https://github.com/etkecc/synapse-admin" target="_blank">
|
||||
Synapse-Admin
|
||||
Synapse Admin
|
||||
</Link> <Link href={`https://github.com/etkecc/synapse-admin/releases/tag/`+version} target="_blank">
|
||||
<span style={{ fontWeight: 'bold', color: "#000" }}>{version}</span>
|
||||
</Link> <Link sx={{ color: "#888", textDecoration: 'none' }} href="https://etke.cc/?utm_source=synapse-admin&utm_medium=footer&utm_campaign=synapse-admin" target="_blank">
|
||||
by etke.cc
|
||||
</Link> <Link sx={{ color: "#888", textDecoration: 'none' }} href="https://github.com/awesome-technologies/synapse-admin" target="_blank">
|
||||
(originally developed by Awesome Technologies Innovationslabor GmbH)
|
||||
</Link>
|
||||
(originally developed by Awesome Technologies Innovationslabor GmbH).
|
||||
</Link> <Link sx={{ fontWeight: 'bold', color: "#000", textDecoration: 'none' }} href="https://matrix.to/#/#synapse-admin:etke.cc" target="_blank">#synapse-admin:etke.cc</Link>
|
||||
</Typography>
|
||||
</Box>
|
||||
);
|
||||
|
@@ -121,6 +121,7 @@ const FilePicker = () => {
|
||||
|
||||
const verifyCsv = ({ data, meta, errors }: ParseResult<ImportLine>, { setValues, setStats, setError }) => {
|
||||
/* First, verify the presence of required fields */
|
||||
meta.fields = meta.fields?.map(f => f.trim().toLowerCase());
|
||||
const missingFields = expectedFields.filter(eF => !meta.fields?.find(mF => eF === mF));
|
||||
|
||||
if (missingFields.length > 0) {
|
||||
@@ -147,6 +148,15 @@ const FilePicker = () => {
|
||||
};
|
||||
|
||||
const errorMessages = errors.map(e => e.message);
|
||||
// sanitize the data first
|
||||
data = data.map(line => {
|
||||
const newLine = {} as ImportLine;
|
||||
for (const [key, value] of Object.entries(line)) {
|
||||
newLine[key.trim().toLowerCase()] = value;
|
||||
}
|
||||
return newLine;
|
||||
});
|
||||
// process the data
|
||||
data.forEach((line, idx) => {
|
||||
if (line.user_type === undefined || line.user_type === "") {
|
||||
stats.user_types.default++;
|
||||
@@ -173,6 +183,7 @@ const FilePicker = () => {
|
||||
line[f] = true; // we need true booleans instead of strings
|
||||
} else {
|
||||
if (line[f] !== "false" && line[f] !== "") {
|
||||
console.log("invalid value", line[f], "for field " + f + " in row " + idx);
|
||||
errorMessages.push(
|
||||
translate("import_users.error.invalid_value", {
|
||||
field: f,
|
||||
|
@@ -13,7 +13,7 @@ const LoginFormBox = styled(Box)(({ theme }) => ({
|
||||
backgroundSize: "cover",
|
||||
|
||||
[`& .card`]: {
|
||||
maxWidth: "30rem",
|
||||
width: "30rem",
|
||||
marginTop: "6rem",
|
||||
marginBottom: "6rem",
|
||||
},
|
||||
|
95
src/components/UserRateLimits.tsx
Normal file
95
src/components/UserRateLimits.tsx
Normal file
@@ -0,0 +1,95 @@
|
||||
import { Stack, Typography } from "@mui/material";
|
||||
import { useEffect, useState } from "react";
|
||||
import { useDataProvider, useNotify, useRecordContext, useTranslate } from "react-admin";
|
||||
import { TextField } from "@mui/material";
|
||||
import { useFormContext } from "react-hook-form";
|
||||
|
||||
const RateLimitRow = ({ limit, value, updateRateLimit }: { limit: string, value: any, updateRateLimit: (limit: string, value: any) => void }) => {
|
||||
const translate = useTranslate();
|
||||
|
||||
const handleChange = (event: React.ChangeEvent<HTMLInputElement>) => {
|
||||
const value = parseInt(event.target.value);
|
||||
if (isNaN(value)) {
|
||||
updateRateLimit(limit, null);
|
||||
return;
|
||||
}
|
||||
updateRateLimit(limit, value);
|
||||
};
|
||||
|
||||
return <Stack
|
||||
spacing={1}
|
||||
alignItems="start"
|
||||
sx={{
|
||||
padding: 2,
|
||||
}}
|
||||
>
|
||||
<TextField
|
||||
id="outlined-number"
|
||||
type="number"
|
||||
value={value}
|
||||
onChange={handleChange}
|
||||
slotProps={{
|
||||
inputLabel: {
|
||||
shrink: true,
|
||||
},
|
||||
}}
|
||||
label={translate(`resources.users.limits.${limit}`)}
|
||||
/>
|
||||
<Stack>
|
||||
<Typography
|
||||
variant="body2"
|
||||
color="text.secondary"
|
||||
>
|
||||
{translate(`resources.users.limits.${limit}_text`)}
|
||||
</Typography>
|
||||
</Stack>
|
||||
</Stack>
|
||||
}
|
||||
|
||||
export const UserRateLimits = () => {
|
||||
const translate = useTranslate();
|
||||
const notify = useNotify();
|
||||
const record = useRecordContext();
|
||||
const form = useFormContext();
|
||||
const dataProvider = useDataProvider();
|
||||
const [rateLimits, setRateLimits] = useState({
|
||||
messages_per_second: "", // we are setting string here to make the number field empty by default, null is prohibited by the field validation
|
||||
burst_count: "",
|
||||
});
|
||||
|
||||
if (!record) {
|
||||
return null;
|
||||
}
|
||||
|
||||
useEffect(() => {
|
||||
const fetchRateLimits = async () => {
|
||||
const rateLimits = await dataProvider.getRateLimits(record.id);
|
||||
if (Object.keys(rateLimits).length > 0) {
|
||||
setRateLimits(rateLimits);
|
||||
}
|
||||
}
|
||||
|
||||
fetchRateLimits();
|
||||
}, []);
|
||||
|
||||
const updateRateLimit = async (limit: string, value: any) => {
|
||||
let updatedRateLimits = { ...rateLimits, [limit]: value };
|
||||
setRateLimits(updatedRateLimits);
|
||||
form.setValue(`rates.${limit}`, value, { shouldDirty: true });
|
||||
};
|
||||
|
||||
return <>
|
||||
<Stack
|
||||
direction="column"
|
||||
>
|
||||
{Object.keys(rateLimits).map((limit: string) =>
|
||||
<RateLimitRow
|
||||
key={limit}
|
||||
limit={limit}
|
||||
value={rateLimits[limit]}
|
||||
updateRateLimit={updateRateLimit}
|
||||
/>
|
||||
)}
|
||||
</Stack>
|
||||
</>
|
||||
};
|
87
src/components/config.ts
Normal file
87
src/components/config.ts
Normal file
@@ -0,0 +1,87 @@
|
||||
import storage from "../storage";
|
||||
|
||||
export interface Config {
|
||||
restrictBaseUrl: string | string[];
|
||||
asManagedUsers: string[];
|
||||
supportURL: string;
|
||||
menu: MenuItem[];
|
||||
}
|
||||
|
||||
export interface MenuItem {
|
||||
label: string;
|
||||
icon: string;
|
||||
url: string;
|
||||
}
|
||||
|
||||
export const WellKnownKey = "cc.etke.synapse-admin";
|
||||
|
||||
export const LoadConfig = (context: Config): Config => {
|
||||
if (context.restrictBaseUrl) {
|
||||
storage.setItem("restrict_base_url", JSON.stringify(context.restrictBaseUrl));
|
||||
}
|
||||
|
||||
if (context.asManagedUsers) {
|
||||
storage.setItem("as_managed_users", JSON.stringify(context.asManagedUsers));
|
||||
}
|
||||
|
||||
let menu: MenuItem[] = [];
|
||||
if (context.menu) {
|
||||
menu = context.menu;
|
||||
}
|
||||
if (context.supportURL) {
|
||||
const migratedSupportURL = {
|
||||
label: "Contact support",
|
||||
icon: "SupportAgent",
|
||||
url: context.supportURL,
|
||||
};
|
||||
console.warn("supportURL config option is deprecated. Please, use the menu option instead. Automatically migrated to the new menu option:", migratedSupportURL);
|
||||
menu.push(migratedSupportURL as MenuItem);
|
||||
}
|
||||
if (menu.length > 0) {
|
||||
storage.setItem("menu", JSON.stringify(menu));
|
||||
}
|
||||
|
||||
// below we try to calculate "final" config, which will contain values from context and already set values in storage
|
||||
// because LoadConfig could be called multiple times to get config from different sources
|
||||
let finalRestrictBaseUrl: string | string[] = "";
|
||||
try {
|
||||
finalRestrictBaseUrl = JSON.parse(storage.getItem("restrict_base_url") || "");
|
||||
if (Array.isArray(finalRestrictBaseUrl) && finalRestrictBaseUrl.length == 1) {
|
||||
finalRestrictBaseUrl = finalRestrictBaseUrl[0];
|
||||
}
|
||||
} catch (e) {}
|
||||
let finalAsManagedUsers: string[] = [];
|
||||
try {
|
||||
finalAsManagedUsers = JSON.parse(storage.getItem("as_managed_users") || "");
|
||||
} catch (e) {}
|
||||
|
||||
let finalMenu: MenuItem[] = [];
|
||||
try {
|
||||
finalMenu = JSON.parse(storage.getItem("menu") || "");
|
||||
} catch (e) {}
|
||||
|
||||
return {
|
||||
restrictBaseUrl: finalRestrictBaseUrl,
|
||||
asManagedUsers: finalAsManagedUsers,
|
||||
supportURL: storage.getItem("support_url") || "",
|
||||
menu: finalMenu,
|
||||
} as Config;
|
||||
|
||||
}
|
||||
|
||||
|
||||
export const ClearConfig = () => {
|
||||
// config.json
|
||||
storage.removeItem("restrict_base_url");
|
||||
storage.removeItem("as_managed_users");
|
||||
storage.removeItem("support_url");
|
||||
storage.removeItem("menu");
|
||||
|
||||
// session
|
||||
storage.removeItem("home_server");
|
||||
storage.removeItem("base_url");
|
||||
storage.removeItem("user_id");
|
||||
storage.removeItem("device_id");
|
||||
storage.removeItem("access_token");
|
||||
storage.removeItem("login_type");
|
||||
}
|
@@ -55,7 +55,7 @@ const de: SynapseTranslationMessages = {
|
||||
},
|
||||
users: {
|
||||
invalid_user_id: "Lokaler Anteil der Matrix Benutzer-ID ohne Homeserver.",
|
||||
tabs: { sso: "SSO" },
|
||||
tabs: { sso: "SSO", experimental: "Experimentell", limits: "Rate Limits" },
|
||||
},
|
||||
rooms: {
|
||||
details: "Raumdetails",
|
||||
@@ -184,13 +184,25 @@ const de: SynapseTranslationMessages = {
|
||||
erase_text: "Das bedeutet, dass die von dem/den Benutzer(n) gesendeten Nachrichten für alle, die zum Zeitpunkt des Sendens im Raum waren, sichtbar bleiben, aber für Benutzer, die dem Raum später beitreten, nicht sichtbar sind.",
|
||||
erase_admin_error: "Das Löschen des eigenen Benutzers ist nicht erlaubt.",
|
||||
modify_managed_user_error: "Das Ändern eines vom System verwalteten Benutzers ist nicht zulässig.",
|
||||
username_available: "Benutzername verfügbar",
|
||||
},
|
||||
action: {
|
||||
erase: "Lösche Benutzerdaten",
|
||||
erase_avatar: "Avatar löschen",
|
||||
delete_media: "Alle von dem/den Benutzer(n) hochgeladenen Medien löschen",
|
||||
redact_events: "Schwärzen aller vom Benutzer gesendeten Ereignisse (-s)",
|
||||
generate_password: "Passwort generieren",
|
||||
overwrite_title: "Warnung!",
|
||||
overwrite_content: "Dieser Benutzername ist bereits vergeben. Sind Sie sicher, dass Sie den vorhandenen Benutzer überschreiben möchten?",
|
||||
overwrite_cancel: "Abbrechen",
|
||||
overwrite_confirm: "Überschreiben",
|
||||
},
|
||||
limits: {
|
||||
messages_per_second: "Nachrichten pro Sekunde",
|
||||
messages_per_second_text: "Die Anzahl der Aktionen, die in einer Sekunde durchgeführt werden können.",
|
||||
burst_count: "Burst-Anzahl",
|
||||
burst_count_text: "Die Anzahl der Aktionen, die vor der Begrenzung durchgeführt werden können.",
|
||||
}
|
||||
},
|
||||
rooms: {
|
||||
name: "Raum |||| Räume",
|
||||
|
@@ -25,7 +25,11 @@ const en: SynapseTranslationMessages = {
|
||||
},
|
||||
users: {
|
||||
invalid_user_id: "Localpart of a Matrix user-id without homeserver.",
|
||||
tabs: { sso: "SSO" },
|
||||
tabs: {
|
||||
sso: "SSO",
|
||||
experimental: "Experimental",
|
||||
limits: "Rate Limits",
|
||||
},
|
||||
},
|
||||
rooms: {
|
||||
details: "Room details",
|
||||
@@ -153,13 +157,25 @@ const en: SynapseTranslationMessages = {
|
||||
erase_text: "This means messages sent by the user(-s) will still be visible by anyone who was in the room when these messages were sent, but hidden from users joining the room afterward.",
|
||||
erase_admin_error: "Deleting own user is not allowed.",
|
||||
modify_managed_user_error: "Modifying a system-managed user is not allowed.",
|
||||
username_available: "Username is available",
|
||||
},
|
||||
action: {
|
||||
erase: "Erase user data",
|
||||
erase_avatar: "Erase avatar",
|
||||
delete_media: "Delete all media uploaded by the user(-s)",
|
||||
redact_events: "Redact all events sent by the user(-s)",
|
||||
generate_password: "Generate password",
|
||||
overwrite_title: "Warning!",
|
||||
overwrite_content: "This username is already taken. Are you sure that you want to overwrite the existing user?",
|
||||
overwrite_cancel: "Cancel",
|
||||
overwrite_confirm: "Overwrite",
|
||||
},
|
||||
limits: {
|
||||
messages_per_second: "Messages per second",
|
||||
messages_per_second_text: "The number of actions that can be performed in a second.",
|
||||
burst_count: "Burst count",
|
||||
burst_count_text: "How many actions that can be performed before being limited.",
|
||||
}
|
||||
},
|
||||
rooms: {
|
||||
name: "Room |||| Rooms",
|
||||
|
@@ -24,7 +24,7 @@ const fa: SynapseTranslationMessages = {
|
||||
},
|
||||
users: {
|
||||
invalid_user_id: "بخش محلی یک شناسه کاربری ماتریکس بدون سرور خانگی.",
|
||||
tabs: { sso: "SSO" },
|
||||
tabs: { sso: "SSO", experimental: "تجربی", limits: "محدودیت ها" },
|
||||
},
|
||||
rooms: {
|
||||
tabs: {
|
||||
@@ -149,13 +149,25 @@ const fa: SynapseTranslationMessages = {
|
||||
erase_text: "وهذا يعني أن الرسائل المرسلة من قبل المستخدم (المستخدمين) ستظل مرئية من قبل أي شخص كان في الغرفة عند إرسال هذه الرسائل، ولكنها مخفية عن المستخدمين الذين ينضمون إلى الغرفة بعد ذلك.",
|
||||
erase_admin_error: "حذف المستخدم الخاص غير مسموح به.",
|
||||
modify_managed_user_error: "لا يُسمح بتغيير المستخدم الذي يديره النظام.",
|
||||
username_available: "نام کاربری موجود",
|
||||
},
|
||||
action: {
|
||||
erase: "پاک کردن اطلاعات کاربر",
|
||||
erase_avatar: "محو الصورة الرمزية",
|
||||
delete_media: "حذف جميع الوسائط التي تم تحميلها بواسطة المستخدم (المستخدمين)",
|
||||
redact_events: "تنقيح جميع الأحداث المرسلة من قبل المستخدم (-s)",
|
||||
generate_password: "توليد رمز عبور",
|
||||
overwrite_title: "هشدار!",
|
||||
overwrite_content: "این نام کاربری قبلا استفاده شده است. آیا مطمئن هستید که می خواهید کاربر موجود را بازنویسی کنید؟",
|
||||
overwrite_cancel: "انصراف",
|
||||
overwrite_confirm: "بازنویسی",
|
||||
},
|
||||
limits: {
|
||||
messages_per_second: "پیام در ثانیه",
|
||||
messages_per_second_text: "تعداد عملیاتی که می تواند در یک ثانیه انجام شود.",
|
||||
burst_count: "تعداد پیچیدگی",
|
||||
burst_count_text: "تعداد عملیاتی که می تواند قبل از محدودیت انجام شود.",
|
||||
}
|
||||
},
|
||||
rooms: {
|
||||
name: "اتاق |||| اتاق ها",
|
||||
@@ -207,6 +219,11 @@ const fa: SynapseTranslationMessages = {
|
||||
title: "حذف اتاق",
|
||||
content:
|
||||
"آیا مطمئن هستید که می خواهید اتاق را حذف کنید؟ این قابل بازگشت نیست. همه پیام ها و رسانه های مشترک در اتاق از سرور حذف می شوند!",
|
||||
fields: {
|
||||
block: "حذف",
|
||||
},
|
||||
success: "اتاق با موفقیت حذف شد.",
|
||||
failure: "خطایی رخ داده است.",
|
||||
},
|
||||
},
|
||||
},
|
||||
|
@@ -24,7 +24,7 @@ const fr: SynapseTranslationMessages = {
|
||||
},
|
||||
users: {
|
||||
invalid_user_id: "Partie locale d'un identifiant utilisateur Matrix sans le nom du serveur d’accueil.",
|
||||
tabs: { sso: "Authentification unique" },
|
||||
tabs: { sso: "Authentification unique", experimental: "Expérimental", limits: "Limites" },
|
||||
},
|
||||
rooms: {
|
||||
tabs: {
|
||||
@@ -151,13 +151,25 @@ const fr: SynapseTranslationMessages = {
|
||||
erase_text: "Cela signifie que les messages envoyés par le(s) utilisateur(s) seront toujours visibles par toute personne qui se trouvait dans la salle au moment où ces messages ont été envoyés, mais qu'ils seront cachés aux utilisateurs qui rejoindront la salle par la suite.",
|
||||
erase_admin_error: "La suppression de son propre utilisateur n'est pas autorisée.",
|
||||
modify_managed_user_error: "La modification d'un utilisateur géré par le système n'est pas autorisée.",
|
||||
username_available: "Nom d'utilisateur disponible",
|
||||
},
|
||||
action: {
|
||||
erase: "Effacer les données de l'utilisateur",
|
||||
erase_avatar: "Effacer l'avatar",
|
||||
delete_media: "Supprimer tous les médias téléchargés par le(s) utilisateur(s)",
|
||||
redact_events: "Expurger tous les événements envoyés par l'utilisateur(-s)",
|
||||
generate_password: "Générer un mot de passe",
|
||||
overwrite_title: "Attention !",
|
||||
overwrite_content: "Ce nom d'utilisateur est déjà pris. Êtes-vous sûr de vouloir écraser l'utilisateur existant ?",
|
||||
overwrite_cancel: "Annuler",
|
||||
overwrite_confirm: "Écraser",
|
||||
},
|
||||
limits: {
|
||||
messages_per_second: "Messages par seconde",
|
||||
messages_per_second_text: "Le nombre d'actions que l'utilisateur peut effectuer par seconde.",
|
||||
burst_count: "Compteur de pics",
|
||||
burst_count_text: "Le nombre d'actions que l'utilisateur peut effectuer avant d'être limité.",
|
||||
}
|
||||
},
|
||||
rooms: {
|
||||
name: "Salon |||| Salons",
|
||||
|
14
src/i18n/index.d.ts
vendored
14
src/i18n/index.d.ts
vendored
@@ -22,7 +22,7 @@ interface SynapseTranslationMessages extends TranslationMessages {
|
||||
};
|
||||
users: {
|
||||
invalid_user_id: string;
|
||||
tabs: { sso: string };
|
||||
tabs: { sso: string; experimental: string; limits: string; };
|
||||
};
|
||||
rooms: {
|
||||
details?: string; // TODO: fa, fr, it, zh
|
||||
@@ -149,12 +149,24 @@ interface SynapseTranslationMessages extends TranslationMessages {
|
||||
erase_text: string;
|
||||
erase_admin_error: string;
|
||||
modify_managed_user_error: string;
|
||||
username_available: string;
|
||||
};
|
||||
action: {
|
||||
erase: string;
|
||||
erase_avatar: string;
|
||||
delete_media: string;
|
||||
redact_events: string;
|
||||
generate_password: string;
|
||||
overwrite_title: string;
|
||||
overwrite_content: string;
|
||||
overwrite_cancel: string;
|
||||
overwrite_confirm: string;
|
||||
};
|
||||
limits: {
|
||||
messages_per_second: string;
|
||||
messages_per_second_text: string;
|
||||
burst_count: string;
|
||||
burst_count_text: string;
|
||||
};
|
||||
};
|
||||
rooms: {
|
||||
|
@@ -24,7 +24,7 @@ const it: SynapseTranslationMessages = {
|
||||
},
|
||||
users: {
|
||||
invalid_user_id: "ID utente non valido su questo homeserver.",
|
||||
tabs: { sso: "SSO" },
|
||||
tabs: { sso: "SSO", experimental: "Sperimentale", limits: "Limiti" },
|
||||
},
|
||||
rooms: {
|
||||
tabs: {
|
||||
@@ -150,13 +150,25 @@ const it: SynapseTranslationMessages = {
|
||||
erase_text: "Ciò significa che i messaggi inviati dall'utente (o dagli utenti) saranno ancora visibili da chiunque si trovasse nella stanza al momento dell'invio, ma saranno nascosti agli utenti che si uniranno alla stanza in seguito.",
|
||||
erase_admin_error: "Non è consentito eliminare il proprio utente.",
|
||||
modify_managed_user_error: "La modifica di un utente gestito dal sistema non è consentita.",
|
||||
username_available: "Nome utente disponibile",
|
||||
},
|
||||
action: {
|
||||
erase: "Cancella i dati dell'utente",
|
||||
erase_avatar: "Cancella l'avatar dell'utente",
|
||||
delete_media: "Elimina tutti i media caricati dall'utente(-s)",
|
||||
redact_events: "Ridurre tutti gli eventi inviati dall'utente(-s)",
|
||||
generate_password: "Genera password",
|
||||
overwrite_title: "Attenzione!",
|
||||
overwrite_content: "Questo nome utente è già stato utilizzato. Sei sicuro di voler sovrascrivere l'utente esistente?",
|
||||
overwrite_cancel: "Annulla",
|
||||
overwrite_confirm: "Sovrascrivi",
|
||||
},
|
||||
limits: {
|
||||
messages_per_second: "Messaggi al secondo",
|
||||
messages_per_second_text: "Il numero di azioni che l'utente può eseguire al secondo.",
|
||||
burst_count: "Burst-conteggio",
|
||||
burst_count_text: "Il numero di azioni che l'utente può eseguire prima di essere limitato.",
|
||||
}
|
||||
},
|
||||
rooms: {
|
||||
name: "Stanza |||| Stanze",
|
||||
|
@@ -50,7 +50,7 @@ const ru: SynapseTranslationMessages = {
|
||||
},
|
||||
users: {
|
||||
invalid_user_id: "Локальная часть ID пользователя Matrix без адреса домашнего сервера.",
|
||||
tabs: { sso: "SSO" },
|
||||
tabs: { sso: "SSO", experimental: "Экспериментальные", limits: "Ограничения" },
|
||||
},
|
||||
rooms: {
|
||||
details: "Данные комнаты",
|
||||
@@ -187,14 +187,26 @@ const ru: SynapseTranslationMessages = {
|
||||
erase_text: "Это означает, что сообщения, отправленные пользователем (-ами), будут по-прежнему видны всем, кто находился в комнате в момент их отправки, но будут скрыты от пользователей, присоединившихся к комнате после этого.",
|
||||
erase_admin_error: "Удаление собственного пользователя запрещено.",
|
||||
modify_managed_user_error: "Изменение пользователя, управляемого системой, не допускается.",
|
||||
username_available: "Имя пользователя доступно",
|
||||
},
|
||||
action: {
|
||||
erase: "Удалить данные пользователя",
|
||||
erase_avatar: "Удалить аватар",
|
||||
delete_media: "Удаление всех медиафайлов, загруженных пользователем (-ами)",
|
||||
redact_events: "Удаление всех событий, отправленных пользователем (-ами)",
|
||||
generate_password: "Сгенерировать пароль",
|
||||
overwrite_title: "Предупреждение!",
|
||||
overwrite_content: "Это имя пользователя уже занято. Вы уверены, что хотите перезаписать существующего пользователя?",
|
||||
overwrite_cancel: "Отмена",
|
||||
overwrite_confirm: "Перезаписать",
|
||||
},
|
||||
},
|
||||
limits: {
|
||||
messages_per_second: "Сообщений в секунду",
|
||||
messages_per_second_text: "Количество действий, которые могут быть выполнены в секунду.",
|
||||
burst_count: "Burst-счётчик",
|
||||
burst_count_text: "Количество действий, которые могут быть выполнены до ограничения.",
|
||||
}
|
||||
},
|
||||
rooms: {
|
||||
name: "Комната |||| Комнаты",
|
||||
fields: {
|
||||
|
@@ -52,7 +52,7 @@ const zh: SynapseTranslationMessages = {
|
||||
},
|
||||
users: {
|
||||
invalid_user_id: "必须要是一个有效的 Matrix 用户 ID ,例如 @user_id:homeserver",
|
||||
tabs: { sso: "SSO" },
|
||||
tabs: { sso: "SSO", experimental: "实验性", limits: "限制" },
|
||||
},
|
||||
rooms: {
|
||||
tabs: {
|
||||
@@ -174,13 +174,25 @@ const zh: SynapseTranslationMessages = {
|
||||
erase_text: "这意味着用户发送的信息对于发送信息时在房间内的任何人来说都是可见的,但对于之后加入房间的用户来说则是隐藏的。",
|
||||
erase_admin_error: "不允许删除自己的用户",
|
||||
modify_managed_user_error: "不允许修改系统管理的用户。",
|
||||
username_available: "用户名可用",
|
||||
},
|
||||
action: {
|
||||
erase: "抹除用户信息",
|
||||
erase_avatar: "抹掉头像",
|
||||
delete_media: "删除用户上传的所有媒体",
|
||||
redact_events: "重新编辑用户(-s)发送的所有事件",
|
||||
generate_password: "生成密码",
|
||||
overwrite_title: "警告!",
|
||||
overwrite_content: "这个用户名已经被占用。您确定要覆盖现有的用户吗?",
|
||||
overwrite_cancel: "取消",
|
||||
overwrite_confirm: "覆盖",
|
||||
},
|
||||
limits: {
|
||||
messages_per_second: "每秒消息数",
|
||||
messages_per_second_text: "每秒可以执行的操作数。",
|
||||
burst_count: "Burst-计数",
|
||||
burst_count_text: "在限制之前可以执行的操作数。",
|
||||
}
|
||||
},
|
||||
rooms: {
|
||||
name: "房间",
|
||||
|
@@ -3,38 +3,47 @@ import React from "react";
|
||||
import { createRoot } from "react-dom/client";
|
||||
|
||||
import App from "./App";
|
||||
import { AppContext, MenuItem } from "./AppContext";
|
||||
import { Config, WellKnownKey, LoadConfig } from "./components/config";
|
||||
import { AppContext } from "./AppContext";
|
||||
import storage from "./storage";
|
||||
|
||||
fetch("config.json")
|
||||
.then(res => res.json())
|
||||
.then(props => {
|
||||
if (props.asManagedUsers) {
|
||||
storage.setItem("as_managed_users", JSON.stringify(props.asManagedUsers));
|
||||
}
|
||||
// load config.json
|
||||
let props: Config = {
|
||||
restrictBaseUrl: [],
|
||||
asManagedUsers: [],
|
||||
supportURL: "",
|
||||
menu: [],
|
||||
};
|
||||
try {
|
||||
const resp = await fetch("config.json");
|
||||
const configJSON = await resp.json();
|
||||
console.log("Loaded config.json", configJSON);
|
||||
props = LoadConfig(configJSON as Config);
|
||||
} catch (e) {
|
||||
console.error(e);
|
||||
}
|
||||
|
||||
let menu: MenuItem[] = [];
|
||||
if (props.menu) {
|
||||
menu = props.menu;
|
||||
}
|
||||
if (props.supportURL) {
|
||||
const migratedSupportURL = {
|
||||
label: "Contact support",
|
||||
icon: "SupportAgent",
|
||||
url: props.supportURL,
|
||||
};
|
||||
console.warn("supportURL config option is deprecated. Please, use the menu option instead. Automatically migrated to the new menu option:", migratedSupportURL);
|
||||
menu.push(migratedSupportURL as MenuItem);
|
||||
}
|
||||
if (menu.length > 0) {
|
||||
storage.setItem("menu", JSON.stringify(menu));
|
||||
// if home_server is set, try to load https://home_server/.well-known/matrix/client
|
||||
const homeserver = storage.getItem("home_server");
|
||||
if (homeserver) {
|
||||
try {
|
||||
const resp = await fetch(`https://${homeserver}/.well-known/matrix/client`);
|
||||
const configWK = await resp.json();
|
||||
if (!configWK[WellKnownKey]) {
|
||||
console.log(`Loaded https://${homeserver}.well-known/matrix/client, but it doesn't contain ${WellKnownKey} key, skipping`, configWK);
|
||||
} else {
|
||||
console.log(`Loaded https://${homeserver}.well-known/matrix/client`, configWK);
|
||||
props = LoadConfig(configWK[WellKnownKey] as Config);
|
||||
}
|
||||
} catch (e) {
|
||||
console.log(`https://${homeserver}/.well-known/matrix/client not found, skipping`, e);
|
||||
}
|
||||
}
|
||||
|
||||
return createRoot(document.getElementById("root")).render(
|
||||
createRoot(document.getElementById("root")).render(
|
||||
<React.StrictMode>
|
||||
<AppContext.Provider value={props}>
|
||||
<App />
|
||||
</AppContext.Provider>
|
||||
</React.StrictMode>
|
||||
)
|
||||
});
|
||||
);
|
||||
|
@@ -1,6 +1,5 @@
|
||||
import { useState, useEffect } from "react";
|
||||
|
||||
import LockIcon from "@mui/icons-material/Lock";
|
||||
import { Avatar, Box, Button, Card, CardActions, CircularProgress, MenuItem, Select, Tab, Tabs, Typography } from "@mui/material";
|
||||
import {
|
||||
Form,
|
||||
@@ -34,7 +33,7 @@ const LoginPage = () => {
|
||||
const login = useLogin();
|
||||
const notify = useNotify();
|
||||
const { restrictBaseUrl } = useAppContext();
|
||||
const allowSingleBaseUrl = typeof restrictBaseUrl === "string";
|
||||
const allowSingleBaseUrl = typeof restrictBaseUrl === "string" && restrictBaseUrl !== "";
|
||||
const allowMultipleBaseUrls =
|
||||
Array.isArray(restrictBaseUrl) &&
|
||||
restrictBaseUrl.length > 0 &&
|
||||
@@ -97,6 +96,9 @@ const LoginPage = () => {
|
||||
|
||||
const handleSubmit = auth => {
|
||||
setLoading(true);
|
||||
const cleanUrl = window.location.href.replace(window.location.search, "");
|
||||
window.history.replaceState({}, "", cleanUrl);
|
||||
|
||||
login(auth).catch(error => {
|
||||
setLoading(false);
|
||||
notify(
|
||||
@@ -167,6 +169,22 @@ const LoginPage = () => {
|
||||
.catch(() => setSSOBaseUrl(""));
|
||||
}, [formData.base_url, form]);
|
||||
|
||||
useEffect(() => {
|
||||
const params = new URLSearchParams(window.location.search);
|
||||
const username = params.get("username");
|
||||
let serverURL = params.get("server");
|
||||
if (username) {
|
||||
form.setValue("username", username);
|
||||
}
|
||||
if (serverURL) {
|
||||
const isFullUrl = serverURL.match(/^(http|https):\/\//);
|
||||
if (!isFullUrl) {
|
||||
serverURL = `https://${serverURL}`;
|
||||
}
|
||||
form.setValue("base_url", serverURL);
|
||||
}
|
||||
}, [window.location.search]);
|
||||
|
||||
return (
|
||||
<>
|
||||
<Tabs
|
||||
@@ -187,10 +205,10 @@ const LoginPage = () => {
|
||||
source="username"
|
||||
label="ra.auth.username"
|
||||
autoComplete="username"
|
||||
disabled={loading || !supportPassAuth}
|
||||
onBlur={handleUsernameChange}
|
||||
resettable
|
||||
validate={required()}
|
||||
{...(loading || !supportPassAuth ? { disabled: true } : {})}
|
||||
/>
|
||||
</Box>
|
||||
<Box>
|
||||
@@ -199,7 +217,7 @@ const LoginPage = () => {
|
||||
label="ra.auth.password"
|
||||
type="password"
|
||||
autoComplete="current-password"
|
||||
disabled={loading || !supportPassAuth}
|
||||
{...(loading || !supportPassAuth ? { disabled: true } : {})}
|
||||
resettable
|
||||
validate={required()}
|
||||
/>
|
||||
@@ -210,7 +228,7 @@ const LoginPage = () => {
|
||||
<TextInput
|
||||
source="accessToken"
|
||||
label="synapseadmin.auth.access_token"
|
||||
disabled={loading}
|
||||
{...(loading ? { disabled: true } : {})}
|
||||
resettable
|
||||
validate={required()}
|
||||
/>
|
||||
@@ -222,7 +240,7 @@ const LoginPage = () => {
|
||||
label="synapseadmin.auth.base_url"
|
||||
select={allowMultipleBaseUrls}
|
||||
autoComplete="url"
|
||||
disabled={loading}
|
||||
{...(loading ? { disabled: true } : {})}
|
||||
readOnly={allowSingleBaseUrl}
|
||||
resettable={allowAnyBaseUrl}
|
||||
validate={[required(), validateBaseUrl]}
|
||||
@@ -249,9 +267,7 @@ const LoginPage = () => {
|
||||
{loading ? (
|
||||
<CircularProgress size={25} thickness={2} />
|
||||
) : (
|
||||
<Avatar className="icon">
|
||||
<LockIcon />
|
||||
</Avatar>
|
||||
<Avatar sx={{ width: "120px", height: "120px" }} src="./images/logo.webp"/>
|
||||
)}
|
||||
</Box>
|
||||
<Box className="hint">{translate("synapseadmin.auth.welcome")}</Box>
|
||||
|
@@ -7,9 +7,12 @@ import NotificationsIcon from "@mui/icons-material/Notifications";
|
||||
import PermMediaIcon from "@mui/icons-material/PermMedia";
|
||||
import PersonPinIcon from "@mui/icons-material/PersonPin";
|
||||
import SettingsInputComponentIcon from "@mui/icons-material/SettingsInputComponent";
|
||||
import ScienceIcon from "@mui/icons-material/Science";
|
||||
import LockClockIcon from '@mui/icons-material/LockClock';
|
||||
import ViewListIcon from "@mui/icons-material/ViewList";
|
||||
import { useEffect, useState } from "react";
|
||||
import { Alert, ownerDocument } from "@mui/material";
|
||||
import { Alert, Typography } from "@mui/material";
|
||||
import { useTheme } from "@mui/material/styles";
|
||||
import {
|
||||
ArrayInput,
|
||||
ArrayField,
|
||||
@@ -54,10 +57,13 @@ import {
|
||||
useNotify,
|
||||
Identifier,
|
||||
ToolbarClasses,
|
||||
RaRecord,
|
||||
ImageInput,
|
||||
ImageField,
|
||||
FunctionField,
|
||||
useDataProvider,
|
||||
Confirm,
|
||||
useCreate,
|
||||
useRedirect,
|
||||
} from "react-admin";
|
||||
import { Link } from "react-router-dom";
|
||||
|
||||
@@ -68,6 +74,11 @@ import { ServerNoticeButton, ServerNoticeBulkButton } from "../components/Server
|
||||
import { DATE_FORMAT } from "../components/date";
|
||||
import { DeviceRemoveButton } from "../components/devices";
|
||||
import { MediaIDField, ProtectMediaButton, QuarantineMediaButton } from "../components/media";
|
||||
import { generateRandomPassword } from "../synapse/synapse";
|
||||
import { useFormContext } from "react-hook-form";
|
||||
import { ExperimentalFeaturesList } from "../components/ExperimentalFeatures";
|
||||
import { UserRateLimits } from "../components/UserRateLimits";
|
||||
import { User, UsernameAvailabilityResult } from "../synapse/dataProvider";
|
||||
|
||||
const choices_medium = [
|
||||
{ id: "email", name: "resources.users.email" },
|
||||
@@ -126,8 +137,6 @@ const UserBulkActionButtons = () => {
|
||||
const [asManagedUserIsSelected, setAsManagedUserIsSelected] = useState(false);
|
||||
const selectedIds = record.selectedIds;
|
||||
const ownUserId = localStorage.getItem("user_id");
|
||||
const notify = useNotify();
|
||||
const translate = useTranslate();
|
||||
|
||||
useEffect(() => {
|
||||
setOwnUserIsSelected(selectedIds.includes(ownUserId));
|
||||
@@ -209,13 +218,70 @@ const UserEditActions = () => {
|
||||
);
|
||||
};
|
||||
|
||||
export const UserCreate = (props: CreateProps) => (
|
||||
<Create
|
||||
export const UserCreate = (props: CreateProps) => {
|
||||
const dataProvider = useDataProvider();
|
||||
const translate = useTranslate();
|
||||
const redirect = useRedirect();
|
||||
const notify = useNotify();
|
||||
const theme = useTheme();
|
||||
|
||||
const [open, setOpen] = useState(false);
|
||||
const [userIsAvailable, setUserIsAvailable] = useState<boolean | undefined>();
|
||||
const [userAvailabilityEl, setUserAvailabilityEl] = useState<React.ReactElement | false>(<Typography component="span"></Typography>);
|
||||
const [formData, setFormData] = useState<Record<string, any>>({});
|
||||
const [create] = useCreate();
|
||||
|
||||
const checkAvailability = async(event: React.FocusEvent<HTMLInputElement>) => {
|
||||
const username = event.target.value;
|
||||
const result: UsernameAvailabilityResult = await dataProvider.checkUsernameAvailability(username);
|
||||
setUserIsAvailable(!!result?.available);
|
||||
if (result?.available) {
|
||||
setUserAvailabilityEl(<Typography component="span" variant="body2" sx={{ color: theme.palette.success.main }}>✔️ {translate("resources.users.helper.username_available")}</Typography>);
|
||||
} else {
|
||||
setUserAvailabilityEl(<Typography component="span" variant="body2" sx={{ color: theme.palette.warning.main }}>⚠️ {result?.error || "unknown error"}</Typography>);
|
||||
}
|
||||
};
|
||||
|
||||
const postSave = (data: Record<string, any>) => {
|
||||
setFormData(data);
|
||||
if (!userIsAvailable) {
|
||||
setOpen(true);
|
||||
return;
|
||||
}
|
||||
|
||||
create("users", { data: data }, {
|
||||
onSuccess: (resource: User) => {
|
||||
notify("ra.notification.created", { messageArgs: { smart_count: 1 } });
|
||||
redirect(() => { return `users/${resource.id}` });
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
const handleConfirm = () => {
|
||||
setOpen(false);
|
||||
updateUser();
|
||||
};
|
||||
|
||||
const handleDialogClose = () => {
|
||||
setOpen(false);
|
||||
};
|
||||
|
||||
const updateUser = () => {
|
||||
create("users", { data: formData }, {
|
||||
onSuccess: (resource: User) => {
|
||||
notify("ra.notification.updated", { messageArgs: { smart_count: 1 } });
|
||||
redirect(() => { return `users/${resource.id}` });
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
return <Create
|
||||
{...props}
|
||||
redirect={(resource: string | undefined, id: Identifier | undefined) => `${resource}/${id}`}
|
||||
>
|
||||
<SimpleForm>
|
||||
<TextInput source="id" autoComplete="off" validate={validateUser} />
|
||||
<SimpleForm
|
||||
onSubmit={postSave}
|
||||
>
|
||||
<TextInput source="id" autoComplete="off" validate={validateUser} onBlur={checkAvailability} helperText={userAvailabilityEl}/>
|
||||
<TextInput source="displayname" validate={maxLength(256)} />
|
||||
<PasswordInput source="password" autoComplete="new-password" validate={maxLength(512)} />
|
||||
<SelectInput source="user_type" choices={choices_type} translateChoice={false} resettable />
|
||||
@@ -233,16 +299,25 @@ export const UserCreate = (props: CreateProps) => (
|
||||
</SimpleFormIterator>
|
||||
</ArrayInput>
|
||||
</SimpleForm>
|
||||
<Confirm
|
||||
isOpen={open}
|
||||
title="resources.users.action.overwrite_title"
|
||||
content="resources.users.action.overwrite_content"
|
||||
onConfirm={handleConfirm}
|
||||
onClose={handleDialogClose}
|
||||
confirm="resources.users.action.overwrite_confirm"
|
||||
cancel="resources.users.action.overwrite_cancel"
|
||||
/>
|
||||
</Create>
|
||||
);
|
||||
};
|
||||
|
||||
const UserTitle = () => {
|
||||
const record = useRecordContext();
|
||||
const translate = useTranslate();
|
||||
if (!record) {
|
||||
return null;
|
||||
}
|
||||
|
||||
const translate = useTranslate();
|
||||
let username = record ? (record.displayname ? `"${record.displayname}"` : `"${record.name}"`) : ""
|
||||
if (isASManaged(record?.id)) {
|
||||
username += " 🤖";
|
||||
@@ -301,12 +376,33 @@ const UserBooleanInput = props => {
|
||||
const UserPasswordInput = props => {
|
||||
const record = useRecordContext();
|
||||
let asManagedUserIsSelected = false;
|
||||
|
||||
// Get form context to update field value
|
||||
const form = useFormContext();
|
||||
if (record) {
|
||||
asManagedUserIsSelected = isASManaged(record.id);
|
||||
}
|
||||
|
||||
const generatePassword = () => {
|
||||
const password = generateRandomPassword();
|
||||
if (record) {
|
||||
form.setValue("password", password, { shouldDirty: true });
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<PasswordInput {...props} helperText="resources.users.helper.modify_managed_user_error" disabled={asManagedUserIsSelected} />
|
||||
<>
|
||||
<PasswordInput {...props} helperText="resources.users.helper.modify_managed_user_error"
|
||||
{...(asManagedUserIsSelected ? { disabled: true } : {})}
|
||||
/>
|
||||
<Button
|
||||
variant="outlined"
|
||||
label="Generate Password"
|
||||
onClick={generatePassword}
|
||||
sx={{ marginBottom: "10px" }}
|
||||
disabled={asManagedUserIsSelected}
|
||||
/>
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
@@ -314,7 +410,11 @@ export const UserEdit = (props: EditProps) => {
|
||||
const translate = useTranslate();
|
||||
|
||||
return (
|
||||
<Edit {...props} title={<UserTitle />} actions={<UserEditActions />} mutationMode="pessimistic">
|
||||
<Edit {...props} title={<UserTitle />} actions={<UserEditActions />} mutationMode="pessimistic" queryOptions={{
|
||||
meta: {
|
||||
include: ["features"] // Tell your dataProvider to include features
|
||||
}
|
||||
}}>
|
||||
<TabbedForm toolbar={<UserEditToolbar />}>
|
||||
<FormTab label={translate("resources.users.name", { smart_count: 1 })} icon={<PersonPinIcon />}>
|
||||
<AvatarField source="avatar_src" sx={{ height: "120px", width: "120px" }} />
|
||||
@@ -448,6 +548,14 @@ export const UserEdit = (props: EditProps) => {
|
||||
</Datagrid>
|
||||
</ReferenceManyField>
|
||||
</FormTab>
|
||||
|
||||
<FormTab label="synapseadmin.users.tabs.experimental" icon={<ScienceIcon />} path="experimental">
|
||||
<ExperimentalFeaturesList />
|
||||
</FormTab>
|
||||
|
||||
<FormTab label="synapseadmin.users.tabs.limits" icon={<LockClockIcon />} path="limits">
|
||||
<UserRateLimits />
|
||||
</FormTab>
|
||||
</TabbedForm>
|
||||
</Edit>
|
||||
);
|
||||
|
@@ -3,6 +3,7 @@ import { AuthProvider, HttpError, Options, fetchUtils } from "react-admin";
|
||||
import storage from "../storage";
|
||||
import { MatrixError, displayError } from "../components/error";
|
||||
import { fetchAuthenticatedMedia } from "../utils/fetchMedia";
|
||||
import { ClearConfig } from "../components/config";
|
||||
|
||||
const authProvider: AuthProvider = {
|
||||
// called when the user attempts to log in
|
||||
@@ -154,8 +155,7 @@ const authProvider: AuthProvider = {
|
||||
} catch (err) {
|
||||
console.log("Error logging out", err);
|
||||
} finally {
|
||||
storage.removeItem("access_token");
|
||||
storage.removeItem("login_type");
|
||||
ClearConfig();
|
||||
}
|
||||
}
|
||||
},
|
||||
|
@@ -120,7 +120,8 @@ interface ExternalId {
|
||||
external_id: string;
|
||||
}
|
||||
|
||||
interface User {
|
||||
export interface User {
|
||||
id?: string;
|
||||
name: string;
|
||||
displayname?: string;
|
||||
threepids: Threepid[];
|
||||
@@ -248,9 +249,30 @@ export interface UploadMediaResult {
|
||||
content_uri: string;
|
||||
}
|
||||
|
||||
export interface ExperimentalFeaturesModel {
|
||||
features: {
|
||||
[key: string]: boolean;
|
||||
};
|
||||
}
|
||||
|
||||
export interface RateLimitsModel {
|
||||
messages_per_second?: number;
|
||||
burst_count?: number;
|
||||
}
|
||||
|
||||
export interface UsernameAvailabilityResult {
|
||||
available?: boolean;
|
||||
error?: string;
|
||||
errcode?: string;
|
||||
}
|
||||
|
||||
export interface SynapseDataProvider extends DataProvider {
|
||||
deleteMedia: (params: DeleteMediaParams) => Promise<DeleteMediaResult>;
|
||||
uploadMedia: (params: UploadMediaParams) => Promise<UploadMediaResult>;
|
||||
updateFeatures: (id: Identifier, features: ExperimentalFeaturesModel) => Promise<void>;
|
||||
getRateLimits: (id: Identifier) => Promise<RateLimitsModel>;
|
||||
setRateLimits: (id: Identifier, rateLimits: RateLimitsModel) => Promise<void>;
|
||||
checkUsernameAvailability: (username: string) => Promise<UsernameAvailabilityResult>;
|
||||
}
|
||||
|
||||
const resourceMap = {
|
||||
@@ -798,6 +820,53 @@ const baseDataProvider: SynapseDataProvider = {
|
||||
});
|
||||
return json as UploadMediaResult;
|
||||
},
|
||||
getFeatures: async (id: Identifier) => {
|
||||
const base_url = storage.getItem("base_url");
|
||||
const endpoint_url = `${base_url}/_synapse/admin/v1/experimental_features/${encodeURIComponent(returnMXID(id))}`;
|
||||
const { json } = await jsonClient(endpoint_url);
|
||||
return json.features as ExperimentalFeaturesModel;
|
||||
},
|
||||
updateFeatures: async (id: Identifier, features: ExperimentalFeaturesModel) => {
|
||||
const base_url = storage.getItem("base_url");
|
||||
const endpoint_url = `${base_url}/_synapse/admin/v1/experimental_features/${encodeURIComponent(returnMXID(id))}`;
|
||||
await jsonClient(endpoint_url, { method: "PUT", body: JSON.stringify({ features }) });
|
||||
},
|
||||
getRateLimits: async (id: Identifier) => {
|
||||
const base_url = storage.getItem("base_url");
|
||||
const endpoint_url = `${base_url}/_synapse/admin/v1/users/${encodeURIComponent(returnMXID(id))}/override_ratelimit`;
|
||||
const { json } = await jsonClient(endpoint_url);
|
||||
return json as RateLimitsModel;
|
||||
},
|
||||
setRateLimits: async (id: Identifier, rateLimits: RateLimitsModel) => {
|
||||
const filtered = Object.entries(rateLimits).
|
||||
filter(([key, value]) => value !== null && value !== undefined).
|
||||
reduce((obj, [key, value]) => {
|
||||
obj[key] = value;
|
||||
return obj;
|
||||
}, {});
|
||||
|
||||
const base_url = storage.getItem("base_url");
|
||||
const endpoint_url = `${base_url}/_synapse/admin/v1/users/${encodeURIComponent(returnMXID(id))}/override_ratelimit`;
|
||||
if (Object.keys(filtered).length === 0) {
|
||||
await jsonClient(endpoint_url, { method: "DELETE" });
|
||||
return
|
||||
}
|
||||
|
||||
await jsonClient(endpoint_url, { method: "POST", body: JSON.stringify(filtered) });
|
||||
},
|
||||
checkUsernameAvailability: async (username: string) => {
|
||||
const base_url = storage.getItem("base_url");
|
||||
const endpoint_url = `${base_url}/_synapse/admin/v1/username_available?username=${encodeURIComponent(username)}`;
|
||||
try {
|
||||
const { json } = await jsonClient(endpoint_url);
|
||||
return json as UsernameAvailabilityResult;
|
||||
} catch (error) {
|
||||
if (error instanceof HttpError) {
|
||||
return { available: false, error: error.body.error, errcode: error.body.errcode } as UsernameAvailabilityResult;
|
||||
}
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
const dataProvider = withLifecycleCallbacks(baseDataProvider, [
|
||||
@@ -806,6 +875,12 @@ const dataProvider = withLifecycleCallbacks(baseDataProvider, [
|
||||
beforeUpdate: async (params: UpdateParams<any>, dataProvider: DataProvider) => {
|
||||
const avatarFile = params.data.avatar_file?.rawFile;
|
||||
const avatarErase = params.data.avatar_erase;
|
||||
const rates = params.data.rates;
|
||||
|
||||
if (rates) {
|
||||
await dataProvider.setRateLimits(params.id, rates);
|
||||
delete params.data.rates;
|
||||
}
|
||||
|
||||
if (avatarErase) {
|
||||
params.data.avatar_url = "";
|
||||
|
@@ -91,8 +91,8 @@ export function returnMXID(input: string | Identifier): string {
|
||||
* Generate a random user password
|
||||
* @returns a new random password as string
|
||||
*/
|
||||
export function generateRandomPassword(length = 20): string {
|
||||
const characters = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz~!@-#$";
|
||||
export function generateRandomPassword(length = 64): string {
|
||||
const characters = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz~`!@#$%^&*()_-+={[}]|:;'.?/<>,";
|
||||
return Array.from(crypto.getRandomValues(new Uint32Array(length)))
|
||||
.map(x => characters[x % characters.length])
|
||||
.join("");
|
||||
|
@@ -5,13 +5,41 @@ import { defineConfig } from "vite";
|
||||
|
||||
export default defineConfig({
|
||||
base: "./",
|
||||
build: {
|
||||
target: "esnext",
|
||||
},
|
||||
plugins: [
|
||||
react(),
|
||||
vitePluginVersionMark({
|
||||
command: "git describe --tags || git rev-parse --short HEAD",
|
||||
ifMeta: true,
|
||||
ifLog: true,
|
||||
name: "Synapse Admin",
|
||||
command: 'git describe --tags || git rev-parse --short HEAD || echo "${SYNAPSE_ADMIN_VERSION:-unknown}"',
|
||||
ifMeta: false,
|
||||
ifLog: false,
|
||||
ifGlobal: true,
|
||||
outputFile: (version) => ({
|
||||
path: "manifest.json",
|
||||
content: JSON.stringify({
|
||||
name: "Synapse Admin",
|
||||
version: version,
|
||||
description: "Synapse Admin is an admin console for synapse Matrix homeserver with additional features.",
|
||||
categories: ["productivity", "utilities"],
|
||||
orientation: "landscape",
|
||||
icons: [{
|
||||
src: "favicon.ico",
|
||||
sizes: "32x32",
|
||||
type: "image/x-icon"
|
||||
},{
|
||||
src: "images/logo.webp",
|
||||
sizes: "512x512",
|
||||
type: "image/webp",
|
||||
purpose: "any maskable"
|
||||
}],
|
||||
start_url: ".",
|
||||
display: "standalone",
|
||||
theme_color: "#000000",
|
||||
background_color: "#ffffff"
|
||||
}),
|
||||
}),
|
||||
}),
|
||||
],
|
||||
});
|
||||
|
576
yarn.lock
576
yarn.lock
@@ -332,10 +332,10 @@
|
||||
dependencies:
|
||||
"@babel/helper-plugin-utils" "^7.25.7"
|
||||
|
||||
"@babel/runtime@^7.12.5", "@babel/runtime@^7.18.3", "@babel/runtime@^7.21.0", "@babel/runtime@^7.23.8", "@babel/runtime@^7.23.9", "@babel/runtime@^7.25.7", "@babel/runtime@^7.5.5", "@babel/runtime@^7.6.2", "@babel/runtime@^7.7.2", "@babel/runtime@^7.7.6", "@babel/runtime@^7.8.7":
|
||||
version "7.25.9"
|
||||
resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.25.9.tgz#65884fd6dc255a775402cc1d9811082918f4bf00"
|
||||
integrity sha512-4zpTHZ9Cm6L9L+uIqghQX8ZXg8HKFcjYO3qHoO8zTmRm6HQUJ8SSJ+KRvbMBZn0EGVlT4DRYeQ/6hjlyXBh+Kg==
|
||||
"@babel/runtime@^7.12.5", "@babel/runtime@^7.18.3", "@babel/runtime@^7.21.0", "@babel/runtime@^7.23.8", "@babel/runtime@^7.23.9", "@babel/runtime@^7.25.7", "@babel/runtime@^7.26.0", "@babel/runtime@^7.5.5", "@babel/runtime@^7.6.2", "@babel/runtime@^7.7.2", "@babel/runtime@^7.7.6", "@babel/runtime@^7.8.7":
|
||||
version "7.26.0"
|
||||
resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.26.0.tgz#8600c2f595f277c60815256418b85356a65173c1"
|
||||
integrity sha512-FDSOghenHTiToteC/QRlv2q3DhPZ/oOXTBoirfWNx1Cx3TMVcGWQtMMmQcSvb/JjpNeGzx8Pq/b4fKEJuWm1sw==
|
||||
dependencies:
|
||||
regenerator-runtime "^0.14.0"
|
||||
|
||||
@@ -658,10 +658,10 @@
|
||||
dependencies:
|
||||
eslint-visitor-keys "^3.3.0"
|
||||
|
||||
"@eslint-community/regexpp@^4.10.0", "@eslint-community/regexpp@^4.11.0":
|
||||
version "4.11.1"
|
||||
resolved "https://registry.npmjs.org/@eslint-community/regexpp/-/regexpp-4.11.1.tgz"
|
||||
integrity sha512-m4DVN9ZqskZoLU5GlWZadwDnYo3vAEydiUayB9widCl9ffWx2IvPnp6n3on5rJmziJSw9Bv+Z3ChDVdMwXCY8Q==
|
||||
"@eslint-community/regexpp@^4.10.0", "@eslint-community/regexpp@^4.12.1":
|
||||
version "4.12.1"
|
||||
resolved "https://registry.yarnpkg.com/@eslint-community/regexpp/-/regexpp-4.12.1.tgz#cfc6cffe39df390a3841cde2abccf92eaa7ae0e0"
|
||||
integrity sha512-CCZCDJuduB9OUkFkY2IgppNZMi2lBQgD2qzwXkEia16cge2pijY/aXi96CJMquDMn3nJdlPV1A5KrJEXwfLNzQ==
|
||||
|
||||
"@eslint/config-array@^0.18.0":
|
||||
version "0.18.0"
|
||||
@@ -692,10 +692,10 @@
|
||||
minimatch "^3.1.2"
|
||||
strip-json-comments "^3.1.1"
|
||||
|
||||
"@eslint/js@9.13.0", "@eslint/js@^9.13.0":
|
||||
version "9.13.0"
|
||||
resolved "https://registry.yarnpkg.com/@eslint/js/-/js-9.13.0.tgz#c5f89bcd57eb54d5d4fa8b77693e9c28dc97e547"
|
||||
integrity sha512-IFLyoY4d72Z5y/6o/BazFBezupzI/taV8sGumxTAVw3lXG9A6md1Dc34T9s1FoD/an9pJH8RHbAxsaEbBed9lA==
|
||||
"@eslint/js@9.14.0", "@eslint/js@^9.13.0":
|
||||
version "9.14.0"
|
||||
resolved "https://registry.yarnpkg.com/@eslint/js/-/js-9.14.0.tgz#2347a871042ebd11a00fd8c2d3d56a265ee6857e"
|
||||
integrity sha512-pFoEtFWCPyDOl+C6Ift+wC7Ro89otjigCf5vcuWqWgqNSQbRrpjSvdeE6ofLz4dHmyxD5f7gIdGT4+p36L6Twg==
|
||||
|
||||
"@eslint/object-schema@^2.1.4":
|
||||
version "2.1.4"
|
||||
@@ -725,17 +725,17 @@
|
||||
dependencies:
|
||||
ra-core "^4.16.2"
|
||||
|
||||
"@humanfs/core@^0.19.0":
|
||||
version "0.19.0"
|
||||
resolved "https://registry.yarnpkg.com/@humanfs/core/-/core-0.19.0.tgz#08db7a8c73bb07673d9ebd925f2dad746411fcec"
|
||||
integrity sha512-2cbWIHbZVEweE853g8jymffCA+NCMiuqeECeBBLm8dg2oFdjuGJhgN4UAbI+6v0CKbbhvtXA4qV8YR5Ji86nmw==
|
||||
"@humanfs/core@^0.19.1":
|
||||
version "0.19.1"
|
||||
resolved "https://registry.yarnpkg.com/@humanfs/core/-/core-0.19.1.tgz#17c55ca7d426733fe3c561906b8173c336b40a77"
|
||||
integrity sha512-5DyQ4+1JEUzejeK1JGICcideyfUbGixgS9jNgex5nqkW+cY7WZhxBigmieN5Qnw9ZosSNVC9KQKyb+GUaGyKUA==
|
||||
|
||||
"@humanfs/node@^0.16.5":
|
||||
version "0.16.5"
|
||||
resolved "https://registry.yarnpkg.com/@humanfs/node/-/node-0.16.5.tgz#a9febb7e7ad2aff65890fdc630938f8d20aa84ba"
|
||||
integrity sha512-KSPA4umqSG4LHYRodq31VDwKAvaTF4xmVlzM8Aeh4PlU1JQ3IG0wiA8C25d3RQ9nJyM3mBHyI53K06VVL/oFFg==
|
||||
"@humanfs/node@^0.16.6":
|
||||
version "0.16.6"
|
||||
resolved "https://registry.yarnpkg.com/@humanfs/node/-/node-0.16.6.tgz#ee2a10eaabd1131987bf0488fd9b820174cd765e"
|
||||
integrity sha512-YuI2ZHQL78Q5HbhDiBA1X4LmYdXCKCMQIfw0pw7piHJwyREFebJUvrQN4cMssyES6x+vfUbx1CIpaQUKYdQZOw==
|
||||
dependencies:
|
||||
"@humanfs/core" "^0.19.0"
|
||||
"@humanfs/core" "^0.19.1"
|
||||
"@humanwhocodes/retry" "^0.3.0"
|
||||
|
||||
"@humanwhocodes/module-importer@^1.0.1":
|
||||
@@ -743,11 +743,16 @@
|
||||
resolved "https://registry.npmjs.org/@humanwhocodes/module-importer/-/module-importer-1.0.1.tgz"
|
||||
integrity sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA==
|
||||
|
||||
"@humanwhocodes/retry@^0.3.0", "@humanwhocodes/retry@^0.3.1":
|
||||
"@humanwhocodes/retry@^0.3.0":
|
||||
version "0.3.1"
|
||||
resolved "https://registry.yarnpkg.com/@humanwhocodes/retry/-/retry-0.3.1.tgz#c72a5c76a9fbaf3488e231b13dc52c0da7bab42a"
|
||||
integrity sha512-JBxkERygn7Bv/GbN5Rv8Ul6LVknS+5Bp6RgDC/O8gEBU/yeH5Ui5C/OlWrTb6qct7LjjfT6Re2NxB0ln0yYybA==
|
||||
|
||||
"@humanwhocodes/retry@^0.4.0":
|
||||
version "0.4.1"
|
||||
resolved "https://registry.yarnpkg.com/@humanwhocodes/retry/-/retry-0.4.1.tgz#9a96ce501bc62df46c4031fbd970e3cc6b10f07b"
|
||||
integrity sha512-c7hNEllBlenFTHBky65mhq8WD2kbN9Q6gk0bTk8lSBvc554jpXSkST1iePudpt7+A/AQvuHs9EMqjHDXMY1lrA==
|
||||
|
||||
"@istanbuljs/load-nyc-config@^1.0.0":
|
||||
version "1.1.0"
|
||||
resolved "https://registry.npmjs.org/@istanbuljs/load-nyc-config/-/load-nyc-config-1.1.0.tgz"
|
||||
@@ -1001,10 +1006,10 @@
|
||||
resolved "https://registry.npmjs.org/@mui/core-downloads-tracker/-/core-downloads-tracker-5.16.7.tgz"
|
||||
integrity sha512-RtsCt4Geed2/v74sbihWzzRs+HsIQCfclHeORh5Ynu2fS4icIKozcSubwuG7vtzq2uW3fOR1zITSP84TNt2GoQ==
|
||||
|
||||
"@mui/core-downloads-tracker@^6.1.5":
|
||||
version "6.1.5"
|
||||
resolved "https://registry.yarnpkg.com/@mui/core-downloads-tracker/-/core-downloads-tracker-6.1.5.tgz#96fe5068d55fba27d90421b8265b965c203d09e2"
|
||||
integrity sha512-3J96098GrC95XsLw/TpGNMxhUOnoG9NZ/17Pfk1CrJj+4rcuolsF2RdF3XAFTu/3a/A+5ouxlSIykzYz6Ee87g==
|
||||
"@mui/core-downloads-tracker@^6.1.6":
|
||||
version "6.1.6"
|
||||
resolved "https://registry.yarnpkg.com/@mui/core-downloads-tracker/-/core-downloads-tracker-6.1.6.tgz#73d96e75689b2af922a989123149a3497c8a96fa"
|
||||
integrity sha512-nz1SlR9TdBYYPz4qKoNasMPRiGb4PaIHFkzLzhju0YVYS5QSuFF2+n7CsiHMIDcHv3piPu/xDWI53ruhOqvZwQ==
|
||||
|
||||
"@mui/icons-material@^5.15.20":
|
||||
version "5.16.7"
|
||||
@@ -1038,16 +1043,16 @@
|
||||
react-is "^18.3.1"
|
||||
react-transition-group "^4.4.5"
|
||||
|
||||
"@mui/material@^6.1.5":
|
||||
version "6.1.5"
|
||||
resolved "https://registry.yarnpkg.com/@mui/material/-/material-6.1.5.tgz#1ba8deda18564b277f37d957d523a9d2624b4b9a"
|
||||
integrity sha512-rhaxC7LnlOG8zIVYv7BycNbWkC5dlm9A/tcDUp0CuwA7Zf9B9JP6M3rr50cNKxI7Z0GIUesAT86ceVm44quwnQ==
|
||||
"@mui/material@^6.1.6":
|
||||
version "6.1.6"
|
||||
resolved "https://registry.yarnpkg.com/@mui/material/-/material-6.1.6.tgz#505d7300401f6af38426006d7fb3b8707dc10fbc"
|
||||
integrity sha512-1yvejiQ/601l5AK3uIdUlAVElyCxoqKnl7QA+2oFB/2qYPWfRwDgavW/MoywS5Y2gZEslcJKhe0s2F3IthgFgw==
|
||||
dependencies:
|
||||
"@babel/runtime" "^7.25.7"
|
||||
"@mui/core-downloads-tracker" "^6.1.5"
|
||||
"@mui/system" "^6.1.5"
|
||||
"@mui/types" "^7.2.18"
|
||||
"@mui/utils" "^6.1.5"
|
||||
"@babel/runtime" "^7.26.0"
|
||||
"@mui/core-downloads-tracker" "^6.1.6"
|
||||
"@mui/system" "^6.1.6"
|
||||
"@mui/types" "^7.2.19"
|
||||
"@mui/utils" "^6.1.6"
|
||||
"@popperjs/core" "^2.11.8"
|
||||
"@types/react-transition-group" "^4.4.11"
|
||||
clsx "^2.1.1"
|
||||
@@ -1065,13 +1070,13 @@
|
||||
"@mui/utils" "^5.16.6"
|
||||
prop-types "^15.8.1"
|
||||
|
||||
"@mui/private-theming@^6.1.5":
|
||||
version "6.1.5"
|
||||
resolved "https://registry.yarnpkg.com/@mui/private-theming/-/private-theming-6.1.5.tgz#634166d5793f6635ee2f815fb30f03342ff4df41"
|
||||
integrity sha512-FJqweqEXk0KdtTho9C2h6JEKXsOT7MAVH2Uj3N5oIqs6YKxnwBn2/zL2QuYYEtj5OJ87rEUnCfFic6ldClvzJw==
|
||||
"@mui/private-theming@^6.1.6":
|
||||
version "6.1.6"
|
||||
resolved "https://registry.yarnpkg.com/@mui/private-theming/-/private-theming-6.1.6.tgz#9966bf2eca3d626cddd6e173752f46d344c7d7d1"
|
||||
integrity sha512-ioAiFckaD/fJSnTrUMWgjl9HYBWt7ixCh7zZw7gDZ+Tae7NuprNV6QJK95EidDT7K0GetR2rU3kAeIR61Myttw==
|
||||
dependencies:
|
||||
"@babel/runtime" "^7.25.7"
|
||||
"@mui/utils" "^6.1.5"
|
||||
"@babel/runtime" "^7.26.0"
|
||||
"@mui/utils" "^6.1.6"
|
||||
prop-types "^15.8.1"
|
||||
|
||||
"@mui/styled-engine@^5.16.6":
|
||||
@@ -1084,12 +1089,12 @@
|
||||
csstype "^3.1.3"
|
||||
prop-types "^15.8.1"
|
||||
|
||||
"@mui/styled-engine@^6.1.5":
|
||||
version "6.1.5"
|
||||
resolved "https://registry.yarnpkg.com/@mui/styled-engine/-/styled-engine-6.1.5.tgz#a21a75799f84446e3553ab191a891ca2192933cc"
|
||||
integrity sha512-tiyWzMkHeWlOoE6AqomWvYvdml8Nv5k5T+LDwOiwHEawx8P9Lyja6ZwWPU6xljwPXYYPT2KBp1XvMly7dsK46A==
|
||||
"@mui/styled-engine@^6.1.6":
|
||||
version "6.1.6"
|
||||
resolved "https://registry.yarnpkg.com/@mui/styled-engine/-/styled-engine-6.1.6.tgz#61996621a0297aac16061e1739a738a899613fd6"
|
||||
integrity sha512-I+yS1cSuSvHnZDBO7e7VHxTWpj+R7XlSZvTC4lS/OIbUNJOMMSd3UDP6V2sfwzAdmdDNBi7NGCRv2SZ6O9hGDA==
|
||||
dependencies:
|
||||
"@babel/runtime" "^7.25.7"
|
||||
"@babel/runtime" "^7.26.0"
|
||||
"@emotion/cache" "^11.13.1"
|
||||
"@emotion/serialize" "^1.3.2"
|
||||
"@emotion/sheet" "^1.4.0"
|
||||
@@ -1110,24 +1115,24 @@
|
||||
csstype "^3.1.3"
|
||||
prop-types "^15.8.1"
|
||||
|
||||
"@mui/system@^6.1.5":
|
||||
version "6.1.5"
|
||||
resolved "https://registry.yarnpkg.com/@mui/system/-/system-6.1.5.tgz#2124f43be98a7393e08edf89ae0fbc8678607e11"
|
||||
integrity sha512-vPM9ocQ8qquRDByTG3XF/wfYTL7IWL/20EiiKqByLDps8wOmbrDG9rVznSE3ZbcjFCFfMRMhtxvN92bwe/63SA==
|
||||
"@mui/system@^6.1.6":
|
||||
version "6.1.6"
|
||||
resolved "https://registry.yarnpkg.com/@mui/system/-/system-6.1.6.tgz#d335d6952092f3c758c8b78c2d993aa13ef58175"
|
||||
integrity sha512-qOf1VUE9wK8syiB0BBCp82oNBAVPYdj4Trh+G1s+L+ImYiKlubWhhqlnvWt3xqMevR+D2h1CXzA1vhX2FvA+VQ==
|
||||
dependencies:
|
||||
"@babel/runtime" "^7.25.7"
|
||||
"@mui/private-theming" "^6.1.5"
|
||||
"@mui/styled-engine" "^6.1.5"
|
||||
"@mui/types" "^7.2.18"
|
||||
"@mui/utils" "^6.1.5"
|
||||
"@babel/runtime" "^7.26.0"
|
||||
"@mui/private-theming" "^6.1.6"
|
||||
"@mui/styled-engine" "^6.1.6"
|
||||
"@mui/types" "^7.2.19"
|
||||
"@mui/utils" "^6.1.6"
|
||||
clsx "^2.1.1"
|
||||
csstype "^3.1.3"
|
||||
prop-types "^15.8.1"
|
||||
|
||||
"@mui/types@^7.2.15", "@mui/types@^7.2.18":
|
||||
version "7.2.18"
|
||||
resolved "https://registry.yarnpkg.com/@mui/types/-/types-7.2.18.tgz#4b6385ed2f7828ef344113cdc339d6fdf8e4bc23"
|
||||
integrity sha512-uvK9dWeyCJl/3ocVnTOS6nlji/Knj8/tVqVX03UVTpdmTJYu/s4jtDd9Kvv0nRGE0CUSNW1UYAci7PYypjealg==
|
||||
"@mui/types@^7.2.15", "@mui/types@^7.2.19":
|
||||
version "7.2.19"
|
||||
resolved "https://registry.yarnpkg.com/@mui/types/-/types-7.2.19.tgz#c941954dd24393fdce5f07830d44440cf4ab6c80"
|
||||
integrity sha512-6XpZEM/Q3epK9RN8ENoXuygnqUQxE+siN/6rGRi2iwJPgBUR25mphYQ9ZI87plGh58YoZ5pp40bFvKYOCDJ3tA==
|
||||
|
||||
"@mui/utils@^5.16.6":
|
||||
version "5.16.6"
|
||||
@@ -1141,13 +1146,13 @@
|
||||
prop-types "^15.8.1"
|
||||
react-is "^18.3.1"
|
||||
|
||||
"@mui/utils@^6.1.5":
|
||||
version "6.1.5"
|
||||
resolved "https://registry.yarnpkg.com/@mui/utils/-/utils-6.1.5.tgz#a5c75ac48f9913340670ebeba2907568a6ee8c49"
|
||||
integrity sha512-vp2WfNDY+IbKUIGg+eqX1Ry4t/BilMjzp6p9xO1rfqpYjH1mj8coQxxDfKxcQLzBQkmBJjymjoGOak5VUYwXug==
|
||||
"@mui/utils@^6.1.6":
|
||||
version "6.1.6"
|
||||
resolved "https://registry.yarnpkg.com/@mui/utils/-/utils-6.1.6.tgz#4b9fd34da3a1dd4700fe506a20ca7da3933ba48e"
|
||||
integrity sha512-sBS6D9mJECtELASLM+18WUcXF6RH3zNxBRFeyCRg8wad6NbyNrdxLuwK+Ikvc38sTZwBzAz691HmSofLqHd9sQ==
|
||||
dependencies:
|
||||
"@babel/runtime" "^7.25.7"
|
||||
"@mui/types" "^7.2.18"
|
||||
"@babel/runtime" "^7.26.0"
|
||||
"@mui/types" "^7.2.19"
|
||||
"@types/prop-types" "^15.7.13"
|
||||
clsx "^2.1.1"
|
||||
prop-types "^15.8.1"
|
||||
@@ -1184,10 +1189,10 @@
|
||||
resolved "https://registry.npmjs.org/@popperjs/core/-/core-2.11.8.tgz"
|
||||
integrity sha512-P1st0aksCrn9sGZhp8GMYwBnQsbvAWsZAX44oXNNvLHGqAOcoVxmjZiohstwQ7SqKnbR47akdNi+uleWD8+g6A==
|
||||
|
||||
"@remix-run/router@1.20.0":
|
||||
version "1.20.0"
|
||||
resolved "https://registry.yarnpkg.com/@remix-run/router/-/router-1.20.0.tgz#03554155b45d8b529adf635b2f6ad1165d70d8b4"
|
||||
integrity sha512-mUnk8rPJBI9loFDZ+YzPGdeniYK+FTmRD1TMCz7ev2SNIozyKKpnGgsxO34u6Z4z/t0ITuu7voi/AshfsGsgFg==
|
||||
"@remix-run/router@1.21.0":
|
||||
version "1.21.0"
|
||||
resolved "https://registry.yarnpkg.com/@remix-run/router/-/router-1.21.0.tgz#c65ae4262bdcfe415dbd4f64ec87676e4a56e2b5"
|
||||
integrity sha512-xfSkCAchbdG5PnbrKqFWwia4Bi61nH+wm8wLEqfHDyp7Y3dZzgqS2itV8i4gAq9pC2HsTpwyBC6Ds8VHZ96JlA==
|
||||
|
||||
"@rollup/rollup-android-arm-eabi@4.22.4":
|
||||
version "4.22.4"
|
||||
@@ -1293,17 +1298,17 @@
|
||||
dependencies:
|
||||
"@sinonjs/commons" "^3.0.0"
|
||||
|
||||
"@tanstack/query-core@5.59.13":
|
||||
version "5.59.13"
|
||||
resolved "https://registry.yarnpkg.com/@tanstack/query-core/-/query-core-5.59.13.tgz#8c962980af174bbd446b7e9b9999f7432897df80"
|
||||
integrity sha512-Oou0bBu/P8+oYjXsJQ11j+gcpLAMpqW42UlokQYEz4dE7+hOtVO9rVuolJKgEccqzvyFzqX4/zZWY+R/v1wVsQ==
|
||||
"@tanstack/query-core@5.59.20":
|
||||
version "5.59.20"
|
||||
resolved "https://registry.yarnpkg.com/@tanstack/query-core/-/query-core-5.59.20.tgz#356718976536727b9af0ad1163a21fd6a44ee0a9"
|
||||
integrity sha512-e8vw0lf7KwfGe1if4uPFhvZRWULqHjFcz3K8AebtieXvnMOz5FSzlZe3mTLlPuUBcydCnBRqYs2YJ5ys68wwLg==
|
||||
|
||||
"@tanstack/react-query@^5.59.15", "@tanstack/react-query@^5.8.4":
|
||||
version "5.59.15"
|
||||
resolved "https://registry.yarnpkg.com/@tanstack/react-query/-/react-query-5.59.15.tgz#fa1c5b4d96e6a148ec761f214304bbf5ac1906be"
|
||||
integrity sha512-QbVlAkTI78wB4Mqgf2RDmgC0AOiJqer2c5k9STOOSXGv1S6ZkY37r/6UpE8DbQ2Du0ohsdoXgFNEyv+4eDoPEw==
|
||||
"@tanstack/react-query@^5.59.20", "@tanstack/react-query@^5.8.4":
|
||||
version "5.59.20"
|
||||
resolved "https://registry.yarnpkg.com/@tanstack/react-query/-/react-query-5.59.20.tgz#bacf1983f44c5690bb99b518f2ef71dc2fa875a4"
|
||||
integrity sha512-Zly0egsK0tFdfSbh5/mapSa+Zfc3Et0Zkar7Wo5sQkFzWyB3p3uZWOHR2wrlAEEV2L953eLuDBtbgFvMYiLvUw==
|
||||
dependencies:
|
||||
"@tanstack/query-core" "5.59.13"
|
||||
"@tanstack/query-core" "5.59.20"
|
||||
|
||||
"@testing-library/dom@^10.0.0":
|
||||
version "10.4.0"
|
||||
@@ -1319,10 +1324,10 @@
|
||||
lz-string "^1.5.0"
|
||||
pretty-format "^27.0.2"
|
||||
|
||||
"@testing-library/jest-dom@^6.6.2":
|
||||
version "6.6.2"
|
||||
resolved "https://registry.yarnpkg.com/@testing-library/jest-dom/-/jest-dom-6.6.2.tgz#8186aa9a07263adef9cc5a59a4772db8c31f4a5b"
|
||||
integrity sha512-P6GJD4yqc9jZLbe98j/EkyQDTPgqftohZF5FBkHY5BUERZmcf4HeO2k0XaefEg329ux2p21i1A1DmyQ1kKw2Jw==
|
||||
"@testing-library/jest-dom@^6.6.3":
|
||||
version "6.6.3"
|
||||
resolved "https://registry.yarnpkg.com/@testing-library/jest-dom/-/jest-dom-6.6.3.tgz#26ba906cf928c0f8172e182c6fe214eb4f9f2bd2"
|
||||
integrity sha512-IteBhl4XqYNkM54f4ejhLRJiZNqcSCoXUOG2CPK7qbD322KjQozM4kHQOfkG2oln9b9HTYqs+Sae8vBATubxxA==
|
||||
dependencies:
|
||||
"@adobe/css-tools" "^4.4.0"
|
||||
aria-query "^5.0.0"
|
||||
@@ -1470,17 +1475,17 @@
|
||||
resolved "https://registry.npmjs.org/@types/json5/-/json5-0.0.29.tgz"
|
||||
integrity sha512-dRLjCWHYg4oaA77cxO64oO+7JwCwnIzkZPdrrC71jQmQtlhM556pwKo5bUzqvZndkVbeFLIIi+9TC40JNF5hNQ==
|
||||
|
||||
"@types/lodash@^4.17.12":
|
||||
version "4.17.12"
|
||||
resolved "https://registry.yarnpkg.com/@types/lodash/-/lodash-4.17.12.tgz#25d71312bf66512105d71e55d42e22c36bcfc689"
|
||||
integrity sha512-sviUmCE8AYdaF/KIHLDJBQgeYzPBI0vf/17NaYehBJfYD1j6/L95Slh07NlyK2iNyBNaEkb3En2jRt+a8y3xZQ==
|
||||
"@types/lodash@^4.17.13":
|
||||
version "4.17.13"
|
||||
resolved "https://registry.yarnpkg.com/@types/lodash/-/lodash-4.17.13.tgz#786e2d67cfd95e32862143abe7463a7f90c300eb"
|
||||
integrity sha512-lfx+dftrEZcdBPczf9d0Qv0x+j/rfNCMuC6OcfXmO8gkfeNAY88PgKUbvG56whcN23gc27yenwF6oJZXGFpYxg==
|
||||
|
||||
"@types/node@*", "@types/node@^22.7.9":
|
||||
version "22.7.9"
|
||||
resolved "https://registry.yarnpkg.com/@types/node/-/node-22.7.9.tgz#2bf2797b5e84702d8262ea2cf843c3c3c880d0e9"
|
||||
integrity sha512-jrTfRC7FM6nChvU7X2KqcrgquofrWLFDeYC1hKfwNWomVvrn7JIksqf344WN2X/y8xrgqBd2dJATZV4GbatBfg==
|
||||
"@types/node@*", "@types/node@^22.8.7":
|
||||
version "22.8.7"
|
||||
resolved "https://registry.yarnpkg.com/@types/node/-/node-22.8.7.tgz#04ab7a073d95b4a6ee899f235d43f3c320a976f4"
|
||||
integrity sha512-LidcG+2UeYIWcMuMUpBKOnryBWG/rnmOHQR5apjn8myTQcx3rinFRn7DcIFhMnS0PPFSC6OafdIKEad0lj6U0Q==
|
||||
dependencies:
|
||||
undici-types "~6.19.2"
|
||||
undici-types "~6.19.8"
|
||||
|
||||
"@types/papaparse@^5.3.15":
|
||||
version "5.3.15"
|
||||
@@ -1536,62 +1541,62 @@
|
||||
dependencies:
|
||||
"@types/yargs-parser" "*"
|
||||
|
||||
"@typescript-eslint/eslint-plugin@8.11.0", "@typescript-eslint/eslint-plugin@^8.11.0":
|
||||
version "8.11.0"
|
||||
resolved "https://registry.yarnpkg.com/@typescript-eslint/eslint-plugin/-/eslint-plugin-8.11.0.tgz#c3f087d20715fa94310b30666c08b3349e0ab084"
|
||||
integrity sha512-KhGn2LjW1PJT2A/GfDpiyOfS4a8xHQv2myUagTM5+zsormOmBlYsnQ6pobJ8XxJmh6hnHwa2Mbe3fPrDJoDhbA==
|
||||
"@typescript-eslint/eslint-plugin@8.13.0", "@typescript-eslint/eslint-plugin@^8.11.0":
|
||||
version "8.13.0"
|
||||
resolved "https://registry.yarnpkg.com/@typescript-eslint/eslint-plugin/-/eslint-plugin-8.13.0.tgz#650c50b8c795b5d092189f139f6d00535b5b0f3d"
|
||||
integrity sha512-nQtBLiZYMUPkclSeC3id+x4uVd1SGtHuElTxL++SfP47jR0zfkZBJHc+gL4qPsgTuypz0k8Y2GheaDYn6Gy3rg==
|
||||
dependencies:
|
||||
"@eslint-community/regexpp" "^4.10.0"
|
||||
"@typescript-eslint/scope-manager" "8.11.0"
|
||||
"@typescript-eslint/type-utils" "8.11.0"
|
||||
"@typescript-eslint/utils" "8.11.0"
|
||||
"@typescript-eslint/visitor-keys" "8.11.0"
|
||||
"@typescript-eslint/scope-manager" "8.13.0"
|
||||
"@typescript-eslint/type-utils" "8.13.0"
|
||||
"@typescript-eslint/utils" "8.13.0"
|
||||
"@typescript-eslint/visitor-keys" "8.13.0"
|
||||
graphemer "^1.4.0"
|
||||
ignore "^5.3.1"
|
||||
natural-compare "^1.4.0"
|
||||
ts-api-utils "^1.3.0"
|
||||
|
||||
"@typescript-eslint/parser@8.11.0", "@typescript-eslint/parser@^8.11.0":
|
||||
version "8.11.0"
|
||||
resolved "https://registry.yarnpkg.com/@typescript-eslint/parser/-/parser-8.11.0.tgz#2ad1481388dc1c937f50b2d138c9ca57cc6c5cce"
|
||||
integrity sha512-lmt73NeHdy1Q/2ul295Qy3uninSqi6wQI18XwSpm8w0ZbQXUpjCAWP1Vlv/obudoBiIjJVjlztjQ+d/Md98Yxg==
|
||||
"@typescript-eslint/parser@8.13.0", "@typescript-eslint/parser@^8.13.0":
|
||||
version "8.13.0"
|
||||
resolved "https://registry.yarnpkg.com/@typescript-eslint/parser/-/parser-8.13.0.tgz#ef76203b7cac515aa3ccc4f7ce5320dd61c46b29"
|
||||
integrity sha512-w0xp+xGg8u/nONcGw1UXAr6cjCPU1w0XVyBs6Zqaj5eLmxkKQAByTdV/uGgNN5tVvN/kKpoQlP2cL7R+ajZZIQ==
|
||||
dependencies:
|
||||
"@typescript-eslint/scope-manager" "8.11.0"
|
||||
"@typescript-eslint/types" "8.11.0"
|
||||
"@typescript-eslint/typescript-estree" "8.11.0"
|
||||
"@typescript-eslint/visitor-keys" "8.11.0"
|
||||
"@typescript-eslint/scope-manager" "8.13.0"
|
||||
"@typescript-eslint/types" "8.13.0"
|
||||
"@typescript-eslint/typescript-estree" "8.13.0"
|
||||
"@typescript-eslint/visitor-keys" "8.13.0"
|
||||
debug "^4.3.4"
|
||||
|
||||
"@typescript-eslint/scope-manager@8.11.0":
|
||||
version "8.11.0"
|
||||
resolved "https://registry.yarnpkg.com/@typescript-eslint/scope-manager/-/scope-manager-8.11.0.tgz#9d399ce624118966732824878bc9a83593a30405"
|
||||
integrity sha512-Uholz7tWhXmA4r6epo+vaeV7yjdKy5QFCERMjs1kMVsLRKIrSdM6o21W2He9ftp5PP6aWOVpD5zvrvuHZC0bMQ==
|
||||
"@typescript-eslint/scope-manager@8.13.0":
|
||||
version "8.13.0"
|
||||
resolved "https://registry.yarnpkg.com/@typescript-eslint/scope-manager/-/scope-manager-8.13.0.tgz#2f4aed0b87d72360e64e4ea194b1fde14a59082e"
|
||||
integrity sha512-XsGWww0odcUT0gJoBZ1DeulY1+jkaHUciUq4jKNv4cpInbvvrtDoyBH9rE/n2V29wQJPk8iCH1wipra9BhmiMA==
|
||||
dependencies:
|
||||
"@typescript-eslint/types" "8.11.0"
|
||||
"@typescript-eslint/visitor-keys" "8.11.0"
|
||||
"@typescript-eslint/types" "8.13.0"
|
||||
"@typescript-eslint/visitor-keys" "8.13.0"
|
||||
|
||||
"@typescript-eslint/type-utils@8.11.0":
|
||||
version "8.11.0"
|
||||
resolved "https://registry.yarnpkg.com/@typescript-eslint/type-utils/-/type-utils-8.11.0.tgz#b7f9e6120c1ddee8a1a07615646642ad85fc91b5"
|
||||
integrity sha512-ItiMfJS6pQU0NIKAaybBKkuVzo6IdnAhPFZA/2Mba/uBjuPQPet/8+zh5GtLHwmuFRShZx+8lhIs7/QeDHflOg==
|
||||
"@typescript-eslint/type-utils@8.13.0":
|
||||
version "8.13.0"
|
||||
resolved "https://registry.yarnpkg.com/@typescript-eslint/type-utils/-/type-utils-8.13.0.tgz#8c8fa68490dcb9ae1687ffc7de8fbe23c26417bd"
|
||||
integrity sha512-Rqnn6xXTR316fP4D2pohZenJnp+NwQ1mo7/JM+J1LWZENSLkJI8ID8QNtlvFeb0HnFSK94D6q0cnMX6SbE5/vA==
|
||||
dependencies:
|
||||
"@typescript-eslint/typescript-estree" "8.11.0"
|
||||
"@typescript-eslint/utils" "8.11.0"
|
||||
"@typescript-eslint/typescript-estree" "8.13.0"
|
||||
"@typescript-eslint/utils" "8.13.0"
|
||||
debug "^4.3.4"
|
||||
ts-api-utils "^1.3.0"
|
||||
|
||||
"@typescript-eslint/types@8.11.0":
|
||||
version "8.11.0"
|
||||
resolved "https://registry.yarnpkg.com/@typescript-eslint/types/-/types-8.11.0.tgz#7c766250502097f49bbc2e651132e6bf489e20b8"
|
||||
integrity sha512-tn6sNMHf6EBAYMvmPUaKaVeYvhUsrE6x+bXQTxjQRp360h1giATU0WvgeEys1spbvb5R+VpNOZ+XJmjD8wOUHw==
|
||||
"@typescript-eslint/types@8.13.0":
|
||||
version "8.13.0"
|
||||
resolved "https://registry.yarnpkg.com/@typescript-eslint/types/-/types-8.13.0.tgz#3f35dead2b2491a04339370dcbcd17bbdfc204d8"
|
||||
integrity sha512-4cyFErJetFLckcThRUFdReWJjVsPCqyBlJTi6IDEpc1GWCIIZRFxVppjWLIMcQhNGhdWJJRYFHpHoDWvMlDzng==
|
||||
|
||||
"@typescript-eslint/typescript-estree@8.11.0":
|
||||
version "8.11.0"
|
||||
resolved "https://registry.yarnpkg.com/@typescript-eslint/typescript-estree/-/typescript-estree-8.11.0.tgz#35fe5d3636fc5727c52429393415412e552e222b"
|
||||
integrity sha512-yHC3s1z1RCHoCz5t06gf7jH24rr3vns08XXhfEqzYpd6Hll3z/3g23JRi0jM8A47UFKNc3u/y5KIMx8Ynbjohg==
|
||||
"@typescript-eslint/typescript-estree@8.13.0":
|
||||
version "8.13.0"
|
||||
resolved "https://registry.yarnpkg.com/@typescript-eslint/typescript-estree/-/typescript-estree-8.13.0.tgz#db8c93dd5437ca3ce417a255fb35ddc3c12c3e95"
|
||||
integrity sha512-v7SCIGmVsRK2Cy/LTLGN22uea6SaUIlpBcO/gnMGT/7zPtxp90bphcGf4fyrCQl3ZtiBKqVTG32hb668oIYy1g==
|
||||
dependencies:
|
||||
"@typescript-eslint/types" "8.11.0"
|
||||
"@typescript-eslint/visitor-keys" "8.11.0"
|
||||
"@typescript-eslint/types" "8.13.0"
|
||||
"@typescript-eslint/visitor-keys" "8.13.0"
|
||||
debug "^4.3.4"
|
||||
fast-glob "^3.3.2"
|
||||
is-glob "^4.0.3"
|
||||
@@ -1599,22 +1604,22 @@
|
||||
semver "^7.6.0"
|
||||
ts-api-utils "^1.3.0"
|
||||
|
||||
"@typescript-eslint/utils@8.11.0":
|
||||
version "8.11.0"
|
||||
resolved "https://registry.yarnpkg.com/@typescript-eslint/utils/-/utils-8.11.0.tgz#4480d1e9f2bb18ea3510c79f870a1aefc118103d"
|
||||
integrity sha512-CYiX6WZcbXNJV7UNB4PLDIBtSdRmRI/nb0FMyqHPTQD1rMjA0foPLaPUV39C/MxkTd/QKSeX+Gb34PPsDVC35g==
|
||||
"@typescript-eslint/utils@8.13.0":
|
||||
version "8.13.0"
|
||||
resolved "https://registry.yarnpkg.com/@typescript-eslint/utils/-/utils-8.13.0.tgz#f6d40e8b5053dcaeabbd2e26463857abf27d62c0"
|
||||
integrity sha512-A1EeYOND6Uv250nybnLZapeXpYMl8tkzYUxqmoKAWnI4sei3ihf2XdZVd+vVOmHGcp3t+P7yRrNsyyiXTvShFQ==
|
||||
dependencies:
|
||||
"@eslint-community/eslint-utils" "^4.4.0"
|
||||
"@typescript-eslint/scope-manager" "8.11.0"
|
||||
"@typescript-eslint/types" "8.11.0"
|
||||
"@typescript-eslint/typescript-estree" "8.11.0"
|
||||
"@typescript-eslint/scope-manager" "8.13.0"
|
||||
"@typescript-eslint/types" "8.13.0"
|
||||
"@typescript-eslint/typescript-estree" "8.13.0"
|
||||
|
||||
"@typescript-eslint/visitor-keys@8.11.0":
|
||||
version "8.11.0"
|
||||
resolved "https://registry.yarnpkg.com/@typescript-eslint/visitor-keys/-/visitor-keys-8.11.0.tgz#273de1cbffe63d9f9cd7dfc20b5a5af66310cb92"
|
||||
integrity sha512-EaewX6lxSjRJnc+99+dqzTeoDZUfyrA52d2/HRrkI830kgovWsmIiTfmr0NZorzqic7ga+1bS60lRBUgR3n/Bw==
|
||||
"@typescript-eslint/visitor-keys@8.13.0":
|
||||
version "8.13.0"
|
||||
resolved "https://registry.yarnpkg.com/@typescript-eslint/visitor-keys/-/visitor-keys-8.13.0.tgz#e97b0d92b266ef38a1faf40a74da289b66683a5b"
|
||||
integrity sha512-7N/+lztJqH4Mrf0lb10R/CbI1EaAMMGyF5y0oJvFoAhafwgiRA7TXyd8TFn8FC8k5y2dTsYogg238qavRGNnlw==
|
||||
dependencies:
|
||||
"@typescript-eslint/types" "8.11.0"
|
||||
"@typescript-eslint/types" "8.13.0"
|
||||
eslint-visitor-keys "^3.4.3"
|
||||
|
||||
"@vitejs/plugin-react@^4.3.3":
|
||||
@@ -1658,10 +1663,10 @@ acorn@^8.1.0, acorn@^8.11.0, acorn@^8.4.1, acorn@^8.8.1:
|
||||
resolved "https://registry.npmjs.org/acorn/-/acorn-8.12.1.tgz"
|
||||
integrity sha512-tcpGyI9zbizT9JbV6oYE477V6mTlXvvi0T0G3SNIYE2apm/G5huBa1+K89VGeovbg+jycCrfhl3ADxErOuO6Jg==
|
||||
|
||||
acorn@^8.12.0:
|
||||
version "8.13.0"
|
||||
resolved "https://registry.yarnpkg.com/acorn/-/acorn-8.13.0.tgz#2a30d670818ad16ddd6a35d3842dacec9e5d7ca3"
|
||||
integrity sha512-8zSiw54Oxrdym50NlZ9sUusyO1Z1ZchgRLWRaK6c86XJFClyCgFKetdowBg5bKxyp/u+CDBJG4Mpp0m3HLZl9w==
|
||||
acorn@^8.14.0:
|
||||
version "8.14.0"
|
||||
resolved "https://registry.yarnpkg.com/acorn/-/acorn-8.14.0.tgz#063e2c70cac5fb4f6467f0b11152e04c682795b0"
|
||||
integrity sha512-cl669nCJTZBsL97OF4kUQm5g5hC2uihk0NxY3WENAC0TYdILVkAyHymAntgxGkl7K+t0cXIrH5siy5S4XkFycA==
|
||||
|
||||
agent-base@6:
|
||||
version "6.0.2"
|
||||
@@ -2512,7 +2517,7 @@ error-ex@^1.3.1:
|
||||
dependencies:
|
||||
is-arrayish "^0.2.1"
|
||||
|
||||
es-abstract@^1.22.1, es-abstract@^1.22.3, es-abstract@^1.23.0, es-abstract@^1.23.1, es-abstract@^1.23.2, es-abstract@^1.23.3:
|
||||
es-abstract@^1.22.1, es-abstract@^1.22.3, es-abstract@^1.23.0, es-abstract@^1.23.2, es-abstract@^1.23.3:
|
||||
version "1.23.3"
|
||||
resolved "https://registry.npmjs.org/es-abstract/-/es-abstract-1.23.3.tgz"
|
||||
integrity sha512-e+HfNH61Bj1X9/jLc5v1owaLYuHdeHHSQlkhCBiTK8rBvKaULl/beGMxwrMXjpYrv4pz22BlY570vVePA2ho4A==
|
||||
@@ -2576,26 +2581,6 @@ es-errors@^1.2.1, es-errors@^1.3.0:
|
||||
resolved "https://registry.npmjs.org/es-errors/-/es-errors-1.3.0.tgz"
|
||||
integrity sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==
|
||||
|
||||
es-iterator-helpers@^1.1.0:
|
||||
version "1.1.0"
|
||||
resolved "https://registry.yarnpkg.com/es-iterator-helpers/-/es-iterator-helpers-1.1.0.tgz#f6d745d342aea214fe09497e7152170dc333a7a6"
|
||||
integrity sha512-/SurEfycdyssORP/E+bj4sEu1CWw4EmLDsHynHwSXQ7utgbrMRWW195pTrCjFgFCddf/UkYm3oqKPRq5i8bJbw==
|
||||
dependencies:
|
||||
call-bind "^1.0.7"
|
||||
define-properties "^1.2.1"
|
||||
es-abstract "^1.23.3"
|
||||
es-errors "^1.3.0"
|
||||
es-set-tostringtag "^2.0.3"
|
||||
function-bind "^1.1.2"
|
||||
get-intrinsic "^1.2.4"
|
||||
globalthis "^1.0.4"
|
||||
has-property-descriptors "^1.0.2"
|
||||
has-proto "^1.0.3"
|
||||
has-symbols "^1.0.3"
|
||||
internal-slot "^1.0.7"
|
||||
iterator.prototype "^1.1.3"
|
||||
safe-array-concat "^1.1.2"
|
||||
|
||||
es-object-atoms@^1.0.0:
|
||||
version "1.0.0"
|
||||
resolved "https://registry.npmjs.org/es-object-atoms/-/es-object-atoms-1.0.0.tgz"
|
||||
@@ -2734,10 +2719,10 @@ eslint-plugin-import@^2.31.0:
|
||||
string.prototype.trimend "^1.0.8"
|
||||
tsconfig-paths "^3.15.0"
|
||||
|
||||
eslint-plugin-jsx-a11y@^6.10.1:
|
||||
version "6.10.1"
|
||||
resolved "https://registry.yarnpkg.com/eslint-plugin-jsx-a11y/-/eslint-plugin-jsx-a11y-6.10.1.tgz#87003835bad8875e023aa5db26f41a0c9e6a8fa9"
|
||||
integrity sha512-zHByM9WTUMnfsDTafGXRiqxp6lFtNoSOWBY6FonVRn3A+BUwN1L/tdBXT40BcBJi0cZjOGTXZ0eD/rTG9fEJ0g==
|
||||
eslint-plugin-jsx-a11y@^6.10.2:
|
||||
version "6.10.2"
|
||||
resolved "https://registry.yarnpkg.com/eslint-plugin-jsx-a11y/-/eslint-plugin-jsx-a11y-6.10.2.tgz#d2812bb23bf1ab4665f1718ea442e8372e638483"
|
||||
integrity sha512-scB3nz4WmG75pV8+3eRUQOHZlNSUhFNq37xnpgRkCCELU3XMvXAxLk1eqWWyE22Ki4Q01Fnsw9BA3cJHDPgn2Q==
|
||||
dependencies:
|
||||
aria-query "^5.3.2"
|
||||
array-includes "^3.1.8"
|
||||
@@ -2747,7 +2732,6 @@ eslint-plugin-jsx-a11y@^6.10.1:
|
||||
axobject-query "^4.1.0"
|
||||
damerau-levenshtein "^1.0.8"
|
||||
emoji-regex "^9.2.2"
|
||||
es-iterator-helpers "^1.1.0"
|
||||
hasown "^2.0.2"
|
||||
jsx-ast-utils "^3.3.5"
|
||||
language-tags "^1.0.9"
|
||||
@@ -2777,10 +2761,10 @@ eslint-plugin-yaml@^1.0.3:
|
||||
js-yaml "^4.1.0"
|
||||
jshint "^2.13.6"
|
||||
|
||||
eslint-scope@^8.1.0:
|
||||
version "8.1.0"
|
||||
resolved "https://registry.yarnpkg.com/eslint-scope/-/eslint-scope-8.1.0.tgz#70214a174d4cbffbc3e8a26911d8bf51b9ae9d30"
|
||||
integrity sha512-14dSvlhaVhKKsa9Fx1l8A17s7ah7Ef7wCakJ10LYk6+GYmP9yDti2oq2SEwcyndt6knfcZyhyxwY3i9yL78EQw==
|
||||
eslint-scope@^8.2.0:
|
||||
version "8.2.0"
|
||||
resolved "https://registry.yarnpkg.com/eslint-scope/-/eslint-scope-8.2.0.tgz#377aa6f1cb5dc7592cfd0b7f892fd0cf352ce442"
|
||||
integrity sha512-PHlWUfG6lvPc3yvP5A4PNyBL1W8fkDUccmI21JUu/+GKZBoH/W5u6usENXUrWFRsyoW5ACUjFGgAFQp5gUlb/A==
|
||||
dependencies:
|
||||
esrecurse "^4.3.0"
|
||||
estraverse "^5.2.0"
|
||||
@@ -2790,26 +2774,26 @@ eslint-visitor-keys@^3.3.0, eslint-visitor-keys@^3.4.3:
|
||||
resolved "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.4.3.tgz"
|
||||
integrity sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==
|
||||
|
||||
eslint-visitor-keys@^4.1.0:
|
||||
version "4.1.0"
|
||||
resolved "https://registry.yarnpkg.com/eslint-visitor-keys/-/eslint-visitor-keys-4.1.0.tgz#1f785cc5e81eb7534523d85922248232077d2f8c"
|
||||
integrity sha512-Q7lok0mqMUSf5a/AdAZkA5a/gHcO6snwQClVNNvFKCAVlxXucdU8pKydU5ZVZjBx5xr37vGbFFWtLQYreLzrZg==
|
||||
eslint-visitor-keys@^4.2.0:
|
||||
version "4.2.0"
|
||||
resolved "https://registry.yarnpkg.com/eslint-visitor-keys/-/eslint-visitor-keys-4.2.0.tgz#687bacb2af884fcdda8a6e7d65c606f46a14cd45"
|
||||
integrity sha512-UyLnSehNt62FFhSwjZlHmeokpRK59rcz29j+F1/aDgbkbRTk7wIc9XzdoasMUbRNKDM0qQt/+BJ4BrpFeABemw==
|
||||
|
||||
eslint@^9.13.0:
|
||||
version "9.13.0"
|
||||
resolved "https://registry.yarnpkg.com/eslint/-/eslint-9.13.0.tgz#7659014b7dda1ff876ecbd990f726e11c61596e6"
|
||||
integrity sha512-EYZK6SX6zjFHST/HRytOdA/zE72Cq/bfw45LSyuwrdvcclb/gqV8RRQxywOBEWO2+WDpva6UZa4CcDeJKzUCFA==
|
||||
eslint@^9.14.0:
|
||||
version "9.14.0"
|
||||
resolved "https://registry.yarnpkg.com/eslint/-/eslint-9.14.0.tgz#534180a97c00af08bcf2b60b0ebf0c4d6c1b2c95"
|
||||
integrity sha512-c2FHsVBr87lnUtjP4Yhvk4yEhKrQavGafRA/Se1ouse8PfbfC/Qh9Mxa00yWsZRlqeUB9raXip0aiiUZkgnr9g==
|
||||
dependencies:
|
||||
"@eslint-community/eslint-utils" "^4.2.0"
|
||||
"@eslint-community/regexpp" "^4.11.0"
|
||||
"@eslint-community/regexpp" "^4.12.1"
|
||||
"@eslint/config-array" "^0.18.0"
|
||||
"@eslint/core" "^0.7.0"
|
||||
"@eslint/eslintrc" "^3.1.0"
|
||||
"@eslint/js" "9.13.0"
|
||||
"@eslint/js" "9.14.0"
|
||||
"@eslint/plugin-kit" "^0.2.0"
|
||||
"@humanfs/node" "^0.16.5"
|
||||
"@humanfs/node" "^0.16.6"
|
||||
"@humanwhocodes/module-importer" "^1.0.1"
|
||||
"@humanwhocodes/retry" "^0.3.1"
|
||||
"@humanwhocodes/retry" "^0.4.0"
|
||||
"@types/estree" "^1.0.6"
|
||||
"@types/json-schema" "^7.0.15"
|
||||
ajv "^6.12.4"
|
||||
@@ -2817,9 +2801,9 @@ eslint@^9.13.0:
|
||||
cross-spawn "^7.0.2"
|
||||
debug "^4.3.2"
|
||||
escape-string-regexp "^4.0.0"
|
||||
eslint-scope "^8.1.0"
|
||||
eslint-visitor-keys "^4.1.0"
|
||||
espree "^10.2.0"
|
||||
eslint-scope "^8.2.0"
|
||||
eslint-visitor-keys "^4.2.0"
|
||||
espree "^10.3.0"
|
||||
esquery "^1.5.0"
|
||||
esutils "^2.0.2"
|
||||
fast-deep-equal "^3.1.3"
|
||||
@@ -2836,14 +2820,14 @@ eslint@^9.13.0:
|
||||
optionator "^0.9.3"
|
||||
text-table "^0.2.0"
|
||||
|
||||
espree@^10.0.1, espree@^10.2.0:
|
||||
version "10.2.0"
|
||||
resolved "https://registry.yarnpkg.com/espree/-/espree-10.2.0.tgz#f4bcead9e05b0615c968e85f83816bc386a45df6"
|
||||
integrity sha512-upbkBJbckcCNBDBDXEbuhjbP68n+scUd3k/U2EkyM9nw+I/jPiL4cLF/Al06CF96wRltFda16sxDFrxsI1v0/g==
|
||||
espree@^10.0.1, espree@^10.3.0:
|
||||
version "10.3.0"
|
||||
resolved "https://registry.yarnpkg.com/espree/-/espree-10.3.0.tgz#29267cf5b0cb98735b65e64ba07e0ed49d1eed8a"
|
||||
integrity sha512-0QYC8b24HWY8zjRnDTL6RiHfDbAWn63qb4LMj1Z4b076A4une81+z03Kg7l7mn/48PUTqoLptSXez8oknU8Clg==
|
||||
dependencies:
|
||||
acorn "^8.12.0"
|
||||
acorn "^8.14.0"
|
||||
acorn-jsx "^5.3.2"
|
||||
eslint-visitor-keys "^4.1.0"
|
||||
eslint-visitor-keys "^4.2.0"
|
||||
|
||||
esprima@^4.0.0, esprima@^4.0.1:
|
||||
version "4.0.1"
|
||||
@@ -3149,7 +3133,7 @@ globals@^14.0.0:
|
||||
resolved "https://registry.yarnpkg.com/globals/-/globals-14.0.0.tgz#898d7413c29babcf6bafe56fcadded858ada724e"
|
||||
integrity sha512-oahGvuMGQlPw/ivIYBjVSrWAfWLBeku5tpPE2fOPLi+WHffIWbuh2tCjhyQhTBPMf5E9jDEH4FOmTYgYwbKwtQ==
|
||||
|
||||
globalthis@^1.0.3, globalthis@^1.0.4:
|
||||
globalthis@^1.0.3:
|
||||
version "1.0.4"
|
||||
resolved "https://registry.npmjs.org/globalthis/-/globalthis-1.0.4.tgz"
|
||||
integrity sha512-DpLKbNU4WylpxJykQujfCcwYWiV/Jhm50Goo0wrVILAv5jOr9d+H+UR3PhSCD2rCCEIg0uc+G+muBTwD54JhDQ==
|
||||
@@ -3362,13 +3346,6 @@ is-arrayish@^0.2.1:
|
||||
resolved "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz"
|
||||
integrity sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg==
|
||||
|
||||
is-async-function@^2.0.0:
|
||||
version "2.0.0"
|
||||
resolved "https://registry.npmjs.org/is-async-function/-/is-async-function-2.0.0.tgz"
|
||||
integrity sha512-Y1JXKrfykRJGdlDwdKlLpLyMIiWqWvuSd17TvZk68PLAOGOoF4Xyav1z0Xhoi+gCYjZVeC5SI+hYFOfvXmGRCA==
|
||||
dependencies:
|
||||
has-tostringtag "^1.0.0"
|
||||
|
||||
is-bigint@^1.0.1:
|
||||
version "1.0.4"
|
||||
resolved "https://registry.npmjs.org/is-bigint/-/is-bigint-1.0.4.tgz"
|
||||
@@ -3403,7 +3380,7 @@ is-data-view@^1.0.1:
|
||||
dependencies:
|
||||
is-typed-array "^1.1.13"
|
||||
|
||||
is-date-object@^1.0.1, is-date-object@^1.0.5:
|
||||
is-date-object@^1.0.1:
|
||||
version "1.0.5"
|
||||
resolved "https://registry.npmjs.org/is-date-object/-/is-date-object-1.0.5.tgz"
|
||||
integrity sha512-9YQaSxsAiSwcvS33MBk3wTCVnWK+HhF8VZR2jRxehM16QcVOdHqPn4VPHmRK4lSr38n9JriurInLcP90xsYNfQ==
|
||||
@@ -3415,13 +3392,6 @@ is-extglob@^2.1.1:
|
||||
resolved "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz"
|
||||
integrity sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==
|
||||
|
||||
is-finalizationregistry@^1.0.2:
|
||||
version "1.0.2"
|
||||
resolved "https://registry.npmjs.org/is-finalizationregistry/-/is-finalizationregistry-1.0.2.tgz"
|
||||
integrity sha512-0by5vtUJs8iFQb5TYUHHPudOR+qXYIMKtiUzvLIZITZUjknFmziyBJuLhVRc+Ds0dREFlskDNJKYIdIzu/9pfw==
|
||||
dependencies:
|
||||
call-bind "^1.0.2"
|
||||
|
||||
is-fullwidth-code-point@^3.0.0:
|
||||
version "3.0.0"
|
||||
resolved "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz"
|
||||
@@ -3432,13 +3402,6 @@ is-generator-fn@^2.0.0:
|
||||
resolved "https://registry.npmjs.org/is-generator-fn/-/is-generator-fn-2.1.0.tgz"
|
||||
integrity sha512-cTIB4yPYL/Grw0EaSzASzg6bBy9gqCofvWN8okThAYIxKJZC+udlRAmGbM0XLeniEJSs8uEgHPGuHSe1XsOLSQ==
|
||||
|
||||
is-generator-function@^1.0.10:
|
||||
version "1.0.10"
|
||||
resolved "https://registry.npmjs.org/is-generator-function/-/is-generator-function-1.0.10.tgz"
|
||||
integrity sha512-jsEjy9l3yiXEQ+PsXdmBwEPcOxaXWLspKdplFUVI9vq1iZgIekeC0L167qeu86czQaxed3q/Uzuw0swL0irL8A==
|
||||
dependencies:
|
||||
has-tostringtag "^1.0.0"
|
||||
|
||||
is-glob@^4.0.0, is-glob@^4.0.1, is-glob@^4.0.3:
|
||||
version "4.0.3"
|
||||
resolved "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz"
|
||||
@@ -3446,11 +3409,6 @@ is-glob@^4.0.0, is-glob@^4.0.1, is-glob@^4.0.3:
|
||||
dependencies:
|
||||
is-extglob "^2.1.1"
|
||||
|
||||
is-map@^2.0.3:
|
||||
version "2.0.3"
|
||||
resolved "https://registry.npmjs.org/is-map/-/is-map-2.0.3.tgz"
|
||||
integrity sha512-1Qed0/Hr2m+YqxnM09CjA2d/i6YZNfF6R2oRAOj36eUdS6qIV/huPJNSEpKbupewFs+ZsJlxsjjPbc0/afW6Lw==
|
||||
|
||||
is-negative-zero@^2.0.3:
|
||||
version "2.0.3"
|
||||
resolved "https://registry.npmjs.org/is-negative-zero/-/is-negative-zero-2.0.3.tgz"
|
||||
@@ -3481,11 +3439,6 @@ is-regex@^1.1.4:
|
||||
call-bind "^1.0.2"
|
||||
has-tostringtag "^1.0.0"
|
||||
|
||||
is-set@^2.0.3:
|
||||
version "2.0.3"
|
||||
resolved "https://registry.npmjs.org/is-set/-/is-set-2.0.3.tgz"
|
||||
integrity sha512-iPAjerrse27/ygGLxw+EBR9agv9Y6uLeYVJMu+QNCoouJ1/1ri0mGrcWpfCqFZuzzx3WjtwxG098X+n4OuRkPg==
|
||||
|
||||
is-shared-array-buffer@^1.0.2, is-shared-array-buffer@^1.0.3:
|
||||
version "1.0.3"
|
||||
resolved "https://registry.npmjs.org/is-shared-array-buffer/-/is-shared-array-buffer-1.0.3.tgz"
|
||||
@@ -3519,11 +3472,6 @@ is-typed-array@^1.1.13:
|
||||
dependencies:
|
||||
which-typed-array "^1.1.14"
|
||||
|
||||
is-weakmap@^2.0.2:
|
||||
version "2.0.2"
|
||||
resolved "https://registry.npmjs.org/is-weakmap/-/is-weakmap-2.0.2.tgz"
|
||||
integrity sha512-K5pXYOm9wqY1RgjpL3YTkF39tni1XajUIkawTLUo9EZEVUFga5gSQJF8nNS7ZwJQ02y+1YCNYcMh+HIf1ZqE+w==
|
||||
|
||||
is-weakref@^1.0.2:
|
||||
version "1.0.2"
|
||||
resolved "https://registry.npmjs.org/is-weakref/-/is-weakref-1.0.2.tgz"
|
||||
@@ -3531,14 +3479,6 @@ is-weakref@^1.0.2:
|
||||
dependencies:
|
||||
call-bind "^1.0.2"
|
||||
|
||||
is-weakset@^2.0.3:
|
||||
version "2.0.3"
|
||||
resolved "https://registry.npmjs.org/is-weakset/-/is-weakset-2.0.3.tgz"
|
||||
integrity sha512-LvIm3/KWzS9oRFHugab7d+M/GcBXuXX5xZkzPmN+NxihdQlZUQ4dWuSV1xR/sq6upL1TJEDrfBgRepHFdBtSNQ==
|
||||
dependencies:
|
||||
call-bind "^1.0.7"
|
||||
get-intrinsic "^1.2.4"
|
||||
|
||||
isarray@0.0.1:
|
||||
version "0.0.1"
|
||||
resolved "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz"
|
||||
@@ -3607,17 +3547,6 @@ istanbul-reports@^3.1.3:
|
||||
html-escaper "^2.0.0"
|
||||
istanbul-lib-report "^3.0.0"
|
||||
|
||||
iterator.prototype@^1.1.3:
|
||||
version "1.1.3"
|
||||
resolved "https://registry.yarnpkg.com/iterator.prototype/-/iterator.prototype-1.1.3.tgz#016c2abe0be3bbdb8319852884f60908ac62bf9c"
|
||||
integrity sha512-FW5iMbeQ6rBGm/oKgzq2aW4KvAGpxPzYES8N4g4xNXUKpL1mclMvOe+76AcLDTvD+Ze+sOpVhgdAQEKF4L9iGQ==
|
||||
dependencies:
|
||||
define-properties "^1.2.1"
|
||||
get-intrinsic "^1.2.1"
|
||||
has-symbols "^1.0.3"
|
||||
reflect.getprototypeof "^1.0.4"
|
||||
set-function-name "^2.0.1"
|
||||
|
||||
jake@^10.8.5:
|
||||
version "10.9.2"
|
||||
resolved "https://registry.npmjs.org/jake/-/jake-10.9.2.tgz"
|
||||
@@ -4719,10 +4648,10 @@ ra-core@^4.11.2, ra-core@^4.16.2:
|
||||
react-is "^17.0.2"
|
||||
react-query "^3.32.1"
|
||||
|
||||
ra-core@^5.3.0:
|
||||
version "5.3.0"
|
||||
resolved "https://registry.yarnpkg.com/ra-core/-/ra-core-5.3.0.tgz#02ce7e7c5d7617dbb2b2805803fde1d0c88dc4bd"
|
||||
integrity sha512-e5Y0u+P+0Kx2XeYEAUDV63NdlAvMtlrb4ndYLtIbCaIeOx1o6GXlD2BedICaYSb6XXjz+KoNZ1nmWuZ6tS4f7Q==
|
||||
ra-core@^5.3.2, ra-core@^5.3.3:
|
||||
version "5.3.3"
|
||||
resolved "https://registry.yarnpkg.com/ra-core/-/ra-core-5.3.3.tgz#b9ca8bb9517718b444f291f5ccf5ff45bf28feef"
|
||||
integrity sha512-M1EyuSyc6QCblRWUtNklgcK3mnh34SnKF01JOuIcncaKW0DQhLE7R9sagBVTJ44ZxxZGBSweW6+Ah8YZ162cCg==
|
||||
dependencies:
|
||||
"@tanstack/react-query" "^5.8.4"
|
||||
clsx "^2.1.1"
|
||||
@@ -4735,32 +4664,32 @@ ra-core@^5.3.0:
|
||||
react-error-boundary "^4.0.13"
|
||||
react-is "^18.2.0"
|
||||
|
||||
ra-i18n-polyglot@^5.3.0:
|
||||
version "5.3.0"
|
||||
resolved "https://registry.yarnpkg.com/ra-i18n-polyglot/-/ra-i18n-polyglot-5.3.0.tgz#ed10be1e3133b3e4a42990d045646ef336faf1ce"
|
||||
integrity sha512-Dc2m6MlpF1qHeqH5iJukd7t6oVxnqC/k8AY+HEYQCXCTHhVWkzHDjLOilcKHbgiY6st1p6KoCL93CP8lyEjaqg==
|
||||
ra-i18n-polyglot@^5.3.2, ra-i18n-polyglot@^5.3.3:
|
||||
version "5.3.3"
|
||||
resolved "https://registry.yarnpkg.com/ra-i18n-polyglot/-/ra-i18n-polyglot-5.3.3.tgz#d85c5b9496660454e815d64682f40dbd6ccb4347"
|
||||
integrity sha512-IqTg364wwPjz+DssVTKe6tKwyCp9336yHhjwil8/xnANLJvEVU6jz4JfQniT9RDg2HtA895hAR/o21dazzXsOg==
|
||||
dependencies:
|
||||
node-polyglot "^2.2.2"
|
||||
ra-core "^5.3.0"
|
||||
ra-core "^5.3.3"
|
||||
|
||||
ra-language-english@^5.3.0:
|
||||
version "5.3.0"
|
||||
resolved "https://registry.yarnpkg.com/ra-language-english/-/ra-language-english-5.3.0.tgz#f2811d9c72513c18ff0f48498bfa92f97911b4ad"
|
||||
integrity sha512-Gp8dt4annXcxFd7BJ/EgngLmI74A25++iwE5lS8WqD6yBL3byU5Xwu9+CQ8YQkU9+cQEFhLhkWIGfXXczxSymw==
|
||||
ra-language-english@^5.3.2, ra-language-english@^5.3.3:
|
||||
version "5.3.3"
|
||||
resolved "https://registry.yarnpkg.com/ra-language-english/-/ra-language-english-5.3.3.tgz#9f532dd2471d3b9ae818245044d186d5b27c707e"
|
||||
integrity sha512-MM8y1R+Ts8Q9Vn+lph27kFwscs+lzMb+xmtDSQIK0/1Fq8f96JA8ogw0u+lKGhTA7t1iudjulBlD/mnuYZJoGg==
|
||||
dependencies:
|
||||
ra-core "^5.3.0"
|
||||
ra-core "^5.3.3"
|
||||
|
||||
ra-language-farsi@^5.0.0:
|
||||
version "5.0.0"
|
||||
resolved "https://registry.npmjs.org/ra-language-farsi/-/ra-language-farsi-5.0.0.tgz"
|
||||
integrity sha512-wdveom01mdPY3KiFBWj4cc1f1YhWWi4pqNIuY79jgbJ43Kk72qOQIr3byWipy/Nt7dYzrAP3IvXmylWLLMmgnw==
|
||||
|
||||
ra-language-french@^5.3.0:
|
||||
version "5.3.0"
|
||||
resolved "https://registry.yarnpkg.com/ra-language-french/-/ra-language-french-5.3.0.tgz#ef173e56ed2bd24015dca7c9e918f5fe88b2cb47"
|
||||
integrity sha512-ybaI13CcE2XnDpvfSDKDHFNnUrOXArSxKnXER2CqE/3ED3VIqDbV/3QSK/eTIl5JRQEu1iZ3aTTX4sxGuK3xrg==
|
||||
ra-language-french@^5.3.3:
|
||||
version "5.3.3"
|
||||
resolved "https://registry.yarnpkg.com/ra-language-french/-/ra-language-french-5.3.3.tgz#38bfe37ef991a31596cd2b5230d0393a1c51a4ab"
|
||||
integrity sha512-N5r6qUpEIkyxU4dFf+57kBaugPPWJ1ZCJ0Y9bnqrvENdsxcYDZwXx1hWUP4TU69iynEnsCCwkl8Sxcbo37vJ2Q==
|
||||
dependencies:
|
||||
ra-core "^5.3.0"
|
||||
ra-core "^5.3.3"
|
||||
|
||||
ra-language-italian@^3.13.1:
|
||||
version "3.13.1"
|
||||
@@ -4774,10 +4703,10 @@ ra-language-russian@^4.14.2:
|
||||
dependencies:
|
||||
ra-core "^4.16.2"
|
||||
|
||||
ra-ui-materialui@^5.3.0:
|
||||
version "5.3.0"
|
||||
resolved "https://registry.yarnpkg.com/ra-ui-materialui/-/ra-ui-materialui-5.3.0.tgz#14b1c35f98a4d133dd0ef6be85191de71da88bb2"
|
||||
integrity sha512-jmEqI77LDcEbhrMC45QM1YmUMSOwzNH8dEjr9A/Xm+UW+YnzOFDkVJJumfP3jpFL4wviX48Qy5mBi54t19CYjw==
|
||||
ra-ui-materialui@^5.3.3:
|
||||
version "5.3.3"
|
||||
resolved "https://registry.yarnpkg.com/ra-ui-materialui/-/ra-ui-materialui-5.3.3.tgz#2f928e668c0242f2e103afc96016a108256dc23e"
|
||||
integrity sha512-zaODfIoN+uc/9wuzlgFA0CHWZPpHs8kxtSi4i2HwBEFY42x/UoPsCqsRgLYGGJofBqxlD1UqzFRuVAKTEM/1bg==
|
||||
dependencies:
|
||||
"@tanstack/react-query" "^5.8.4"
|
||||
autosuggest-highlight "^3.1.1"
|
||||
@@ -4792,19 +4721,19 @@ ra-ui-materialui@^5.3.0:
|
||||
react-error-boundary "^4.0.13"
|
||||
react-transition-group "^4.4.5"
|
||||
|
||||
react-admin@^5.3.0:
|
||||
version "5.3.0"
|
||||
resolved "https://registry.yarnpkg.com/react-admin/-/react-admin-5.3.0.tgz#c94dce0e96b949717e3c79df03b7cba133949ba1"
|
||||
integrity sha512-86M0c76ClN7mbMsONLY83lV32hAQREH1hnhHXANZPS4BnRSKSyFjI93Wke+TwUkWlYiqXlEwaYzISfDTTU3xqA==
|
||||
react-admin@^5.3.3:
|
||||
version "5.3.3"
|
||||
resolved "https://registry.yarnpkg.com/react-admin/-/react-admin-5.3.3.tgz#0db4d69db7eca3e0bfcb42858e069b6710c8bed8"
|
||||
integrity sha512-TAN3G7/JHQZpR1CieREjYFepSkQQdS4b70k060UVkeUL4RRU1c9whDfnSsUVuO56mnxTBKpQx0e/VHablSmBwA==
|
||||
dependencies:
|
||||
"@emotion/react" "^11.4.1"
|
||||
"@emotion/styled" "^11.3.0"
|
||||
"@mui/icons-material" "^5.15.20"
|
||||
"@mui/material" "^5.15.20"
|
||||
ra-core "^5.3.0"
|
||||
ra-i18n-polyglot "^5.3.0"
|
||||
ra-language-english "^5.3.0"
|
||||
ra-ui-materialui "^5.3.0"
|
||||
ra-core "^5.3.3"
|
||||
ra-i18n-polyglot "^5.3.3"
|
||||
ra-language-english "^5.3.3"
|
||||
ra-ui-materialui "^5.3.3"
|
||||
react-hook-form "^7.53.0"
|
||||
react-router "^6.22.0"
|
||||
react-router-dom "^6.22.0"
|
||||
@@ -4867,20 +4796,20 @@ react-refresh@^0.14.2:
|
||||
resolved "https://registry.npmjs.org/react-refresh/-/react-refresh-0.14.2.tgz"
|
||||
integrity sha512-jCvmsr+1IUSMUyzOkRcvnVbX3ZYC6g9TDrDbFuFmRDq7PD4yaGbLKNQL6k2jnArV8hjYxh7hVhAZB6s9HDGpZA==
|
||||
|
||||
react-router-dom@^6.22.0, react-router-dom@^6.27.0:
|
||||
version "6.27.0"
|
||||
resolved "https://registry.yarnpkg.com/react-router-dom/-/react-router-dom-6.27.0.tgz#8d7972a425fd75f91c1e1ff67e47240c5752dc3f"
|
||||
integrity sha512-+bvtFWMC0DgAFrfKXKG9Fc+BcXWRUO1aJIihbB79xaeq0v5UzfvnM5houGUm1Y461WVRcgAQ+Clh5rdb1eCx4g==
|
||||
react-router-dom@^6.22.0, react-router-dom@^6.28.0:
|
||||
version "6.28.0"
|
||||
resolved "https://registry.yarnpkg.com/react-router-dom/-/react-router-dom-6.28.0.tgz#f73ebb3490e59ac9f299377062ad1d10a9f579e6"
|
||||
integrity sha512-kQ7Unsl5YdyOltsPGl31zOjLrDv+m2VcIEcIHqYYD3Lp0UppLjrzcfJqDJwXxFw3TH/yvapbnUvPlAj7Kx5nbg==
|
||||
dependencies:
|
||||
"@remix-run/router" "1.20.0"
|
||||
react-router "6.27.0"
|
||||
"@remix-run/router" "1.21.0"
|
||||
react-router "6.28.0"
|
||||
|
||||
react-router@6.27.0, react-router@^6.22.0, react-router@^6.26.2:
|
||||
version "6.27.0"
|
||||
resolved "https://registry.yarnpkg.com/react-router/-/react-router-6.27.0.tgz#db292474926c814c996c0ff3ef0162d1f9f60ed4"
|
||||
integrity sha512-YA+HGZXz4jaAkVoYBE98VQl+nVzI+cVI2Oj/06F5ZM+0u3TgedN9Y9kmMRo2mnkSK2nCpNQn0DVob4HCsY/WLw==
|
||||
react-router@6.28.0, react-router@^6.22.0, react-router@^6.26.2:
|
||||
version "6.28.0"
|
||||
resolved "https://registry.yarnpkg.com/react-router/-/react-router-6.28.0.tgz#29247c86d7ba901d7e5a13aa79a96723c3e59d0d"
|
||||
integrity sha512-HrYdIFqdrnhDw0PqG/AKjAqEqM7AvxCz0DQ4h2W8k6nqmc5uRBYDag0SBxx9iYz5G8gnuNVLzUe13wl9eAsXXg==
|
||||
dependencies:
|
||||
"@remix-run/router" "1.20.0"
|
||||
"@remix-run/router" "1.21.0"
|
||||
|
||||
react-shallow-renderer@^16.15.0:
|
||||
version "16.15.0"
|
||||
@@ -4934,19 +4863,6 @@ redent@^3.0.0:
|
||||
indent-string "^4.0.0"
|
||||
strip-indent "^3.0.0"
|
||||
|
||||
reflect.getprototypeof@^1.0.4:
|
||||
version "1.0.6"
|
||||
resolved "https://registry.npmjs.org/reflect.getprototypeof/-/reflect.getprototypeof-1.0.6.tgz"
|
||||
integrity sha512-fmfw4XgoDke3kdI6h4xcUz1dG8uaiv5q9gcEwLS4Pnth2kxT+GZ7YehS1JTMGBQmtV7Y4GFGbs2re2NqhdozUg==
|
||||
dependencies:
|
||||
call-bind "^1.0.7"
|
||||
define-properties "^1.2.1"
|
||||
es-abstract "^1.23.1"
|
||||
es-errors "^1.3.0"
|
||||
get-intrinsic "^1.2.4"
|
||||
globalthis "^1.0.3"
|
||||
which-builtin-type "^1.1.3"
|
||||
|
||||
regenerator-runtime@^0.14.0:
|
||||
version "0.14.1"
|
||||
resolved "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.14.1.tgz"
|
||||
@@ -5524,14 +5440,14 @@ typed-array-length@^1.0.6:
|
||||
is-typed-array "^1.1.13"
|
||||
possible-typed-array-names "^1.0.0"
|
||||
|
||||
typescript-eslint@^8.11.0:
|
||||
version "8.11.0"
|
||||
resolved "https://registry.yarnpkg.com/typescript-eslint/-/typescript-eslint-8.11.0.tgz#74a0551972d675b4141672cec3acc5139b7399c0"
|
||||
integrity sha512-cBRGnW3FSlxaYwU8KfAewxFK5uzeOAp0l2KebIlPDOT5olVi65KDG/yjBooPBG0kGW/HLkoz1c/iuBFehcS3IA==
|
||||
typescript-eslint@^8.13.0:
|
||||
version "8.13.0"
|
||||
resolved "https://registry.yarnpkg.com/typescript-eslint/-/typescript-eslint-8.13.0.tgz#c7d92cc06188176c7d0e3825e10305b9c22fb102"
|
||||
integrity sha512-vIMpDRJrQd70au2G8w34mPps0ezFSPMEX4pXkTzUkrNbRX+36ais2ksGWN0esZL+ZMaFJEneOBHzCgSqle7DHw==
|
||||
dependencies:
|
||||
"@typescript-eslint/eslint-plugin" "8.11.0"
|
||||
"@typescript-eslint/parser" "8.11.0"
|
||||
"@typescript-eslint/utils" "8.11.0"
|
||||
"@typescript-eslint/eslint-plugin" "8.13.0"
|
||||
"@typescript-eslint/parser" "8.13.0"
|
||||
"@typescript-eslint/utils" "8.13.0"
|
||||
|
||||
typescript@^5.6.3:
|
||||
version "5.6.3"
|
||||
@@ -5548,7 +5464,7 @@ unbox-primitive@^1.0.2:
|
||||
has-symbols "^1.0.3"
|
||||
which-boxed-primitive "^1.0.2"
|
||||
|
||||
undici-types@~6.19.2:
|
||||
undici-types@~6.19.8:
|
||||
version "6.19.8"
|
||||
resolved "https://registry.npmjs.org/undici-types/-/undici-types-6.19.8.tgz"
|
||||
integrity sha512-ve2KP6f/JnbPBFyobGHuerC9g1FYGn/F8n1LWTwNxCEzd6IfqTwUQcNXgEtmmQ6DlRrC1hrSrBnCZPokRrDHjw==
|
||||
@@ -5689,34 +5605,6 @@ which-boxed-primitive@^1.0.2:
|
||||
is-string "^1.0.5"
|
||||
is-symbol "^1.0.3"
|
||||
|
||||
which-builtin-type@^1.1.3:
|
||||
version "1.1.4"
|
||||
resolved "https://registry.npmjs.org/which-builtin-type/-/which-builtin-type-1.1.4.tgz"
|
||||
integrity sha512-bppkmBSsHFmIMSl8BO9TbsyzsvGjVoppt8xUiGzwiu/bhDCGxnpOKCxgqj6GuyHE0mINMDecBFPlOm2hzY084w==
|
||||
dependencies:
|
||||
function.prototype.name "^1.1.6"
|
||||
has-tostringtag "^1.0.2"
|
||||
is-async-function "^2.0.0"
|
||||
is-date-object "^1.0.5"
|
||||
is-finalizationregistry "^1.0.2"
|
||||
is-generator-function "^1.0.10"
|
||||
is-regex "^1.1.4"
|
||||
is-weakref "^1.0.2"
|
||||
isarray "^2.0.5"
|
||||
which-boxed-primitive "^1.0.2"
|
||||
which-collection "^1.0.2"
|
||||
which-typed-array "^1.1.15"
|
||||
|
||||
which-collection@^1.0.2:
|
||||
version "1.0.2"
|
||||
resolved "https://registry.npmjs.org/which-collection/-/which-collection-1.0.2.tgz"
|
||||
integrity sha512-K4jVyjnBdgvc86Y6BkaLZEN933SwYOuBFkdmBu9ZfkcAbdVbpITnDmjvZ/aQjRXQrv5EPkTnD1s39GiiqbngCw==
|
||||
dependencies:
|
||||
is-map "^2.0.3"
|
||||
is-set "^2.0.3"
|
||||
is-weakmap "^2.0.2"
|
||||
is-weakset "^2.0.3"
|
||||
|
||||
which-typed-array@^1.1.14, which-typed-array@^1.1.15:
|
||||
version "1.1.15"
|
||||
resolved "https://registry.npmjs.org/which-typed-array/-/which-typed-array-1.1.15.tgz"
|
||||
|
Reference in New Issue
Block a user