Compare commits
34 Commits
v0.10.3-et
...
v0.10.3-et
Author | SHA1 | Date | |
---|---|---|---|
![]() |
cb1314ab1d | ||
![]() |
dae6872fe8 | ||
![]() |
61b91adf25 | ||
![]() |
5f7f587477 | ||
![]() |
75b9aeea01 | ||
![]() |
fb71b5ed08 | ||
![]() |
2e8e5e73bc | ||
![]() |
befcd15298 | ||
![]() |
86d0fd04e6 | ||
![]() |
c28ed94ca0 | ||
![]() |
d139ab4a7d | ||
![]() |
6575a05a8a | ||
![]() |
3f2c3f2c0c | ||
![]() |
2c5ee7da10 | ||
![]() |
03bf4a5c5d | ||
![]() |
3fce37b735 | ||
![]() |
6c6ec227fa | ||
![]() |
128fea726e | ||
![]() |
97c44f85ef | ||
![]() |
ca2decda3a | ||
![]() |
e394a7e186 | ||
![]() |
c182f600f8 | ||
![]() |
915e3564f8 | ||
![]() |
1570ca5485 | ||
![]() |
b94b782547 | ||
![]() |
90328a5b19 | ||
![]() |
b42eb07a2f | ||
![]() |
131bfaaece | ||
![]() |
b759d5d5fb | ||
![]() |
003e9da792 | ||
![]() |
908271060b | ||
![]() |
08cd427084 | ||
![]() |
73a1d952b1 | ||
![]() |
1d5511421d |
237
README.md
237
README.md
@@ -5,28 +5,29 @@
|
||||
<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">
|
||||
<a href="./LICENSE">
|
||||
<img alt="License" src="https://img.shields.io/github/license/etkecc/synapse-admin">
|
||||
</a>
|
||||
</h3>
|
||||
<p align="center">Manager your Synapse homeserver with ease</p>
|
||||
<p align="center">Feature-packed and visually customizable: A better way to manage your Synapse homeserver.</p>
|
||||
</p>
|
||||
|
||||
---
|
||||
|
||||

|
||||
|
||||
This project is built using [react-admin](https://marmelab.com/react-admin/).
|
||||

|
||||

|
||||
|
||||
<!-- vim-markdown-toc GFM -->
|
||||
|
||||
* [Fork differences](#fork-differences)
|
||||
* [Availability](#availability)
|
||||
* [Changes](#changes)
|
||||
* [Development](#development)
|
||||
* [Support](#support)
|
||||
* [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)
|
||||
* [Providing support URL](#providing-support-url)
|
||||
* [Usage](#usage)
|
||||
* [Supported Synapse](#supported-synapse)
|
||||
* [Prerequisites](#prerequisites)
|
||||
@@ -42,55 +43,61 @@ This project is built using [react-admin](https://marmelab.com/react-admin/).
|
||||
|
||||
## Fork differences
|
||||
|
||||
With [Awesome-Technologies/synapse-admin](https://github.com/Awesome-Technologies/synapse-admin) as the upstream, this
|
||||
fork is intended to be a more feature-rich version of the original project. The main goal is to provide a more
|
||||
user-friendly interface for managing Synapse homeservers.
|
||||
With [Awesome-Technologies/synapse-admin](https://github.com/Awesome-Technologies/synapse-admin) as the upstream,
|
||||
this fork introduces numerous enhancements to improve usability and extend functionality,
|
||||
including support for authenticated media, advanced user management options, and visual customization.
|
||||
The full list is described below in the [Changes](#changes) section.
|
||||
|
||||
### Availability
|
||||
**Availability**
|
||||
|
||||
* As a core/default component on [etke.cc](https://etke.cc/?utm_source=github&utm_medium=readme&utm_campaign=synapse-admin)
|
||||
* Via CDN on [admin.etke.cc](https://admin.etke.cc)
|
||||
* As a standalone app on [admin.etke.cc](https://admin.etke.cc)
|
||||
* As a prebuilt distribution on [GitHub Releases](https://github.com/etkecc/synapse-admin/releases)
|
||||
* As a Docker container on [GitHub Container Registry](https://github.com/etkecc/synapse-admin/pkgs/container/synapse-admin)
|
||||
* As a component in [Matrix-Docker-Ansible-Deploy Playbook](https://github.com/spantaleev/matrix-docker-ansible-deploy/blob/master/docs/configuring-playbook-synapse-admin.md)
|
||||
|
||||
### Changes
|
||||
|
||||
The following changes are already implemented:
|
||||
|
||||
* [Prevent admins from deleting themselves](https://github.com/etkecc/synapse-admin/pull/1)
|
||||
* [Fix user's default tab not being shown](https://github.com/etkecc/synapse-admin/pull/8)
|
||||
* [Add identifier when authorizing with password](https://github.com/Awesome-Technologies/synapse-admin/pull/601)
|
||||
* [Add ability to toggle whether to show locked users](https://github.com/Awesome-Technologies/synapse-admin/pull/573)
|
||||
* [Fix user's display name in header on user's page](https://github.com/etkecc/synapse-admin/pull/9)
|
||||
* [Fix footer overlapping content](https://github.com/Awesome-Technologies/synapse-admin/issues/574)
|
||||
* Switch from nginx to [SWS](https://static-web-server.net/) for serving the app, reducing the size of the Docker image
|
||||
* [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) (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)
|
||||
* [Expose user avatar URL field in the UI](https://github.com/etkecc/synapse-admin/pull/27)
|
||||
* [Upgrade react-admin to v5](https://github.com/etkecc/synapse-admin/pull/40)
|
||||
* [Restrict actions on specific users](https://github.com/etkecc/synapse-admin/pull/42)
|
||||
* [Add `Contact support` menu item](https://github.com/etkecc/synapse-admin/pull/45)
|
||||
* [Provide options to delete media and redact events on user erase](https://github.com/etkecc/synapse-admin/pull/49)
|
||||
* [Authenticated Media support](https://github.com/etkecc/synapse-admin/pull/51)
|
||||
* [Better media preview/download](https://github.com/etkecc/synapse-admin/pull/53)
|
||||
* [Login with access token](https://github.com/etkecc/synapse-admin/pull/58)
|
||||
* [Fix footer causing vertical scrollbar](https://github.com/etkecc/synapse-admin/pull/60)
|
||||
* [Custom Menu Items](https://github.com/etkecc/synapse-admin/pull/79)
|
||||
* [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 admins from deleting themselves](https://github.com/etkecc/synapse-admin/pull/1)
|
||||
* 🐛 [Fix user's default tab not being shown](https://github.com/etkecc/synapse-admin/pull/8)
|
||||
* 🔑 [Add identifier when authorizing with password](https://github.com/Awesome-Technologies/synapse-admin/pull/601)
|
||||
* 🔒 [Add ability to toggle whether to show locked users](https://github.com/Awesome-Technologies/synapse-admin/pull/573)
|
||||
* 🖊️ [Fix user's display name in header on user's page](https://github.com/etkecc/synapse-admin/pull/9)
|
||||
* 🧹 [Fix footer overlapping content](https://github.com/Awesome-Technologies/synapse-admin/issues/574)
|
||||
* 🐋 Switch from nginx to [SWS](https://static-web-server.net/) for serving the app, reducing the size of the Docker image
|
||||
* 🔄 [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) (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)
|
||||
* 🖼️ [Expose user avatar URL field in the UI](https://github.com/etkecc/synapse-admin/pull/27)
|
||||
* 🚀 [Upgrade react-admin to v5](https://github.com/etkecc/synapse-admin/pull/40)
|
||||
* 🔒 [Restrict actions on specific users](https://github.com/etkecc/synapse-admin/pull/42)
|
||||
* 📞 [Add `Contact support` menu item](https://github.com/etkecc/synapse-admin/pull/45)
|
||||
* 🧹 [Provide options to delete media and redact events on user erase](https://github.com/etkecc/synapse-admin/pull/49)
|
||||
* 🎞️ [Authenticated Media support](https://github.com/etkecc/synapse-admin/pull/51)
|
||||
* 👁️ [Better media preview/download](https://github.com/etkecc/synapse-admin/pull/53)
|
||||
* 🔐 [Login with access token](https://github.com/etkecc/synapse-admin/pull/58)
|
||||
* 📏 [Fix footer causing vertical scrollbar](https://github.com/etkecc/synapse-admin/pull/60)
|
||||
* 🍴 [Custom Menu Items](https://github.com/etkecc/synapse-admin/pull/79)
|
||||
* 🧑💻 [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)
|
||||
* 🎨 [Add preferred theme colors to login page and footer](https://github.com/etkecc/synapse-admin/pull/155)
|
||||
* 🔰 [Add "Assign Admin" button to the rooms](https://github.com/etkecc/synapse-admin/pull/156)
|
||||
|
||||
_the list will be updated as new changes are added_
|
||||
|
||||
@@ -99,12 +106,19 @@ _the list will be updated as new changes are added_
|
||||
`just run-dev` to start the development stack (depending on your system speed, you may want to re-run this command if
|
||||
user creation fails)
|
||||
|
||||
This command initializes the development environment (local Synapse server and Postgres DB),
|
||||
and launches the app in a dev mode at `http://localhost:5173`
|
||||
|
||||
After that open `http://localhost:5173` in your browser, login using the following credentials:
|
||||
|
||||
* Login: admin
|
||||
* Password: admin
|
||||
* Homeserver URL: http://localhost:8008
|
||||
|
||||
### Support
|
||||
|
||||
If you have any questions or need help, feel free to join the [community room](https://matrix.to/#/#synapse-admin:etke.cc) or create an issue on GitHub.
|
||||
|
||||
## Configuration
|
||||
|
||||
You can use `config.json` file to configure Synapse Admin instance,
|
||||
@@ -113,6 +127,12 @@ In the latter case, any instance of Synapse Admin will automatically pick up the
|
||||
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.
|
||||
|
||||
[Configuration options](./docs/config.md)
|
||||
|
||||
The `config.json` can be injected into a Docker container using a bind mount.
|
||||
|
||||
```yml
|
||||
@@ -124,124 +144,35 @@ 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.
|
||||
|
||||
Edit `config.json` to restrict either to a single homeserver:
|
||||
|
||||
```json
|
||||
{
|
||||
"restrictBaseUrl": "https://your-matrixs-erver.example.com"
|
||||
}
|
||||
```
|
||||
|
||||
similar for `/.well-known/matrix/client`:
|
||||
|
||||
```json
|
||||
{
|
||||
"cc.etke.synapse-admin": {
|
||||
"restrictBaseUrl": "https://your-matrixs-erver.example.com"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
or to a list of homeservers:
|
||||
|
||||
```json
|
||||
{
|
||||
"restrictBaseUrl": ["https://your-first-matrix-server.example.com", "https://your-second-matrix-server.example.com"]
|
||||
}
|
||||
```
|
||||
|
||||
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"]
|
||||
}
|
||||
}
|
||||
```
|
||||
[Documentation](./docs/restrict-hs.md)
|
||||
|
||||
### Protecting appservice managed users
|
||||
|
||||
To avoid accidental adjustments of appservice-managed users (e.g., puppets created by a bridge) and breaking the bridge,
|
||||
you can specify the list of MXIDs (regexp) that should be prohibited from any changes, except display name and avatar.
|
||||
|
||||
Example for [mautrix-telegram](https://github.com/mautrix/telegram)
|
||||
|
||||
```json
|
||||
{
|
||||
"asManagedUsers": ["^@telegram_[a-zA-Z0-9]+:example\\.com$"]
|
||||
}
|
||||
```
|
||||
|
||||
similar for `/.well-known/matrix/client`:
|
||||
|
||||
```json
|
||||
{
|
||||
"cc.etke.synapse-admin": {
|
||||
"asManagedUsers": ["^@telegram_[a-zA-Z0-9]+:example\\.com$"]
|
||||
}
|
||||
}
|
||||
```
|
||||
[Documentation](./docs/system-users.md)
|
||||
|
||||
### Adding custom menu items
|
||||
|
||||
You can add custom menu items to the main menu by providing a `menu` array in the `config.json`.
|
||||
You can add custom menu items to the main menu by providing a `menu` array in the config.
|
||||
|
||||
```json
|
||||
{
|
||||
"menu": [
|
||||
{
|
||||
"label": "Contact support",
|
||||
"icon": "SupportAgent",
|
||||
"url": "https://github.com/etkecc/synapse-admin/issues"
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
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`.~~
|
||||
|
||||
```json
|
||||
{
|
||||
"supportURL": "https://example.com/support"
|
||||
}
|
||||
```
|
||||
|
||||
similar for `/.well-known/matrix/client`:
|
||||
|
||||
```json
|
||||
{
|
||||
"cc.etke.synapse-admin": {
|
||||
"supportURL": "https://example.com/support"
|
||||
}
|
||||
}
|
||||
```
|
||||
[Documentation](./docs/custom-menu.md)
|
||||
|
||||
## Usage
|
||||
|
||||
@@ -290,6 +221,8 @@ You have three options:
|
||||
- move or symlink the `synapse-admin` into your vhosts root dir
|
||||
- open the url of the vhost in your browser
|
||||
|
||||
[Reverse Proxy Documentation with Examples](./docs/reverse-proxy.md)
|
||||
|
||||
#### Steps for 2)
|
||||
|
||||
- make sure you have installed the following: git, yarn, nodejs
|
||||
@@ -348,7 +281,7 @@ services:
|
||||
- /var/run/docker.sock:/var/run/docker.sock:ro
|
||||
|
||||
synapse-admin:
|
||||
image: etkecc/synapse-admin:latest
|
||||
image: ghcr.io/etkecc/synapse-admin:latest
|
||||
restart: unless-stopped
|
||||
labels:
|
||||
- "traefik.enable=true"
|
||||
|
94
docs/config.md
Normal file
94
docs/config.md
Normal file
@@ -0,0 +1,94 @@
|
||||
# Configuration
|
||||
|
||||
Synapse Admin could be configured using the following ways (both are optional, and both could be used together):
|
||||
|
||||
* By providing the `config.json` file alongside with the Synapse Admin deployment, example: [admin.etke.cc/config.json](https://admin.etke.cc/config.json)
|
||||
* By providing configuration under the `cc.etke.synapse-admin` key in the `/.well-known/matrix/client` file, example:
|
||||
[demo.etke.host/.well-known/matrix/client](https://demo.etke.host/.well-known/matrix/client)
|
||||
|
||||
In case you are an [etke.cc](https://etke.cc) customer,
|
||||
or 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.
|
||||
|
||||
**Why `/.well-known/matrix/client`?**
|
||||
|
||||
Because any instance of Synapse Admin will automatically pick up the configuration from the homeserver.
|
||||
Common use case when you have a Synapse server running, but don't want (or can't) deploy Synapse Admin alongside with it.
|
||||
In this case, you could provide the configuration in the `/.well-known/matrix/client` file,
|
||||
and any Synapse Admin instance (e.g., [admin.etke.cc](https://admin.etke.cc) will pick it up.
|
||||
|
||||
Another common case is when you have multiple Synapse servers running and want to use a single Synapse Admin instance to manage them all.
|
||||
In this case, you could provide the configuration in the `/.well-known/matrix/client` file for each of the servers.
|
||||
|
||||
## Configuration options
|
||||
|
||||
* `restrictBaseUrl` - restrictBaseUrl restricts the Synapse Admin instance to work only with specific homeserver(-s).
|
||||
It accepts both a string and an array of strings.
|
||||
The homeserver URL should be the _actual_ homeserver URL, and not the delegated one.
|
||||
Example: `https://matrix.example.com` or `https://synapse.example.net`
|
||||
[More details](restrict-hs.md)
|
||||
* `asManagedUsers` - protect system user accounts managed by appservices (such as bridges) / system (such as bots) from accidental changes.
|
||||
By defining a list of MXID regex patterns, you can protect these accounts from accidental changes.
|
||||
Example: `^@baibot:example\\.com$`, `^@slackbot:example\\.com$`, `^@slack_[a-zA-Z0-9\\-]+:example\\.com$`, `^@telegrambot:example\\.com$`, `^@telegram_[a-zA-Z0-9]+:example\\.com$`
|
||||
[More details](system-users.md)
|
||||
* `menu` - add custom menu items to the main menu (sidebar) by providing a `menu` array in the config.
|
||||
Each `menu` item can contain the following fields:
|
||||
* `label` (required): The text to display in the menu.
|
||||
* `icon` (optional): The icon to display next to the label, one of the [../src/components/icons.ts] icons, otherwise a default icon will be used.
|
||||
* `url` (required): The URL to navigate to when the menu item is clicked.
|
||||
[More details](custom-menu.md)
|
||||
|
||||
## Examples
|
||||
|
||||
### config.json
|
||||
|
||||
```json
|
||||
{
|
||||
"restrictBaseUrl": [
|
||||
"https://matrix.example.com",
|
||||
"https://synapse.example.net"
|
||||
],
|
||||
"asManagedUsers": [
|
||||
"^@baibot:example\\.com$",
|
||||
"^@slackbot:example\\.com$",
|
||||
"^@slack_[a-zA-Z0-9\\-]+:example\\.com$",
|
||||
"^@telegrambot:example\\.com$",
|
||||
"^@telegram_[a-zA-Z0-9]+:example\\.com$"
|
||||
],
|
||||
"menu": [
|
||||
{
|
||||
"label": "Contact support",
|
||||
"icon": "SupportAgent",
|
||||
"url": "https://github.com/etkecc/synapse-admin/issues"
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
### `/.well-known/matrix/client`
|
||||
|
||||
```json
|
||||
{
|
||||
"cc.etke.synapse-admin": {
|
||||
"restrictBaseUrl": [
|
||||
"https://matrix.example.com",
|
||||
"https://synapse.example.net"
|
||||
],
|
||||
"asManagedUsers": [
|
||||
"^@baibot:example\\.com$",
|
||||
"^@slackbot:example\\.com$",
|
||||
"^@slack_[a-zA-Z0-9\\-]+:example\\.com$",
|
||||
"^@telegrambot:example\\.com$",
|
||||
"^@telegram_[a-zA-Z0-9]+:example\\.com$"
|
||||
],
|
||||
"menu": [
|
||||
{
|
||||
"label": "Contact support",
|
||||
"icon": "SupportAgent",
|
||||
"url": "https://github.com/etkecc/synapse-admin/issues"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
```
|
47
docs/custom-menu.md
Normal file
47
docs/custom-menu.md
Normal file
@@ -0,0 +1,47 @@
|
||||
# Custom Menu Items
|
||||
|
||||
You can add custom menu items to the main menu (sidebar) by providing a `menu` array in the config.
|
||||
This is useful for adding links to external sites or other pages in your documentation, like a support page or internal wiki.
|
||||
|
||||
## Configuration
|
||||
|
||||
The examples below contain the configuration settings to add a link to the [Synapse Admin issues](https://github.com/etke.cc/synapse-admin/issues).
|
||||
|
||||
Each `menu` item can contain the following fields:
|
||||
|
||||
* `label` (required): The text to display in the menu.
|
||||
* `icon` (optional): The icon to display next to the label, one of the [../src/components/icons.ts] icons, otherwise a
|
||||
default icon will be used.
|
||||
* `url` (required): The URL to navigate to when the menu item is clicked.
|
||||
|
||||
[Configuration options](config.md)
|
||||
|
||||
### config.json
|
||||
|
||||
```json
|
||||
{
|
||||
"menu": [
|
||||
{
|
||||
"label": "Contact support",
|
||||
"icon": "SupportAgent",
|
||||
"url": "https://github.com/etkecc/synapse-admin/issues"
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
### `/.well-known/matrix/client`
|
||||
|
||||
```json
|
||||
{
|
||||
"cc.etke.synapse-admin": {
|
||||
"menu": [
|
||||
{
|
||||
"label": "Contact support",
|
||||
"icon": "SupportAgent",
|
||||
"url": "https://github.com/etkecc/synapse-admin/issues"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
```
|
44
docs/restrict-hs.md
Normal file
44
docs/restrict-hs.md
Normal file
@@ -0,0 +1,44 @@
|
||||
# Restricting available homeserver
|
||||
|
||||
If you want to have your Synapse Admin instance work only with specific homeserver(-s),
|
||||
you can do that by setting `restrictBaseUrl` in the configuration.
|
||||
|
||||
## Configuration
|
||||
|
||||
You can do that for a single homeserver or multiple homeservers at once, as `restrictBaseUrl` accepts both a string and
|
||||
an array of strings.
|
||||
|
||||
The examples below contain the configuration settings to restrict the Synapse Admin instance to work only with
|
||||
`example.com` (with Synapse runing at `matrix.example.com`) and
|
||||
`example.net` (with Synapse running at `synapse.example.net`) homeservers.
|
||||
Note that the homeserver URL should be the _actual_ homeserver URL, and not the delegated one.
|
||||
|
||||
So, if you have a homeserver `example.com` where users have MXIDs like `@user:example.com`,
|
||||
but actual Synapse is installed on `matrix.example.com` subdomain, you should use `https://matrix.example.com` in the
|
||||
configuration.
|
||||
|
||||
[Configuration options](config.md)
|
||||
|
||||
### config.json
|
||||
|
||||
```json
|
||||
{
|
||||
"restrictBaseUrl": [
|
||||
"https://matrix.example.com",
|
||||
"https://synapse.example.net"
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
### `/.well-known/matrix/client`
|
||||
|
||||
```json
|
||||
{
|
||||
"cc.etke.synapse-admin": {
|
||||
"restrictBaseUrl": [
|
||||
"https://matrix.example.com",
|
||||
"https://synapse.example.net"
|
||||
]
|
||||
}
|
||||
}
|
||||
```
|
53
docs/reverse-proxy.md
Normal file
53
docs/reverse-proxy.md
Normal file
@@ -0,0 +1,53 @@
|
||||
# Serving Synapse Admin behind a reverse proxy
|
||||
|
||||
Your are supposed to do so for any service you want to expose to the internet,
|
||||
and here you can find specific instructions and example configurations for Synapse Admin.
|
||||
|
||||
## Nginx
|
||||
|
||||
Place the config below into `/etc/nginx/conf.d/synapse-admin.conf` (don't forget to replace `server_name` and `root`):
|
||||
|
||||
```nginx
|
||||
server {
|
||||
listen 80;
|
||||
listen [::]:80;
|
||||
server_name example.com; # REPLACE with your domain
|
||||
root /var/www/synapse-admin; # REPLACE with path where you extracted synapse admin
|
||||
index index.html;
|
||||
location / {
|
||||
try_files $uri $uri/ /index.html;
|
||||
}
|
||||
location ~* \.(?:css|js|jpg|jpeg|gif|png|svg|ico|woff|woff2|ttf|eot|webp)$ {
|
||||
expires 30d; # Set caching for static assets
|
||||
add_header Cache-Control "public";
|
||||
}
|
||||
|
||||
gzip on;
|
||||
gzip_types text/plain application/javascript application/json text/css text/xml application/xml+rss;
|
||||
gzip_min_length 1000;
|
||||
}
|
||||
```
|
||||
|
||||
After you've done that, ensure that the configuration is correct by running `nginx -t` and then reload Nginx
|
||||
(e.g. `systemctl reload nginx`).
|
||||
|
||||
> **Note:** This configuration doesn't cover HTTPS, which is highly recommended to use. You can find more information
|
||||
about setting up HTTPS in the [Nginx documentation](https://nginx.org/en/docs/http/configuring_https_servers.html).
|
||||
|
||||
## Traefik (docker labels)
|
||||
|
||||
If you are using Traefik as a reverse proxy, you can use the following labels, `docker-compose.yml` example:
|
||||
|
||||
```yaml
|
||||
services:
|
||||
synapse-admin:
|
||||
image: ghcr.io/etkecc/synapse-admin:latest
|
||||
restart: unless-stopped
|
||||
labels:
|
||||
- "traefik.enable=true"
|
||||
- "traefik.http.routers.synapse-admin.rule=Host(`example.com`)"
|
||||
```
|
||||
|
||||
## Other reverse proxies
|
||||
|
||||
There is no examples for other reverse proxies yet, and so PRs are greatly appreciated.
|
44
docs/system-users.md
Normal file
44
docs/system-users.md
Normal file
@@ -0,0 +1,44 @@
|
||||
# System / Appservice-managed Users
|
||||
|
||||
Inadvertently altering system user accounts managed by appservices (such as bridges) / system (such as bots) is a common issue.
|
||||
Editing, deleting, locking, or changing the passwords of these appservice-managed accounts can cause serious problems.
|
||||
To prevent this, we've added a new feature that blocks these types of modifications to such accounts,
|
||||
while still allowing other risk-free changes (changing display names and avatars).
|
||||
By defining a list of MXID regex patterns in the new `asManagedUsers` configuration setting,
|
||||
you can protect these accounts from accidental changes.
|
||||
|
||||
## Configuration
|
||||
|
||||
The examples below contain the configuration settings to mark
|
||||
[Telegram bridge (mautrix-telegram)](https://github.com/mautrix/telegram),
|
||||
[Slack bridge (mautrix-slack)](https://github.com/mautrix/slack),
|
||||
and [Baibot](https://github.com/etkecc/baibot) users of `example.com` homeserver as appservice-managed users,
|
||||
just to illustrate the options to protect both specific MXIDs (as in the Baibot example) and all puppets of a bridge (as in the Telegram and Slack examples).
|
||||
|
||||
[Configuration options](config.md)
|
||||
|
||||
### config.json
|
||||
|
||||
```json
|
||||
"asManagedUsers": [
|
||||
"^@baibot:example\\.com$",
|
||||
"^@slackbot:example\\.com$",
|
||||
"^@slack_[a-zA-Z0-9\\-]+:example\\.com$",
|
||||
"^@telegrambot:example\\.com$",
|
||||
"^@telegram_[a-zA-Z0-9]+:example\\.com$"
|
||||
]
|
||||
```
|
||||
|
||||
### `/.well-known/matrix/client`
|
||||
|
||||
```json
|
||||
"cc.etke.synapse-admin": {
|
||||
"asManagedUsers": [
|
||||
"^@baibot:example\\.com$",
|
||||
"^@slackbot:example\\.com$",
|
||||
"^@slack_[a-zA-Z0-9\\-]+:example\\.com$",
|
||||
"^@telegrambot:example\\.com$",
|
||||
"^@telegram_[a-zA-Z0-9]+:example\\.com$"
|
||||
]
|
||||
}
|
||||
```
|
28
package.json
28
package.json
@@ -21,10 +21,10 @@
|
||||
"@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/eslint-plugin": "^8.14.0",
|
||||
"@typescript-eslint/parser": "^8.13.0",
|
||||
"@vitejs/plugin-react": "^4.3.3",
|
||||
"eslint": "^9.13.0",
|
||||
"eslint": "^9.15.0",
|
||||
"eslint-config-prettier": "^9.1.0",
|
||||
"eslint-plugin-import": "^2.31.0",
|
||||
"eslint-plugin-jsx-a11y": "^6.10.2",
|
||||
@@ -39,8 +39,8 @@
|
||||
"ts-jest": "^29.2.5",
|
||||
"ts-node": "^10.9.2",
|
||||
"typescript": "^5.6.3",
|
||||
"typescript-eslint": "^8.12.2",
|
||||
"vite": "^5.4.10",
|
||||
"typescript-eslint": "^8.13.0",
|
||||
"vite": "^5.4.11",
|
||||
"vite-plugin-version-mark": "^0.1.2"
|
||||
},
|
||||
"dependencies": {
|
||||
@@ -48,27 +48,27 @@
|
||||
"@emotion/styled": "^11.13.0",
|
||||
"@haleos/ra-language-german": "^1.0.0",
|
||||
"@haxqer/ra-language-chinese": "^4.16.2",
|
||||
"@mui/icons-material": "^6.1.5",
|
||||
"@mui/material": "^6.1.6",
|
||||
"@mui/icons-material": "^6.1.7",
|
||||
"@mui/material": "^6.1.7",
|
||||
"@mui/utils": "^5.16.6",
|
||||
"@tanstack/react-query": "^5.59.19",
|
||||
"@tanstack/react-query": "^5.60.5",
|
||||
"history": "^5.3.0",
|
||||
"lodash": "^4.17.21",
|
||||
"papaparse": "^5.4.1",
|
||||
"ra-core": "^5.3.2",
|
||||
"ra-i18n-polyglot": "^5.3.2",
|
||||
"ra-language-english": "^5.3.2",
|
||||
"ra-core": "^5.3.4",
|
||||
"ra-i18n-polyglot": "^5.3.4",
|
||||
"ra-language-english": "^5.3.4",
|
||||
"ra-language-farsi": "^5.0.0",
|
||||
"ra-language-french": "^5.3.1",
|
||||
"ra-language-french": "^5.3.4",
|
||||
"ra-language-italian": "^3.13.1",
|
||||
"ra-language-russian": "^4.14.2",
|
||||
"react": "^18.3.1",
|
||||
"react-admin": "^5.3.1",
|
||||
"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",
|
||||
|
BIN
screenshots/auth.webp
Normal file
BIN
screenshots/auth.webp
Normal file
Binary file not shown.
After Width: | Height: | Size: 83 KiB |
Before Width: | Height: | Size: 222 KiB After Width: | Height: | Size: 222 KiB |
@@ -7,6 +7,6 @@ import App from "./App";
|
||||
describe("App", () => {
|
||||
it("renders", async () => {
|
||||
render(<App />);
|
||||
await screen.findAllByText("Welcome to Synapse-admin");
|
||||
await screen.findAllByText("Welcome to Synapse Admin");
|
||||
});
|
||||
});
|
||||
|
@@ -23,7 +23,6 @@ import users from "./resources/users";
|
||||
import authProvider from "./synapse/authProvider";
|
||||
import dataProvider from "./synapse/dataProvider";
|
||||
import { QueryClient, QueryClientProvider } from "@tanstack/react-query";
|
||||
import Footer from "./components/Footer";
|
||||
|
||||
// TODO: Can we use lazy loading together with browser locale?
|
||||
const messages = {
|
||||
@@ -82,7 +81,6 @@ const App = () => (
|
||||
<Resource name="room_state" />
|
||||
<Resource name="destination_rooms" />
|
||||
</Admin>
|
||||
<Footer />
|
||||
</QueryClientProvider>
|
||||
);
|
||||
|
||||
|
@@ -1,8 +1,9 @@
|
||||
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";
|
||||
import Footer from "./Footer";
|
||||
|
||||
const AdminUserMenu = () => {
|
||||
const [open, setOpen] = useState(false);
|
||||
@@ -88,8 +89,9 @@ const AdminMenu = (props) => {
|
||||
);
|
||||
};
|
||||
|
||||
export const AdminLayout = ({ children }) => (
|
||||
<Layout appBar={AdminAppBar} menu={AdminMenu} sx={{
|
||||
export const AdminLayout = ({ children }) => {
|
||||
return <>
|
||||
<Layout appBar={AdminAppBar} menu={AdminMenu} sx={{
|
||||
['& .RaLayout-appFrame']: {
|
||||
minHeight: '90vh',
|
||||
height: '90vh',
|
||||
@@ -98,6 +100,9 @@ export const AdminLayout = ({ children }) => (
|
||||
marginBottom: '3rem',
|
||||
},
|
||||
}}>
|
||||
{children}
|
||||
</Layout>
|
||||
);
|
||||
{children}
|
||||
<CheckForApplicationUpdate />
|
||||
</Layout>
|
||||
<Footer />
|
||||
</>
|
||||
};
|
@@ -1,8 +1,11 @@
|
||||
import { Avatar, Box, Link, Typography } from "@mui/material";
|
||||
import { useEffect, useState } from "react";
|
||||
import { useTheme } from "@mui/material/styles";
|
||||
|
||||
const Footer = () => {
|
||||
const [version, setVersion] = useState<string | null>(null);
|
||||
const theme = useTheme();
|
||||
|
||||
useEffect(() => {
|
||||
const version = document.getElementById("js-version")?.textContent;
|
||||
if (version) {
|
||||
@@ -17,23 +20,28 @@ const Footer = () => {
|
||||
zIndex: 100,
|
||||
bottom: 0,
|
||||
width: '100%',
|
||||
bgcolor: "#eee",
|
||||
bgcolor: theme.palette.background.default,
|
||||
color: theme.palette.text.primary,
|
||||
borderTop: '1px solid',
|
||||
borderColor: '#ddd',
|
||||
borderColor: theme.palette.divider,
|
||||
fontSize: '0.89rem',
|
||||
display: 'flex',
|
||||
flexDirection: 'row',
|
||||
alignItems: 'center',
|
||||
justifyContent: 'start',
|
||||
p: 1,
|
||||
gap: '10px'
|
||||
}}>
|
||||
<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
|
||||
</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> <Link sx={{ fontWeight: 'bold', color: "#000", textDecoration: 'none' }} href="https://matrix.to/#/#synapse-admin:etke.cc" target="_blank">#synapse-admin:etke.cc</Link>
|
||||
</Typography>
|
||||
<Link href="https://github.com/etkecc/synapse-admin" target="_blank">
|
||||
Synapse Admin {version}
|
||||
</Link>
|
||||
by
|
||||
<Link href="https://etke.cc/?utm_source=synapse-admin&utm_medium=footer&utm_campaign=synapse-admin" target="_blank">
|
||||
etke.cc
|
||||
</Link>
|
||||
(originally developed by Awesome Technologies Innovationslabor GmbH).
|
||||
<Link sx={{ fontWeight: 'bold' }} href="https://matrix.to/#/#synapse-admin:etke.cc" target="_blank">#synapse-admin:etke.cc</Link>
|
||||
</Box>
|
||||
);
|
||||
};
|
||||
|
@@ -2,57 +2,58 @@ import { styled } from "@mui/material/styles";
|
||||
import { Box } from "@mui/material";
|
||||
|
||||
const LoginFormBox = styled(Box)(({ theme }) => ({
|
||||
display: "flex",
|
||||
flexDirection: "column",
|
||||
minHeight: "calc(100vh - 1rem)",
|
||||
alignItems: "center",
|
||||
justifyContent: "flex-start",
|
||||
background: "url(./images/floating-cogs.svg)",
|
||||
backgroundColor: "#f9f9f9",
|
||||
backgroundRepeat: "no-repeat",
|
||||
backgroundSize: "cover",
|
||||
display: "flex",
|
||||
flexDirection: "column",
|
||||
minHeight: "calc(100vh - 1rem)",
|
||||
alignItems: "center",
|
||||
justifyContent: "flex-start",
|
||||
background: "url(./images/floating-cogs.svg)",
|
||||
backgroundColor: theme.palette.mode === 'dark' ? theme.palette.background.default : theme.palette.background.paper,
|
||||
backgroundRepeat: "no-repeat",
|
||||
backgroundSize: "cover",
|
||||
|
||||
[`& .card`]: {
|
||||
width: "30rem",
|
||||
marginTop: "6rem",
|
||||
marginBottom: "6rem",
|
||||
},
|
||||
[`& .avatar`]: {
|
||||
margin: "1rem",
|
||||
display: "flex",
|
||||
justifyContent: "center",
|
||||
},
|
||||
[`& .icon`]: {
|
||||
backgroundColor: theme.palette.grey[500],
|
||||
},
|
||||
[`& .hint`]: {
|
||||
marginTop: "1em",
|
||||
marginBottom: "1em",
|
||||
display: "flex",
|
||||
justifyContent: "center",
|
||||
color: theme.palette.grey[600],
|
||||
},
|
||||
[`& .form`]: {
|
||||
padding: "0 1rem 1rem 1rem",
|
||||
},
|
||||
[`& .select`]: {
|
||||
marginBottom: "2rem",
|
||||
},
|
||||
[`& .actions`]: {
|
||||
padding: "0 1rem 1rem 1rem",
|
||||
},
|
||||
[`& .serverVersion`]: {
|
||||
color: theme.palette.grey[500],
|
||||
fontFamily: "Roboto, Helvetica, Arial, sans-serif",
|
||||
marginLeft: "0.5rem",
|
||||
},
|
||||
[`& .matrixVersions`]: {
|
||||
color: theme.palette.grey[500],
|
||||
fontFamily: "Roboto, Helvetica, Arial, sans-serif",
|
||||
fontSize: "0.8rem",
|
||||
marginBottom: "1rem",
|
||||
marginLeft: "0.5rem",
|
||||
},
|
||||
}));
|
||||
[`& .card`]: {
|
||||
width: "30rem",
|
||||
marginTop: "6rem",
|
||||
marginBottom: "6rem",
|
||||
},
|
||||
[`& .avatar`]: {
|
||||
margin: "1rem",
|
||||
display: "flex",
|
||||
justifyContent: "center",
|
||||
},
|
||||
[`& .icon`]: {
|
||||
backgroundColor: theme.palette.grey[500],
|
||||
},
|
||||
[`& .hint`]: {
|
||||
marginTop: "1em",
|
||||
marginBottom: "1em",
|
||||
display: "flex",
|
||||
justifyContent: "center",
|
||||
color: theme.palette.grey[600],
|
||||
},
|
||||
[`& .form`]: {
|
||||
padding: "0 1rem 1rem 1rem",
|
||||
},
|
||||
[`& .select`]: {
|
||||
marginBottom: "2rem",
|
||||
},
|
||||
[`& .actions`]: {
|
||||
padding: "0 1rem 1rem 1rem",
|
||||
},
|
||||
[`& .serverVersion`]: {
|
||||
color: theme.palette.grey[500],
|
||||
fontFamily: "Roboto, Helvetica, Arial, sans-serif",
|
||||
marginLeft: "0.5rem",
|
||||
},
|
||||
[`& .matrixVersions`]: {
|
||||
color: theme.palette.grey[500],
|
||||
fontFamily: "Roboto, Helvetica, Arial, sans-serif",
|
||||
fontSize: "0.8rem",
|
||||
marginBottom: "1rem",
|
||||
marginLeft: "0.5rem",
|
||||
},
|
||||
}
|
||||
));
|
||||
|
||||
export default LoginFormBox;
|
||||
|
@@ -4,11 +4,16 @@ import { useDataProvider, useNotify, useRecordContext, useTranslate } from "reac
|
||||
import { TextField } from "@mui/material";
|
||||
import { useFormContext } from "react-hook-form";
|
||||
|
||||
const RateLimitRow = ({ limit, value, updateRateLimit }: { limit: string, value: number, updateRateLimit: (limit: string, value: number) => void }) => {
|
||||
const RateLimitRow = ({ limit, value, updateRateLimit }: { limit: string, value: any, updateRateLimit: (limit: string, value: any) => void }) => {
|
||||
const translate = useTranslate();
|
||||
|
||||
const handleChange = (event: React.ChangeEvent<HTMLInputElement>) => {
|
||||
updateRateLimit(limit, parseInt(event.target.value));
|
||||
const value = parseInt(event.target.value);
|
||||
if (isNaN(value)) {
|
||||
updateRateLimit(limit, null);
|
||||
return;
|
||||
}
|
||||
updateRateLimit(limit, value);
|
||||
};
|
||||
|
||||
return <Stack
|
||||
@@ -48,8 +53,8 @@ export const UserRateLimits = () => {
|
||||
const form = useFormContext();
|
||||
const dataProvider = useDataProvider();
|
||||
const [rateLimits, setRateLimits] = useState({
|
||||
messages_per_second: 0,
|
||||
burst_count: 0,
|
||||
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) {
|
||||
@@ -67,7 +72,7 @@ export const UserRateLimits = () => {
|
||||
fetchRateLimits();
|
||||
}, []);
|
||||
|
||||
const updateRateLimit = async (limit: string, value: number) => {
|
||||
const updateRateLimit = async (limit: string, value: any) => {
|
||||
let updatedRateLimits = { ...rateLimits, [limit]: value };
|
||||
setRateLimits(updatedRateLimits);
|
||||
form.setValue(`rates.${limit}`, value, { shouldDirty: true });
|
||||
|
@@ -37,7 +37,7 @@ const de: SynapseTranslationMessages = {
|
||||
synapseadmin: {
|
||||
auth: {
|
||||
base_url: "Heimserver URL",
|
||||
welcome: "Willkommen bei Synapse-admin",
|
||||
welcome: "Willkommen bei Synapse Admin",
|
||||
server_version: "Synapse Version",
|
||||
supports_specs: "unterstützt Matrix-Specs",
|
||||
username_error: "Bitte vollständigen Nutzernamen angeben: '@user:domain'",
|
||||
@@ -184,6 +184,7 @@ 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",
|
||||
@@ -191,10 +192,14 @@ const de: SynapseTranslationMessages = {
|
||||
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. 0 bedeutet, dass die Rate-Limitierung für diesen Benutzer deaktiviert ist.",
|
||||
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.",
|
||||
}
|
||||
@@ -255,6 +260,14 @@ const de: SynapseTranslationMessages = {
|
||||
success: "Raum/Räume erfolgreich gelöscht.",
|
||||
failure: "Der/die Raum/Räume konnten nicht gelöscht werden.",
|
||||
},
|
||||
make_admin: {
|
||||
assign_admin: "Raumadministrator zuweisen",
|
||||
title: "Raumadministrator zu %{roomName} zuweisen",
|
||||
confirm: "Raumadministrator zuweisen",
|
||||
content: "Geben Sie die vollständige MXID des Benutzers an, der als Administrator gesetzt werden soll.\nWarnung: Damit dies funktioniert, muss der Raum mindestens einen lokalen Mitglied als Administrator haben.",
|
||||
success: "Der/die Benutzer wurde/n als Raumadministrator gesetzt.",
|
||||
failure: "Der/die Benutzer konnte/n nicht als Raumadministrator gesetzt werden. %{errMsg}",
|
||||
}
|
||||
},
|
||||
},
|
||||
reports: {
|
||||
|
@@ -7,7 +7,7 @@ const en: SynapseTranslationMessages = {
|
||||
synapseadmin: {
|
||||
auth: {
|
||||
base_url: "Homeserver URL",
|
||||
welcome: "Welcome to Synapse-admin",
|
||||
welcome: "Welcome to Synapse Admin",
|
||||
server_version: "Synapse version",
|
||||
supports_specs: "supports Matrix specs",
|
||||
username_error: "Please enter fully qualified user ID: '@user:domain'",
|
||||
@@ -38,7 +38,7 @@ const en: SynapseTranslationMessages = {
|
||||
members: "Members",
|
||||
detail: "Details",
|
||||
permission: "Permissions",
|
||||
},
|
||||
}
|
||||
},
|
||||
reports: { tabs: { basic: "Basic", detail: "Details" } },
|
||||
},
|
||||
@@ -157,6 +157,7 @@ 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",
|
||||
@@ -164,10 +165,14 @@ const en: SynapseTranslationMessages = {
|
||||
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. 0 mean that ratelimiting is disabled for this user",
|
||||
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.",
|
||||
}
|
||||
@@ -228,6 +233,14 @@ const en: SynapseTranslationMessages = {
|
||||
success: "Room/s successfully deleted.",
|
||||
failure: "The room/s could not be deleted.",
|
||||
},
|
||||
make_admin: {
|
||||
assign_admin: "Assign admin",
|
||||
title: "Assign a room admin to %{roomName}",
|
||||
confirm: "Make admin",
|
||||
content: "Put the full MXID of the user which will be set as admin.\nWarning: for this to work, the room needs to have at least one local member as admin.",
|
||||
success: "The user has been set as room admin.",
|
||||
failure: "The user could not be set as room admin. %{errMsg}",
|
||||
}
|
||||
},
|
||||
},
|
||||
reports: {
|
||||
|
@@ -149,6 +149,7 @@ const fa: SynapseTranslationMessages = {
|
||||
erase_text: "وهذا يعني أن الرسائل المرسلة من قبل المستخدم (المستخدمين) ستظل مرئية من قبل أي شخص كان في الغرفة عند إرسال هذه الرسائل، ولكنها مخفية عن المستخدمين الذين ينضمون إلى الغرفة بعد ذلك.",
|
||||
erase_admin_error: "حذف المستخدم الخاص غير مسموح به.",
|
||||
modify_managed_user_error: "لا يُسمح بتغيير المستخدم الذي يديره النظام.",
|
||||
username_available: "نام کاربری موجود",
|
||||
},
|
||||
action: {
|
||||
erase: "پاک کردن اطلاعات کاربر",
|
||||
@@ -156,10 +157,14 @@ const fa: SynapseTranslationMessages = {
|
||||
delete_media: "حذف جميع الوسائط التي تم تحميلها بواسطة المستخدم (المستخدمين)",
|
||||
redact_events: "تنقيح جميع الأحداث المرسلة من قبل المستخدم (-s)",
|
||||
generate_password: "توليد رمز عبور",
|
||||
overwrite_title: "هشدار!",
|
||||
overwrite_content: "این نام کاربری قبلا استفاده شده است. آیا مطمئن هستید که می خواهید کاربر موجود را بازنویسی کنید؟",
|
||||
overwrite_cancel: "انصراف",
|
||||
overwrite_confirm: "بازنویسی",
|
||||
},
|
||||
limits: {
|
||||
messages_per_second: "پیام در ثانیه",
|
||||
messages_per_second_text: "تعداد عملیاتی که می تواند در یک ثانیه انجام شود. 0 به معنای غیرفعال کردن محدودیت برای این کاربر است.",
|
||||
messages_per_second_text: "تعداد عملیاتی که می تواند در یک ثانیه انجام شود.",
|
||||
burst_count: "تعداد پیچیدگی",
|
||||
burst_count_text: "تعداد عملیاتی که می تواند قبل از محدودیت انجام شود.",
|
||||
}
|
||||
@@ -220,6 +225,14 @@ const fa: SynapseTranslationMessages = {
|
||||
success: "اتاق با موفقیت حذف شد.",
|
||||
failure: "خطایی رخ داده است.",
|
||||
},
|
||||
make_admin: {
|
||||
assign_admin: "مدیر انتخاب کنید",
|
||||
title: "مدیر اتاق %{roomName} را انتخاب کنید",
|
||||
confirm: "مدیر انتخاب کنید",
|
||||
content: "کامل MXID کاربری را وارد کنید که به عنوان مدیر تنظیم شود.\nهشدار: برای این کار، اتاق باید حداقل یک اعضای محلی به عنوان مدیر داشته باشد.",
|
||||
success: "کاربر به عنوان مدیر اتاق تنظیم شد.",
|
||||
failure: "کاربر به عنوان مدیر اتاق تنظیم نشد. %{errMsg}",
|
||||
}
|
||||
},
|
||||
},
|
||||
reports: {
|
||||
|
@@ -7,7 +7,7 @@ const fr: SynapseTranslationMessages = {
|
||||
synapseadmin: {
|
||||
auth: {
|
||||
base_url: "URL du serveur d’accueil",
|
||||
welcome: "Bienvenue sur Synapse-admin",
|
||||
welcome: "Bienvenue sur Synapse Admin",
|
||||
server_version: "Version du serveur Synapse",
|
||||
username_error: "Veuillez entrer un nom d'utilisateur complet : « @utilisateur:domaine »",
|
||||
protocol_error: "L'URL doit commencer par « http:// » ou « https:// »",
|
||||
@@ -151,6 +151,7 @@ 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",
|
||||
@@ -158,10 +159,14 @@ const fr: SynapseTranslationMessages = {
|
||||
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. 0 signifie que la limitation est désactivée pour cet utilisateur.",
|
||||
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é.",
|
||||
}
|
||||
@@ -222,6 +227,14 @@ const fr: SynapseTranslationMessages = {
|
||||
success: "Salle/s supprimées avec succès.",
|
||||
failure: "La/les salle/s n'ont pas pu être supprimées.",
|
||||
},
|
||||
make_admin: {
|
||||
assign_admin: "Assigner un administrateur",
|
||||
title: "Assigner un administrateur au salon %{roomName}",
|
||||
confirm: "Assigner un administrateur",
|
||||
content: "Entrez la MXID complète de l'utilisateur qui sera désigné comme administrateur.\nAttention : pour que cela fonctionne, la salle doit avoir au moins un membre local en tant qu'administrateur.",
|
||||
success: "L'utilisateur a été désigné comme administrateur de la salle.",
|
||||
failure: "L'utilisateur n'a pas pu être désigné comme administrateur de la salle. %{errMsg}",
|
||||
}
|
||||
},
|
||||
},
|
||||
reports: {
|
||||
|
13
src/i18n/index.d.ts
vendored
13
src/i18n/index.d.ts
vendored
@@ -149,6 +149,7 @@ interface SynapseTranslationMessages extends TranslationMessages {
|
||||
erase_text: string;
|
||||
erase_admin_error: string;
|
||||
modify_managed_user_error: string;
|
||||
username_available: string;
|
||||
};
|
||||
action: {
|
||||
erase: string;
|
||||
@@ -156,6 +157,10 @@ interface SynapseTranslationMessages extends TranslationMessages {
|
||||
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;
|
||||
@@ -218,6 +223,14 @@ interface SynapseTranslationMessages extends TranslationMessages {
|
||||
success: string;
|
||||
failure: string;
|
||||
};
|
||||
make_admin: {
|
||||
assign_admin: string;
|
||||
title: string;
|
||||
confirm: string;
|
||||
content: string;
|
||||
success: string;
|
||||
failure: string;
|
||||
};
|
||||
};
|
||||
};
|
||||
reports: {
|
||||
|
@@ -7,7 +7,7 @@ const it: SynapseTranslationMessages = {
|
||||
synapseadmin: {
|
||||
auth: {
|
||||
base_url: "URL dell'homeserver",
|
||||
welcome: "Benvenuto in Synapse-admin",
|
||||
welcome: "Benvenuto in Synapse Admin",
|
||||
server_version: "Versione di Synapse",
|
||||
username_error: "Per favore inserisci un ID utente completo: '@utente:dominio'",
|
||||
protocol_error: "L'URL deve iniziare per 'http://' o 'https://'",
|
||||
@@ -150,6 +150,7 @@ 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",
|
||||
@@ -157,10 +158,14 @@ const it: SynapseTranslationMessages = {
|
||||
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. 0 significa che la limitazione è disabilitata per questo utente.",
|
||||
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.",
|
||||
}
|
||||
@@ -216,6 +221,14 @@ const it: SynapseTranslationMessages = {
|
||||
content:
|
||||
"Sei sicuro di voler eliminare questa stanza? Questa azione è definitiva. Tutti i messaggi e i media condivisi in questa stanza verranno eliminati dal server!",
|
||||
},
|
||||
make_admin: {
|
||||
assign_admin: "Assegna un amministratore",
|
||||
title: "Assegna un amministratore alla stanza %{roomName}",
|
||||
confirm: "Assegna un amministratore",
|
||||
content: "Inserisci la MXID completa dell'utente che sarà designato come amministratore.\nAttenzione: per questo funzionare, la stanza deve avere almeno un membro locale come amministratore.",
|
||||
success: "L'utente è stato designato come amministratore della stanza.",
|
||||
failure: "L'utente non può essere designato come amministratore della stanza. %{errMsg}",
|
||||
}
|
||||
},
|
||||
},
|
||||
reports: {
|
||||
|
@@ -32,7 +32,7 @@ const ru: SynapseTranslationMessages = {
|
||||
synapseadmin: {
|
||||
auth: {
|
||||
base_url: "Адрес домашнего сервера",
|
||||
welcome: "Добро пожаловать в Synapse-admin",
|
||||
welcome: "Добро пожаловать в Synapse Admin",
|
||||
server_version: "Версия Synapse",
|
||||
supports_specs: "поддерживает спецификации Matrix",
|
||||
username_error: "Пожалуйста, укажите полный ID пользователя: '@user:domain'",
|
||||
@@ -187,6 +187,7 @@ const ru: SynapseTranslationMessages = {
|
||||
erase_text: "Это означает, что сообщения, отправленные пользователем (-ами), будут по-прежнему видны всем, кто находился в комнате в момент их отправки, но будут скрыты от пользователей, присоединившихся к комнате после этого.",
|
||||
erase_admin_error: "Удаление собственного пользователя запрещено.",
|
||||
modify_managed_user_error: "Изменение пользователя, управляемого системой, не допускается.",
|
||||
username_available: "Имя пользователя доступно",
|
||||
},
|
||||
action: {
|
||||
erase: "Удалить данные пользователя",
|
||||
@@ -194,10 +195,14 @@ const ru: SynapseTranslationMessages = {
|
||||
delete_media: "Удаление всех медиафайлов, загруженных пользователем (-ами)",
|
||||
redact_events: "Удаление всех событий, отправленных пользователем (-ами)",
|
||||
generate_password: "Сгенерировать пароль",
|
||||
overwrite_title: "Предупреждение!",
|
||||
overwrite_content: "Это имя пользователя уже занято. Вы уверены, что хотите перезаписать существующего пользователя?",
|
||||
overwrite_cancel: "Отмена",
|
||||
overwrite_confirm: "Перезаписать",
|
||||
},
|
||||
limits: {
|
||||
messages_per_second: "Сообщений в секунду",
|
||||
messages_per_second_text: "Количество действий, которые могут быть выполнены в секунду. 0 означает, что ограничение на количество действий отключено для этого пользователя.",
|
||||
messages_per_second_text: "Количество действий, которые могут быть выполнены в секунду.",
|
||||
burst_count: "Burst-счётчик",
|
||||
burst_count_text: "Количество действий, которые могут быть выполнены до ограничения.",
|
||||
}
|
||||
@@ -261,6 +266,14 @@ const ru: SynapseTranslationMessages = {
|
||||
success: "Комната/ы успешно удалены",
|
||||
failure: "Комната/ы не могут быть удалены.",
|
||||
},
|
||||
make_admin: {
|
||||
assign_admin: "Назначить администратора",
|
||||
title: "Назначить администратора комнате %{roomName}",
|
||||
confirm: "Назначить администратора",
|
||||
content: "Введите полную MXID пользователя, которого нужно назначить администратором.\nПредупреждение: для этого должен быть назначен хотя бы один локальный участник в качестве администратора.",
|
||||
success: "Пользователь назначен администратором комнаты.",
|
||||
failure: "Пользователь не может быть назначен администратором комнаты. %{errMsg}",
|
||||
}
|
||||
},
|
||||
},
|
||||
reports: {
|
||||
|
@@ -35,7 +35,7 @@ const zh: SynapseTranslationMessages = {
|
||||
synapseadmin: {
|
||||
auth: {
|
||||
base_url: "服务器 URL",
|
||||
welcome: "欢迎来到 Synapse-admin",
|
||||
welcome: "欢迎来到 Synapse Admin",
|
||||
server_version: "Synapse 版本",
|
||||
username_error: "请输入完整有效的用户 ID: '@user:domain'",
|
||||
protocol_error: "URL 需要以'http://'或'https://'作为起始",
|
||||
@@ -174,6 +174,7 @@ const zh: SynapseTranslationMessages = {
|
||||
erase_text: "这意味着用户发送的信息对于发送信息时在房间内的任何人来说都是可见的,但对于之后加入房间的用户来说则是隐藏的。",
|
||||
erase_admin_error: "不允许删除自己的用户",
|
||||
modify_managed_user_error: "不允许修改系统管理的用户。",
|
||||
username_available: "用户名可用",
|
||||
},
|
||||
action: {
|
||||
erase: "抹除用户信息",
|
||||
@@ -181,10 +182,14 @@ const zh: SynapseTranslationMessages = {
|
||||
delete_media: "删除用户上传的所有媒体",
|
||||
redact_events: "重新编辑用户(-s)发送的所有事件",
|
||||
generate_password: "生成密码",
|
||||
overwrite_title: "警告!",
|
||||
overwrite_content: "这个用户名已经被占用。您确定要覆盖现有的用户吗?",
|
||||
overwrite_cancel: "取消",
|
||||
overwrite_confirm: "覆盖",
|
||||
},
|
||||
limits: {
|
||||
messages_per_second: "每秒消息数",
|
||||
messages_per_second_text: "每秒可以执行的操作数。0 表示禁用此用户的限制。",
|
||||
messages_per_second_text: "每秒可以执行的操作数。",
|
||||
burst_count: "Burst-计数",
|
||||
burst_count_text: "在限制之前可以执行的操作数。",
|
||||
}
|
||||
|
@@ -8,7 +8,12 @@ import { AppContext } from "./AppContext";
|
||||
import storage from "./storage";
|
||||
|
||||
// load config.json
|
||||
let props: Config = {};
|
||||
let props: Config = {
|
||||
restrictBaseUrl: [],
|
||||
asManagedUsers: [],
|
||||
supportURL: "",
|
||||
menu: [],
|
||||
};
|
||||
try {
|
||||
const resp = await fetch("config.json");
|
||||
const configJSON = await resp.json();
|
||||
|
@@ -26,6 +26,7 @@ import {
|
||||
splitMxid,
|
||||
} from "../synapse/synapse";
|
||||
import storage from "../storage";
|
||||
import Footer from "../components/Footer";
|
||||
|
||||
export type LoginMethod = "credentials" | "accessToken";
|
||||
|
||||
@@ -96,6 +97,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(
|
||||
@@ -166,6 +170,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
|
||||
@@ -186,10 +206,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>
|
||||
@@ -198,7 +218,7 @@ const LoginPage = () => {
|
||||
label="ra.auth.password"
|
||||
type="password"
|
||||
autoComplete="current-password"
|
||||
disabled={loading || !supportPassAuth}
|
||||
{...(loading || !supportPassAuth ? { disabled: true } : {})}
|
||||
resettable
|
||||
validate={required()}
|
||||
/>
|
||||
@@ -209,7 +229,7 @@ const LoginPage = () => {
|
||||
<TextInput
|
||||
source="accessToken"
|
||||
label="synapseadmin.auth.access_token"
|
||||
disabled={loading}
|
||||
{...(loading ? { disabled: true } : {})}
|
||||
resettable
|
||||
validate={required()}
|
||||
/>
|
||||
@@ -221,7 +241,7 @@ const LoginPage = () => {
|
||||
label="synapseadmin.auth.base_url"
|
||||
select={allowMultipleBaseUrls}
|
||||
autoComplete="url"
|
||||
disabled={loading}
|
||||
{...(loading ? { disabled: true } : {})}
|
||||
readOnly={allowSingleBaseUrl}
|
||||
resettable={allowAnyBaseUrl}
|
||||
validate={[required(), validateBaseUrl]}
|
||||
@@ -302,6 +322,7 @@ const LoginPage = () => {
|
||||
</Card>
|
||||
</LoginFormBox>
|
||||
<Notification />
|
||||
<Footer />
|
||||
</Form>
|
||||
);
|
||||
};
|
||||
|
@@ -27,8 +27,7 @@ import {
|
||||
} from "react-admin";
|
||||
import { useMutation } from "@tanstack/react-query";
|
||||
import AvatarField from "../components/AvatarField";
|
||||
|
||||
|
||||
import { MakeAdminBtn } from "./rooms";
|
||||
const RoomDirectoryPagination = () => <Pagination rowsPerPageOptions={[100, 500, 1000, 2000]} />;
|
||||
|
||||
export const RoomDirectoryUnpublishButton = (props: DeleteButtonProps) => {
|
||||
@@ -154,6 +153,7 @@ export const RoomDirectoryList = () => (
|
||||
<NumberField source="num_joined_members" sortable={false} label="resources.rooms.fields.joined_members" />
|
||||
<BooleanField source="world_readable" sortable={false} label="resources.room_directory.fields.world_readable" />
|
||||
<BooleanField source="guest_can_join" sortable={false} label="resources.room_directory.fields.guest_can_join" />
|
||||
<MakeAdminBtn />
|
||||
</DatagridConfigurable>
|
||||
</List>
|
||||
);
|
||||
|
@@ -11,11 +11,11 @@ import Box from "@mui/material/Box";
|
||||
import { useTheme } from "@mui/material/styles";
|
||||
import {
|
||||
BooleanField,
|
||||
BulkDeleteButton,
|
||||
DateField,
|
||||
EditButton,
|
||||
WrapperField,
|
||||
Datagrid,
|
||||
DatagridConfigurable,
|
||||
DeleteButton,
|
||||
ExportButton,
|
||||
FunctionField,
|
||||
List,
|
||||
@@ -32,13 +32,15 @@ import {
|
||||
ShowProps,
|
||||
Tab,
|
||||
TabbedShowLayout,
|
||||
TextField,
|
||||
TextField as RaTextField,
|
||||
TopToolbar,
|
||||
useRecordContext,
|
||||
useTranslate,
|
||||
useListContext,
|
||||
useNotify,
|
||||
} from "react-admin";
|
||||
|
||||
import TextField from "@mui/material/TextField";
|
||||
import {
|
||||
RoomDirectoryBulkUnpublishButton,
|
||||
RoomDirectoryBulkPublishButton,
|
||||
@@ -48,7 +50,14 @@ import {
|
||||
import { DATE_FORMAT } from "../components/date";
|
||||
import DeleteRoomButton from "../components/DeleteRoomButton";
|
||||
import AvatarField from "../components/AvatarField";
|
||||
|
||||
import { Room } from "../synapse/dataProvider";
|
||||
import { useMutation } from "@tanstack/react-query";
|
||||
import { useDataProvider } from "react-admin";
|
||||
import { Confirm } from "react-admin";
|
||||
import { useState } from "react";
|
||||
import Button from "@mui/material/Button";
|
||||
import PersonIcon from '@mui/icons-material/Person';
|
||||
import Typography from "@mui/material/Typography";
|
||||
const RoomPagination = () => <Pagination rowsPerPageOptions={[10, 25, 50, 100, 500, 1000]} />;
|
||||
|
||||
const RoomTitle = () => {
|
||||
@@ -76,6 +85,7 @@ const RoomShowActions = () => {
|
||||
return (
|
||||
<TopToolbar>
|
||||
{publishButton}
|
||||
<MakeAdminBtn />
|
||||
<DeleteRoomButton
|
||||
selectedIds={[record.id]}
|
||||
confirmTitle="resources.rooms.action.erase.title"
|
||||
@@ -85,8 +95,97 @@ const RoomShowActions = () => {
|
||||
);
|
||||
};
|
||||
|
||||
export const MakeAdminBtn = () => {
|
||||
const record = useRecordContext() as Room;
|
||||
|
||||
if (!record) {
|
||||
return null;
|
||||
}
|
||||
|
||||
if (record.joined_local_members < 1) {
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
const ownMXID = localStorage.getItem("user_id") || "";
|
||||
const [open, setOpen] = useState(false);
|
||||
const [userIdValue, setUserIdValue] = useState(ownMXID);
|
||||
const dataProvider = useDataProvider();
|
||||
const notify = useNotify();
|
||||
const translate = useTranslate();
|
||||
|
||||
const { mutate, isPending } = useMutation({
|
||||
mutationFn: async () => {
|
||||
try {
|
||||
const result = await dataProvider.makeRoomAdmin(record.room_id, userIdValue);
|
||||
if (!result.success) {
|
||||
throw new Error(result.error);
|
||||
}
|
||||
} catch (error) {
|
||||
throw error;
|
||||
}
|
||||
},
|
||||
onSuccess: () => {
|
||||
notify("resources.rooms.action.make_admin.success", { type: "success" });
|
||||
setOpen(false);
|
||||
setUserIdValue("");
|
||||
},
|
||||
onError: (err) => {
|
||||
const errorMessage = err instanceof Error ? err.message : "Unknown error";
|
||||
notify("resources.rooms.action.make_admin.failure", { type: "error", messageArgs: { errMsg: errorMessage } });
|
||||
setOpen(false);
|
||||
setUserIdValue("");
|
||||
}
|
||||
});
|
||||
|
||||
const handleChange = (event: React.ChangeEvent<HTMLInputElement>) => {
|
||||
setUserIdValue(event.target.value);
|
||||
};
|
||||
|
||||
const handleConfirm = async () => {
|
||||
mutate();
|
||||
setOpen(false);
|
||||
};
|
||||
|
||||
const handleDialogClose = () => {
|
||||
setOpen(false);
|
||||
};
|
||||
|
||||
const handleKeyDown = (event: React.KeyboardEvent<HTMLInputElement>) => {
|
||||
if (event.key === "Enter") {
|
||||
handleConfirm();
|
||||
}
|
||||
};
|
||||
|
||||
return (<>
|
||||
<Button size="small" onClick={(e) => { e.stopPropagation(); setOpen(true); }} disabled={isPending}>
|
||||
<PersonIcon /> {translate("resources.rooms.action.make_admin.assign_admin")}
|
||||
</Button>
|
||||
<Confirm
|
||||
isOpen={open}
|
||||
onConfirm={handleConfirm}
|
||||
onClose={handleDialogClose}
|
||||
confirm="resources.rooms.action.make_admin.confirm"
|
||||
cancel="ra.action.cancel"
|
||||
title={translate("resources.rooms.action.make_admin.title", { roomName: record.name ? record.name : record.room_id })}
|
||||
content={<>
|
||||
<Typography sx={{ marginBottom: 2, whiteSpace: "pre-line"}}>{translate("resources.rooms.action.make_admin.content")}</Typography>
|
||||
<TextField
|
||||
type="text"
|
||||
variant="filled"
|
||||
value={userIdValue}
|
||||
onChange={handleChange}
|
||||
onKeyDown={handleKeyDown}
|
||||
label={"Matrix ID"}
|
||||
/>
|
||||
</>}
|
||||
/>
|
||||
</>);
|
||||
};
|
||||
|
||||
export const RoomShow = (props: ShowProps) => {
|
||||
const translate = useTranslate();
|
||||
const record = useRecordContext();
|
||||
return (
|
||||
<Show {...props} actions={<RoomShowActions />} title={<RoomTitle />}>
|
||||
<TabbedShowLayout>
|
||||
@@ -96,28 +195,29 @@ export const RoomShow = (props: ShowProps) => {
|
||||
sx={{ height: "120px", width: "120px" }}
|
||||
label="resources.rooms.fields.avatar"
|
||||
/>
|
||||
<TextField source="room_id" />
|
||||
<TextField source="name" />
|
||||
<TextField source="topic" />
|
||||
<TextField source="canonical_alias" />
|
||||
<RaTextField source="room_id" />
|
||||
<RaTextField source="name" />
|
||||
<RaTextField source="topic" />
|
||||
<RaTextField source="canonical_alias" />
|
||||
<ReferenceField source="creator" reference="users">
|
||||
<TextField source="id" />
|
||||
<RaTextField source="id" />
|
||||
</ReferenceField>
|
||||
</Tab>
|
||||
|
||||
<Tab label="synapseadmin.rooms.tabs.detail" icon={<PageviewIcon />} path="detail">
|
||||
<TextField source="joined_members" />
|
||||
<TextField source="joined_local_members" />
|
||||
<TextField source="joined_local_devices" />
|
||||
<TextField source="state_events" />
|
||||
<TextField source="version" />
|
||||
<TextField source="encryption" emptyText={translate("resources.rooms.enums.unencrypted")} />
|
||||
<RaTextField source="joined_members" />
|
||||
<RaTextField source="joined_local_members" />
|
||||
<RaTextField source="joined_local_devices" />
|
||||
<RaTextField source="state_events" />
|
||||
<RaTextField source="version" />
|
||||
<RaTextField source="encryption" emptyText={translate("resources.rooms.enums.unencrypted")} />
|
||||
</Tab>
|
||||
|
||||
<Tab label="synapseadmin.rooms.tabs.members" icon={<UserIcon />} path="members">
|
||||
<MakeAdminBtn />
|
||||
<ReferenceManyField reference="room_members" target="room_id" label={false}>
|
||||
<Datagrid style={{ width: "100%" }} rowClick={id => "/users/" + id} bulkActionButtons={false}>
|
||||
<TextField source="id" sortable={false} label="resources.users.fields.id" />
|
||||
<RaTextField source="id" sortable={false} label="resources.users.fields.id" />
|
||||
<ReferenceField
|
||||
label="resources.users.fields.displayname"
|
||||
source="id"
|
||||
@@ -125,7 +225,7 @@ export const RoomShow = (props: ShowProps) => {
|
||||
sortable={false}
|
||||
link=""
|
||||
>
|
||||
<TextField source="displayname" sortable={false} />
|
||||
<RaTextField source="displayname" sortable={false} />
|
||||
</ReferenceField>
|
||||
</Datagrid>
|
||||
</ReferenceManyField>
|
||||
@@ -185,11 +285,11 @@ export const RoomShow = (props: ShowProps) => {
|
||||
<Tab label={translate("resources.room_state.name", { smart_count: 2 })} icon={<EventIcon />} path="state">
|
||||
<ReferenceManyField reference="room_state" target="room_id" label={false}>
|
||||
<Datagrid style={{ width: "100%" }} bulkActionButtons={false}>
|
||||
<TextField source="type" sortable={false} />
|
||||
<RaTextField source="type" sortable={false} />
|
||||
<DateField source="origin_server_ts" showTime options={DATE_FORMAT} sortable={false} />
|
||||
<FunctionField source="content" sortable={false} render={record => `${JSON.stringify(record.content, null, 2)}`} />
|
||||
<ReferenceField source="sender" reference="users" sortable={false}>
|
||||
<TextField source="id" />
|
||||
<RaTextField source="id" />
|
||||
</ReferenceField>
|
||||
</Datagrid>
|
||||
</ReferenceManyField>
|
||||
@@ -206,10 +306,10 @@ export const RoomShow = (props: ShowProps) => {
|
||||
</Box>
|
||||
<ReferenceManyField reference="forward_extremities" target="room_id" label={false}>
|
||||
<Datagrid style={{ width: "100%" }} bulkActionButtons={false}>
|
||||
<TextField source="id" sortable={false} />
|
||||
<RaTextField source="id" sortable={false} />
|
||||
<DateField source="received_ts" showTime options={DATE_FORMAT} sortable={false} />
|
||||
<NumberField source="depth" sortable={false} />
|
||||
<TextField source="state_group" sortable={false} />
|
||||
<RaTextField source="state_group" sortable={false} />
|
||||
</Datagrid>
|
||||
</ReferenceManyField>
|
||||
</Tab>
|
||||
@@ -270,12 +370,13 @@ export const RoomList = (props: ListProps) => {
|
||||
}}
|
||||
/>
|
||||
<FunctionField source="name" render={record => record["name"] || record["canonical_alias"] || record["id"]} />
|
||||
<TextField source="joined_members" />
|
||||
<TextField source="joined_local_members" />
|
||||
<TextField source="state_events" />
|
||||
<TextField source="version" />
|
||||
<RaTextField source="joined_members" />
|
||||
<RaTextField source="joined_local_members" />
|
||||
<RaTextField source="state_events" />
|
||||
<RaTextField source="version" />
|
||||
<BooleanField source="federatable" />
|
||||
<BooleanField source="public" />
|
||||
<MakeAdminBtn />
|
||||
</DatagridConfigurable>
|
||||
</List>
|
||||
);
|
||||
|
@@ -11,7 +11,8 @@ 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 } from "@mui/material";
|
||||
import { Alert, Typography } from "@mui/material";
|
||||
import { useTheme } from "@mui/material/styles";
|
||||
import {
|
||||
ArrayInput,
|
||||
ArrayField,
|
||||
@@ -60,6 +61,9 @@ import {
|
||||
ImageField,
|
||||
FunctionField,
|
||||
useDataProvider,
|
||||
Confirm,
|
||||
useCreate,
|
||||
useRedirect,
|
||||
} from "react-admin";
|
||||
import { Link } from "react-router-dom";
|
||||
|
||||
@@ -74,6 +78,8 @@ 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";
|
||||
import { MakeAdminBtn } from "./rooms";
|
||||
|
||||
const choices_medium = [
|
||||
{ id: "email", name: "resources.users.email" },
|
||||
@@ -213,13 +219,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 />
|
||||
@@ -237,8 +300,17 @@ 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();
|
||||
@@ -455,6 +527,7 @@ export const UserEdit = (props: EditProps) => {
|
||||
>
|
||||
<TextField source="name" sortable={false} />
|
||||
</ReferenceField>
|
||||
<MakeAdminBtn />
|
||||
</Datagrid>
|
||||
</ReferenceManyField>
|
||||
</FormTab>
|
||||
|
@@ -52,7 +52,7 @@ interface Action {
|
||||
body?: Record<string, any>;
|
||||
}
|
||||
|
||||
interface Room {
|
||||
export interface Room {
|
||||
room_id: string;
|
||||
name?: string;
|
||||
canonical_alias?: string;
|
||||
@@ -120,7 +120,8 @@ interface ExternalId {
|
||||
external_id: string;
|
||||
}
|
||||
|
||||
interface User {
|
||||
export interface User {
|
||||
id?: string;
|
||||
name: string;
|
||||
displayname?: string;
|
||||
threepids: Threepid[];
|
||||
@@ -259,12 +260,20 @@ export interface RateLimitsModel {
|
||||
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>;
|
||||
makeRoomAdmin: (room_id: string, user_id: string) => Promise<{ success: boolean; error?: string; errcode?: string }>;
|
||||
}
|
||||
|
||||
const resourceMap = {
|
||||
@@ -830,10 +839,49 @@ const baseDataProvider: SynapseDataProvider = {
|
||||
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`;
|
||||
await jsonClient(endpoint_url, { method: "POST", body: JSON.stringify(rateLimits) });
|
||||
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;
|
||||
}
|
||||
},
|
||||
makeRoomAdmin: async (room_id: string, user_id: string) => {
|
||||
const base_url = storage.getItem("base_url");
|
||||
|
||||
const endpoint_url = `${base_url}/_synapse/admin/v1/rooms/${encodeURIComponent(room_id)}/make_room_admin`;
|
||||
try {
|
||||
const { json } = await jsonClient(endpoint_url, { method: "POST", body: JSON.stringify({ user_id }) });
|
||||
return { success: true };
|
||||
} catch (error) {
|
||||
if (error instanceof HttpError) {
|
||||
return { success: false, error: error.body.error, errcode: error.body.errcode };
|
||||
}
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
const dataProvider = withLifecycleCallbacks(baseDataProvider, [
|
||||
|
533
yarn.lock
533
yarn.lock
@@ -332,7 +332,7 @@
|
||||
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.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":
|
||||
"@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.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==
|
||||
@@ -658,29 +658,29 @@
|
||||
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"
|
||||
resolved "https://registry.yarnpkg.com/@eslint/config-array/-/config-array-0.18.0.tgz#37d8fe656e0d5e3dbaea7758ea56540867fd074d"
|
||||
integrity sha512-fTxvnS1sRMu3+JjXwJG0j/i4RT9u4qJ+lqS/yCGap4lH4zZGzQ7tu+xZqQmcMZq5OBZDL4QRxQzRjkWcGt8IVw==
|
||||
"@eslint/config-array@^0.19.0":
|
||||
version "0.19.0"
|
||||
resolved "https://registry.yarnpkg.com/@eslint/config-array/-/config-array-0.19.0.tgz#3251a528998de914d59bb21ba4c11767cf1b3519"
|
||||
integrity sha512-zdHg2FPIFNKPdcHWtiNT+jEFCHYVplAXRDlQDyqy0zGx/q2parwh7brGJSiTxRk/TSMkbM//zt/f5CHgyTyaSQ==
|
||||
dependencies:
|
||||
"@eslint/object-schema" "^2.1.4"
|
||||
debug "^4.3.1"
|
||||
minimatch "^3.1.2"
|
||||
|
||||
"@eslint/core@^0.7.0":
|
||||
version "0.7.0"
|
||||
resolved "https://registry.yarnpkg.com/@eslint/core/-/core-0.7.0.tgz#a1bb4b6a4e742a5ff1894b7ee76fbf884ec72bd3"
|
||||
integrity sha512-xp5Jirz5DyPYlPiKat8jaq0EmYvDXKKpzTbxXMpT9eqlRJkRKIz9AGMdlvYjih+im+QlhWrpvVjl8IPC/lHlUw==
|
||||
"@eslint/core@^0.9.0":
|
||||
version "0.9.0"
|
||||
resolved "https://registry.yarnpkg.com/@eslint/core/-/core-0.9.0.tgz#168ee076f94b152c01ca416c3e5cf82290ab4fcd"
|
||||
integrity sha512-7ATR9F0e4W85D/0w7cU0SNj7qkAexMG+bAHEZOjo9akvGuhHE2m7umzWzfnpa0XAg5Kxc1BWmtPMV67jJ+9VUg==
|
||||
|
||||
"@eslint/eslintrc@^3.1.0":
|
||||
version "3.1.0"
|
||||
resolved "https://registry.yarnpkg.com/@eslint/eslintrc/-/eslintrc-3.1.0.tgz#dbd3482bfd91efa663cbe7aa1f506839868207b6"
|
||||
integrity sha512-4Bfj15dVJdoy3RfZmmo86RK1Fwzn6SstsvK9JS+BaVKqC6QQQQyXekNaC+g+LKNgkQ+2VhGAzm6hO40AhMR3zQ==
|
||||
"@eslint/eslintrc@^3.2.0":
|
||||
version "3.2.0"
|
||||
resolved "https://registry.yarnpkg.com/@eslint/eslintrc/-/eslintrc-3.2.0.tgz#57470ac4e2e283a6bf76044d63281196e370542c"
|
||||
integrity sha512-grOjVNN8P3hjJn/eIETF1wwd12DdnwFDoyceUJLYYdkpbwq3nLi+4fqrTAONx7XDALqlL220wC/RHSC/QTI/0w==
|
||||
dependencies:
|
||||
ajv "^6.12.4"
|
||||
debug "^4.3.2"
|
||||
@@ -692,20 +692,20 @@
|
||||
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.15.0", "@eslint/js@^9.13.0":
|
||||
version "9.15.0"
|
||||
resolved "https://registry.yarnpkg.com/@eslint/js/-/js-9.15.0.tgz#df0e24fe869143b59731942128c19938fdbadfb5"
|
||||
integrity sha512-tMTqrY+EzbXmKJR5ToI8lxu7jaN5EdmrBFJpQk5JmSlyLsx6o4t27r883K5xsLuCYCpfKBCGswMSWXsM+jB7lg==
|
||||
|
||||
"@eslint/object-schema@^2.1.4":
|
||||
version "2.1.4"
|
||||
resolved "https://registry.yarnpkg.com/@eslint/object-schema/-/object-schema-2.1.4.tgz#9e69f8bb4031e11df79e03db09f9dbbae1740843"
|
||||
integrity sha512-BsWiH1yFGjXXS2yvrf5LyuoSIIbPrGUWob917o+BTKuZ7qJdxX8aJLRxs1fS9n6r7vESrq1OUqb68dANcFXuQQ==
|
||||
|
||||
"@eslint/plugin-kit@^0.2.0":
|
||||
version "0.2.1"
|
||||
resolved "https://registry.yarnpkg.com/@eslint/plugin-kit/-/plugin-kit-0.2.1.tgz#cd14fe2db79fa639839dfef4105e83bad1814482"
|
||||
integrity sha512-HFZ4Mp26nbWk9d/BpvP0YNL6W4UoZF0VFcTw/aPPA8RpOxeFQgK+ClABGgAUXs9Y/RGX/l1vOmrqz1MQt9MNuw==
|
||||
"@eslint/plugin-kit@^0.2.3":
|
||||
version "0.2.3"
|
||||
resolved "https://registry.yarnpkg.com/@eslint/plugin-kit/-/plugin-kit-0.2.3.tgz#812980a6a41ecf3a8341719f92a6d1e784a2e0e8"
|
||||
integrity sha512-2b/g5hRmpbb1o4GnTZax9N9m0FXzz9OV42ZzI4rDDMDuHUqigAiQCEWChBWCY4ztAGVRjoWT19v0yMmc5/L5kA==
|
||||
dependencies:
|
||||
levn "^0.4.1"
|
||||
|
||||
@@ -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.1":
|
||||
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.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/core-downloads-tracker@^6.1.7":
|
||||
version "6.1.7"
|
||||
resolved "https://registry.yarnpkg.com/@mui/core-downloads-tracker/-/core-downloads-tracker-6.1.7.tgz#80f4327804ee97b6af7b11980f87e29dc2231226"
|
||||
integrity sha512-POuIBi80BZBogQkG4PQKIGwy4QFwB+kOr+OI4k7Znh7LqMAIhwB9OC00l6M+w1GrZJYj3T8R5WX8G6QAIvoVEw==
|
||||
|
||||
"@mui/icons-material@^5.15.20":
|
||||
version "5.16.7"
|
||||
@@ -1013,12 +1018,12 @@
|
||||
dependencies:
|
||||
"@babel/runtime" "^7.23.9"
|
||||
|
||||
"@mui/icons-material@^6.1.5":
|
||||
version "6.1.5"
|
||||
resolved "https://registry.yarnpkg.com/@mui/icons-material/-/icons-material-6.1.5.tgz#5b5a4237796956e208d480ebd68350a78d81d202"
|
||||
integrity sha512-SbxFtO5I4cXfvhjAMgGib/t2lQUzcEzcDFYiRHRufZUeMMeXuoKaGsptfwAHTepYkv0VqcCwvxtvtWbpZLAbjQ==
|
||||
"@mui/icons-material@^6.1.7":
|
||||
version "6.1.7"
|
||||
resolved "https://registry.yarnpkg.com/@mui/icons-material/-/icons-material-6.1.7.tgz#79c0fa7087acbcba2fe81f89d9dda15cb65c6742"
|
||||
integrity sha512-RGzkeHNArIVy5ZQ12bq/8VYNeICEyngngsFskTJ/2hYKhIeIII3iRGtaZaSvLpXh7h3Fg3VKTulT+QU0w5K4XQ==
|
||||
dependencies:
|
||||
"@babel/runtime" "^7.25.7"
|
||||
"@babel/runtime" "^7.26.0"
|
||||
|
||||
"@mui/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.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==
|
||||
"@mui/material@^6.1.7":
|
||||
version "6.1.7"
|
||||
resolved "https://registry.yarnpkg.com/@mui/material/-/material-6.1.7.tgz#a30dcfdae6e3cbb184669813d6b3a8addd4540ee"
|
||||
integrity sha512-KsjujQL/A2hLd1PV3QboF+W6SSL5QqH6ZlSuQoeYz9r69+TnyBFIevbYLxdjJcJmGBjigL5pfpn7hTGop+vhSg==
|
||||
dependencies:
|
||||
"@babel/runtime" "^7.26.0"
|
||||
"@mui/core-downloads-tracker" "^6.1.6"
|
||||
"@mui/system" "^6.1.6"
|
||||
"@mui/core-downloads-tracker" "^6.1.7"
|
||||
"@mui/system" "^6.1.7"
|
||||
"@mui/types" "^7.2.19"
|
||||
"@mui/utils" "^6.1.6"
|
||||
"@mui/utils" "^6.1.7"
|
||||
"@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.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==
|
||||
"@mui/private-theming@^6.1.7":
|
||||
version "6.1.7"
|
||||
resolved "https://registry.yarnpkg.com/@mui/private-theming/-/private-theming-6.1.7.tgz#9415c32eb567194b713941243cf18fde09981ba1"
|
||||
integrity sha512-uLbfUSsug5K0LVkv0PI6Flste3le8+6WSL2omdTiYde93P89Qr7pKr8TA6d2yXfr+Bm+SvD8/fGnkaRwFkryuQ==
|
||||
dependencies:
|
||||
"@babel/runtime" "^7.26.0"
|
||||
"@mui/utils" "^6.1.6"
|
||||
"@mui/utils" "^6.1.7"
|
||||
prop-types "^15.8.1"
|
||||
|
||||
"@mui/styled-engine@^5.16.6":
|
||||
@@ -1084,10 +1089,10 @@
|
||||
csstype "^3.1.3"
|
||||
prop-types "^15.8.1"
|
||||
|
||||
"@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==
|
||||
"@mui/styled-engine@^6.1.7":
|
||||
version "6.1.7"
|
||||
resolved "https://registry.yarnpkg.com/@mui/styled-engine/-/styled-engine-6.1.7.tgz#2e38642325afe473dd14349c95a56e947640b154"
|
||||
integrity sha512-Ou4CxN7MQmwrfG1Pu6EYjPgPChQXxPDJrwgizLXlRPOad5qAq4gYXRuzrGQ2DfGjjwmJhjI8T6A0SeapAZPGig==
|
||||
dependencies:
|
||||
"@babel/runtime" "^7.26.0"
|
||||
"@emotion/cache" "^11.13.1"
|
||||
@@ -1110,16 +1115,16 @@
|
||||
csstype "^3.1.3"
|
||||
prop-types "^15.8.1"
|
||||
|
||||
"@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==
|
||||
"@mui/system@^6.1.7":
|
||||
version "6.1.7"
|
||||
resolved "https://registry.yarnpkg.com/@mui/system/-/system-6.1.7.tgz#041d450b842d5c2fb1608d4027360ad2ba25bd9a"
|
||||
integrity sha512-qbMGgcC/FodpuRSfjXlEDdbNQaW++eATh0vNBcPUv2/YXSpReoOpoT9FhogxEBNks+aQViDXBRZKh6HX2fVmwg==
|
||||
dependencies:
|
||||
"@babel/runtime" "^7.26.0"
|
||||
"@mui/private-theming" "^6.1.6"
|
||||
"@mui/styled-engine" "^6.1.6"
|
||||
"@mui/private-theming" "^6.1.7"
|
||||
"@mui/styled-engine" "^6.1.7"
|
||||
"@mui/types" "^7.2.19"
|
||||
"@mui/utils" "^6.1.6"
|
||||
"@mui/utils" "^6.1.7"
|
||||
clsx "^2.1.1"
|
||||
csstype "^3.1.3"
|
||||
prop-types "^15.8.1"
|
||||
@@ -1141,10 +1146,10 @@
|
||||
prop-types "^15.8.1"
|
||||
react-is "^18.3.1"
|
||||
|
||||
"@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==
|
||||
"@mui/utils@^6.1.7":
|
||||
version "6.1.7"
|
||||
resolved "https://registry.yarnpkg.com/@mui/utils/-/utils-6.1.7.tgz#0959d9772ae13c6ceac984a493e06aebb9087e71"
|
||||
integrity sha512-Gr7cRZxBoZ0BIa3Xqf/2YaUrBLyNPJvXPQH3OsD9WMZukI/TutibbQBVqLYpgqJn8pKSjbD50Yq2auG0wI1xOw==
|
||||
dependencies:
|
||||
"@babel/runtime" "^7.26.0"
|
||||
"@mui/types" "^7.2.19"
|
||||
@@ -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.17":
|
||||
version "5.59.17"
|
||||
resolved "https://registry.yarnpkg.com/@tanstack/query-core/-/query-core-5.59.17.tgz#bda3bb678be48e2f6ee692abd1cfc2db3d455e4b"
|
||||
integrity sha512-jWdDiif8kaqnRGHNXAa9CnudtxY5v9DUxXhodgqX2Rwzj+1UwStDHEbBd9IA5C7VYAaJ2s+BxFR6PUBs8ERorA==
|
||||
"@tanstack/query-core@5.60.5":
|
||||
version "5.60.5"
|
||||
resolved "https://registry.yarnpkg.com/@tanstack/query-core/-/query-core-5.60.5.tgz#37b7c5ab7e6894cea9ef341299a7a3febc2ea361"
|
||||
integrity sha512-jiS1aC3XI3BJp83ZiTuDLerTmn9P3U95r6p+6/SNauLJaYxfIC4dMuWygwnBHIZxjn2zJqEpj3nysmPieoxfPQ==
|
||||
|
||||
"@tanstack/react-query@^5.59.19", "@tanstack/react-query@^5.8.4":
|
||||
version "5.59.19"
|
||||
resolved "https://registry.yarnpkg.com/@tanstack/react-query/-/react-query-5.59.19.tgz#309ae0d75844e331ea72762bfe0e11fb829a69d3"
|
||||
integrity sha512-xLRfyFyQOFcLltKCds0LijfC6/HQJrrTTnZB8ciyn74LIkVAm++vZJ6eUVG20RmJtdP8REdy7vSOYW4M3//XLA==
|
||||
"@tanstack/react-query@^5.60.5", "@tanstack/react-query@^5.8.4":
|
||||
version "5.60.5"
|
||||
resolved "https://registry.yarnpkg.com/@tanstack/react-query/-/react-query-5.60.5.tgz#3194c390f7eff20542b321c3042880dc3f1a81e2"
|
||||
integrity sha512-M77bOsPwj1wYE56gk7iJvxGAr4IC12NWdIDhT+Eo8ldkWRHMvIR8I/rufIvT1OXoV/bl7EECwuRuMlxxWtvW2Q==
|
||||
dependencies:
|
||||
"@tanstack/query-core" "5.59.17"
|
||||
"@tanstack/query-core" "5.60.5"
|
||||
|
||||
"@testing-library/dom@^10.0.0":
|
||||
version "10.4.0"
|
||||
@@ -1536,62 +1541,100 @@
|
||||
dependencies:
|
||||
"@types/yargs-parser" "*"
|
||||
|
||||
"@typescript-eslint/eslint-plugin@8.12.2", "@typescript-eslint/eslint-plugin@^8.11.0":
|
||||
version "8.12.2"
|
||||
resolved "https://registry.yarnpkg.com/@typescript-eslint/eslint-plugin/-/eslint-plugin-8.12.2.tgz#c2ef660bb83fd1432368319312a2581fc92ccac1"
|
||||
integrity sha512-gQxbxM8mcxBwaEmWdtLCIGLfixBMHhQjBqR8sVWNTPpcj45WlYL2IObS/DNMLH1DBP0n8qz+aiiLTGfopPEebw==
|
||||
"@typescript-eslint/eslint-plugin@8.13.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.12.2"
|
||||
"@typescript-eslint/type-utils" "8.12.2"
|
||||
"@typescript-eslint/utils" "8.12.2"
|
||||
"@typescript-eslint/visitor-keys" "8.12.2"
|
||||
"@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.12.2", "@typescript-eslint/parser@^8.11.0":
|
||||
version "8.12.2"
|
||||
resolved "https://registry.yarnpkg.com/@typescript-eslint/parser/-/parser-8.12.2.tgz#2e8173b34e1685e918b2d571c16c906d3747bad2"
|
||||
integrity sha512-MrvlXNfGPLH3Z+r7Tk+Z5moZAc0dzdVjTgUgwsdGweH7lydysQsnSww3nAmsq8blFuRD5VRlAr9YdEFw3e6PBw==
|
||||
"@typescript-eslint/eslint-plugin@^8.14.0":
|
||||
version "8.14.0"
|
||||
resolved "https://registry.yarnpkg.com/@typescript-eslint/eslint-plugin/-/eslint-plugin-8.14.0.tgz#7dc0e419c87beadc8f554bf5a42e5009ed3748dc"
|
||||
integrity sha512-tqp8H7UWFaZj0yNO6bycd5YjMwxa6wIHOLZvWPkidwbgLCsBMetQoGj7DPuAlWa2yGO3H48xmPwjhsSPPCGU5w==
|
||||
dependencies:
|
||||
"@typescript-eslint/scope-manager" "8.12.2"
|
||||
"@typescript-eslint/types" "8.12.2"
|
||||
"@typescript-eslint/typescript-estree" "8.12.2"
|
||||
"@typescript-eslint/visitor-keys" "8.12.2"
|
||||
"@eslint-community/regexpp" "^4.10.0"
|
||||
"@typescript-eslint/scope-manager" "8.14.0"
|
||||
"@typescript-eslint/type-utils" "8.14.0"
|
||||
"@typescript-eslint/utils" "8.14.0"
|
||||
"@typescript-eslint/visitor-keys" "8.14.0"
|
||||
graphemer "^1.4.0"
|
||||
ignore "^5.3.1"
|
||||
natural-compare "^1.4.0"
|
||||
ts-api-utils "^1.3.0"
|
||||
|
||||
"@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.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.12.2":
|
||||
version "8.12.2"
|
||||
resolved "https://registry.yarnpkg.com/@typescript-eslint/scope-manager/-/scope-manager-8.12.2.tgz#6db0213745e6392c8e90fe9af5915e6da32eb94a"
|
||||
integrity sha512-gPLpLtrj9aMHOvxJkSbDBmbRuYdtiEbnvO25bCMza3DhMjTQw0u7Y1M+YR5JPbMsXXnSPuCf5hfq0nEkQDL/JQ==
|
||||
"@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.12.2"
|
||||
"@typescript-eslint/visitor-keys" "8.12.2"
|
||||
"@typescript-eslint/types" "8.13.0"
|
||||
"@typescript-eslint/visitor-keys" "8.13.0"
|
||||
|
||||
"@typescript-eslint/type-utils@8.12.2":
|
||||
version "8.12.2"
|
||||
resolved "https://registry.yarnpkg.com/@typescript-eslint/type-utils/-/type-utils-8.12.2.tgz#132b0c52d45f6814e6f2e32416c7951ed480b016"
|
||||
integrity sha512-bwuU4TAogPI+1q/IJSKuD4shBLc/d2vGcRT588q+jzayQyjVK2X6v/fbR4InY2U2sgf8MEvVCqEWUzYzgBNcGQ==
|
||||
"@typescript-eslint/scope-manager@8.14.0":
|
||||
version "8.14.0"
|
||||
resolved "https://registry.yarnpkg.com/@typescript-eslint/scope-manager/-/scope-manager-8.14.0.tgz#01f37c147a735cd78f0ff355e033b9457da1f373"
|
||||
integrity sha512-aBbBrnW9ARIDn92Zbo7rguLnqQ/pOrUguVpbUwzOhkFg2npFDwTgPGqFqE0H5feXcOoJOfX3SxlJaKEVtq54dw==
|
||||
dependencies:
|
||||
"@typescript-eslint/typescript-estree" "8.12.2"
|
||||
"@typescript-eslint/utils" "8.12.2"
|
||||
"@typescript-eslint/types" "8.14.0"
|
||||
"@typescript-eslint/visitor-keys" "8.14.0"
|
||||
|
||||
"@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.13.0"
|
||||
"@typescript-eslint/utils" "8.13.0"
|
||||
debug "^4.3.4"
|
||||
ts-api-utils "^1.3.0"
|
||||
|
||||
"@typescript-eslint/types@8.12.2":
|
||||
version "8.12.2"
|
||||
resolved "https://registry.yarnpkg.com/@typescript-eslint/types/-/types-8.12.2.tgz#8d70098c0e90442495b53d0296acdca6d0f3f73c"
|
||||
integrity sha512-VwDwMF1SZ7wPBUZwmMdnDJ6sIFk4K4s+ALKLP6aIQsISkPv8jhiw65sAK6SuWODN/ix+m+HgbYDkH+zLjrzvOA==
|
||||
|
||||
"@typescript-eslint/typescript-estree@8.12.2":
|
||||
version "8.12.2"
|
||||
resolved "https://registry.yarnpkg.com/@typescript-eslint/typescript-estree/-/typescript-estree-8.12.2.tgz#206df9b1cbff212aaa9401985ef99f04daa84da5"
|
||||
integrity sha512-mME5MDwGe30Pq9zKPvyduyU86PH7aixwqYR2grTglAdB+AN8xXQ1vFGpYaUSJ5o5P/5znsSBeNcs5g5/2aQwow==
|
||||
"@typescript-eslint/type-utils@8.14.0":
|
||||
version "8.14.0"
|
||||
resolved "https://registry.yarnpkg.com/@typescript-eslint/type-utils/-/type-utils-8.14.0.tgz#455c6af30c336b24a1af28bc4f81b8dd5d74d94d"
|
||||
integrity sha512-Xcz9qOtZuGusVOH5Uk07NGs39wrKkf3AxlkK79RBK6aJC1l03CobXjJbwBPSidetAOV+5rEVuiT1VSBUOAsanQ==
|
||||
dependencies:
|
||||
"@typescript-eslint/types" "8.12.2"
|
||||
"@typescript-eslint/visitor-keys" "8.12.2"
|
||||
"@typescript-eslint/typescript-estree" "8.14.0"
|
||||
"@typescript-eslint/utils" "8.14.0"
|
||||
debug "^4.3.4"
|
||||
ts-api-utils "^1.3.0"
|
||||
|
||||
"@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/types@8.14.0":
|
||||
version "8.14.0"
|
||||
resolved "https://registry.yarnpkg.com/@typescript-eslint/types/-/types-8.14.0.tgz#0d33d8d0b08479c424e7d654855fddf2c71e4021"
|
||||
integrity sha512-yjeB9fnO/opvLJFAsPNYlKPnEM8+z4og09Pk504dkqonT02AyL5Z9SSqlE0XqezS93v6CXn49VHvB2G7XSsl0g==
|
||||
|
||||
"@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.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 +1642,54 @@
|
||||
semver "^7.6.0"
|
||||
ts-api-utils "^1.3.0"
|
||||
|
||||
"@typescript-eslint/utils@8.12.2":
|
||||
version "8.12.2"
|
||||
resolved "https://registry.yarnpkg.com/@typescript-eslint/utils/-/utils-8.12.2.tgz#726cc9f49f5866605bd15bbc1768ffc15637930e"
|
||||
integrity sha512-UTTuDIX3fkfAz6iSVa5rTuSfWIYZ6ATtEocQ/umkRSyC9O919lbZ8dcH7mysshrCdrAM03skJOEYaBugxN+M6A==
|
||||
"@typescript-eslint/typescript-estree@8.14.0":
|
||||
version "8.14.0"
|
||||
resolved "https://registry.yarnpkg.com/@typescript-eslint/typescript-estree/-/typescript-estree-8.14.0.tgz#a7a3a5a53a6c09313e12fb4531d4ff582ee3c312"
|
||||
integrity sha512-OPXPLYKGZi9XS/49rdaCbR5j/S14HazviBlUQFvSKz3npr3NikF+mrgK7CFVur6XEt95DZp/cmke9d5i3vtVnQ==
|
||||
dependencies:
|
||||
"@typescript-eslint/types" "8.14.0"
|
||||
"@typescript-eslint/visitor-keys" "8.14.0"
|
||||
debug "^4.3.4"
|
||||
fast-glob "^3.3.2"
|
||||
is-glob "^4.0.3"
|
||||
minimatch "^9.0.4"
|
||||
semver "^7.6.0"
|
||||
ts-api-utils "^1.3.0"
|
||||
|
||||
"@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.12.2"
|
||||
"@typescript-eslint/types" "8.12.2"
|
||||
"@typescript-eslint/typescript-estree" "8.12.2"
|
||||
"@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.12.2":
|
||||
version "8.12.2"
|
||||
resolved "https://registry.yarnpkg.com/@typescript-eslint/visitor-keys/-/visitor-keys-8.12.2.tgz#94d7410f78eb6d134b9fcabaf1eeedb910ba8c38"
|
||||
integrity sha512-PChz8UaKQAVNHghsHcPyx1OMHoFRUEA7rJSK/mDhdq85bk+PLsUHUBqTQTFt18VJZbmxBovM65fezlheQRsSDA==
|
||||
"@typescript-eslint/utils@8.14.0":
|
||||
version "8.14.0"
|
||||
resolved "https://registry.yarnpkg.com/@typescript-eslint/utils/-/utils-8.14.0.tgz#ac2506875e03aba24e602364e43b2dfa45529dbd"
|
||||
integrity sha512-OGqj6uB8THhrHj0Fk27DcHPojW7zKwKkPmHXHvQ58pLYp4hy8CSUdTKykKeh+5vFqTTVmjz0zCOOPKRovdsgHA==
|
||||
dependencies:
|
||||
"@typescript-eslint/types" "8.12.2"
|
||||
"@eslint-community/eslint-utils" "^4.4.0"
|
||||
"@typescript-eslint/scope-manager" "8.14.0"
|
||||
"@typescript-eslint/types" "8.14.0"
|
||||
"@typescript-eslint/typescript-estree" "8.14.0"
|
||||
|
||||
"@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.13.0"
|
||||
eslint-visitor-keys "^3.4.3"
|
||||
|
||||
"@typescript-eslint/visitor-keys@8.14.0":
|
||||
version "8.14.0"
|
||||
resolved "https://registry.yarnpkg.com/@typescript-eslint/visitor-keys/-/visitor-keys-8.14.0.tgz#2418d5a54669af9658986ade4e6cfb7767d815ad"
|
||||
integrity sha512-vG0XZo8AdTH9OE6VFRwAZldNc7qtJ/6NLGWak+BtENuEUXGZgFpihILPiBvKXvJ2nFu27XNGC6rKiwuaoMbYzQ==
|
||||
dependencies:
|
||||
"@typescript-eslint/types" "8.14.0"
|
||||
eslint-visitor-keys "^3.4.3"
|
||||
|
||||
"@vitejs/plugin-react@^4.3.3":
|
||||
@@ -1658,10 +1733,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"
|
||||
@@ -2207,10 +2282,10 @@ cross-fetch@^3.0.4:
|
||||
dependencies:
|
||||
node-fetch "^2.6.12"
|
||||
|
||||
cross-spawn@^7.0.2, cross-spawn@^7.0.3:
|
||||
version "7.0.3"
|
||||
resolved "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz"
|
||||
integrity sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==
|
||||
cross-spawn@^7.0.3, cross-spawn@^7.0.5:
|
||||
version "7.0.5"
|
||||
resolved "https://registry.yarnpkg.com/cross-spawn/-/cross-spawn-7.0.5.tgz#910aac880ff5243da96b728bc6521a5f6c2f2f82"
|
||||
integrity sha512-ZVJrKKYunU38/76t0RMOulHOnUcbU9GbpWKAOZ0mhjr7CX6FVrH+4FrAapSOekrgFQ3f/8gwMEuIft0aKq6Hug==
|
||||
dependencies:
|
||||
path-key "^3.1.0"
|
||||
shebang-command "^2.0.0"
|
||||
@@ -2756,10 +2831,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"
|
||||
@@ -2769,36 +2844,36 @@ 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.15.0:
|
||||
version "9.15.0"
|
||||
resolved "https://registry.yarnpkg.com/eslint/-/eslint-9.15.0.tgz#77c684a4e980e82135ebff8ee8f0a9106ce6b8a6"
|
||||
integrity sha512-7CrWySmIibCgT1Os28lUU6upBshZ+GxybLOrmRzi08kS8MBuO8QA7pXEgYgY5W8vK3e74xv0lpjo9DbaGU9Rkw==
|
||||
dependencies:
|
||||
"@eslint-community/eslint-utils" "^4.2.0"
|
||||
"@eslint-community/regexpp" "^4.11.0"
|
||||
"@eslint/config-array" "^0.18.0"
|
||||
"@eslint/core" "^0.7.0"
|
||||
"@eslint/eslintrc" "^3.1.0"
|
||||
"@eslint/js" "9.13.0"
|
||||
"@eslint/plugin-kit" "^0.2.0"
|
||||
"@humanfs/node" "^0.16.5"
|
||||
"@eslint-community/regexpp" "^4.12.1"
|
||||
"@eslint/config-array" "^0.19.0"
|
||||
"@eslint/core" "^0.9.0"
|
||||
"@eslint/eslintrc" "^3.2.0"
|
||||
"@eslint/js" "9.15.0"
|
||||
"@eslint/plugin-kit" "^0.2.3"
|
||||
"@humanfs/node" "^0.16.6"
|
||||
"@humanwhocodes/module-importer" "^1.0.1"
|
||||
"@humanwhocodes/retry" "^0.3.1"
|
||||
"@humanwhocodes/retry" "^0.4.1"
|
||||
"@types/estree" "^1.0.6"
|
||||
"@types/json-schema" "^7.0.15"
|
||||
ajv "^6.12.4"
|
||||
chalk "^4.0.0"
|
||||
cross-spawn "^7.0.2"
|
||||
cross-spawn "^7.0.5"
|
||||
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"
|
||||
@@ -2813,16 +2888,15 @@ eslint@^9.13.0:
|
||||
minimatch "^3.1.2"
|
||||
natural-compare "^1.4.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"
|
||||
@@ -4643,10 +4717,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.1, ra-core@^5.3.2:
|
||||
version "5.3.2"
|
||||
resolved "https://registry.yarnpkg.com/ra-core/-/ra-core-5.3.2.tgz#8d60096f9bd3b88339fa798f42be21791813199e"
|
||||
integrity sha512-JDZ44jMCTlAXWWdR8LLFXXjKIc6bNf4L/zjY9/iL9yP5Kcy4yNf4kTBzR46dNWpt5/3k4Z59cMKBf+A9fDjJAQ==
|
||||
ra-core@^5.3.3, ra-core@^5.3.4:
|
||||
version "5.3.4"
|
||||
resolved "https://registry.yarnpkg.com/ra-core/-/ra-core-5.3.4.tgz#849f6da3460b896f295f5a88ea2b8a1487c7111d"
|
||||
integrity sha512-BC6pO8jaUjJESfO0FS6J2CMgeRreJ2kpdPkkySBODM0M5S4ZRC0rOFh1jBXFnjSUcNoPWaVc/WaZPwfAg00Wmw==
|
||||
dependencies:
|
||||
"@tanstack/react-query" "^5.8.4"
|
||||
clsx "^2.1.1"
|
||||
@@ -4659,32 +4733,32 @@ ra-core@^5.3.1, ra-core@^5.3.2:
|
||||
react-error-boundary "^4.0.13"
|
||||
react-is "^18.2.0"
|
||||
|
||||
ra-i18n-polyglot@^5.3.1, ra-i18n-polyglot@^5.3.2:
|
||||
version "5.3.2"
|
||||
resolved "https://registry.yarnpkg.com/ra-i18n-polyglot/-/ra-i18n-polyglot-5.3.2.tgz#7da554550fe8e7d2a2028d68280767a9392603cb"
|
||||
integrity sha512-jyaDTPKyJOZlMnvLnrw7dqpD/ek01iVFg73FGoI3PAD/xYwKj4AfJBvwWlLVwlc6TOz9fcwd4hTWWVKbOMMFbA==
|
||||
ra-i18n-polyglot@^5.3.3, ra-i18n-polyglot@^5.3.4:
|
||||
version "5.3.4"
|
||||
resolved "https://registry.yarnpkg.com/ra-i18n-polyglot/-/ra-i18n-polyglot-5.3.4.tgz#f4653d6d6a9bcf1f52d65993e2a6e5acf2b7e000"
|
||||
integrity sha512-9BtWoCHE5LxIN4+VJGOrxL29lDhCTgBjIDkTb/i228vr/CD3+ozjyMiBG8NGeLN5wCqtHpsKDwUNJOcoPtwkiQ==
|
||||
dependencies:
|
||||
node-polyglot "^2.2.2"
|
||||
ra-core "^5.3.2"
|
||||
ra-core "^5.3.4"
|
||||
|
||||
ra-language-english@^5.3.1, ra-language-english@^5.3.2:
|
||||
version "5.3.2"
|
||||
resolved "https://registry.yarnpkg.com/ra-language-english/-/ra-language-english-5.3.2.tgz#9d4fc545b05bda945c9ec96d60203ca2d560f632"
|
||||
integrity sha512-otfNWGAyRXuaEBYneYpNaNj96umOLQ+MVtWPJSHvHXq80nRL0y2tEy0RNDrdIayvF6Q9dRYs1Q7a+mV0tkNbAw==
|
||||
ra-language-english@^5.3.3, ra-language-english@^5.3.4:
|
||||
version "5.3.4"
|
||||
resolved "https://registry.yarnpkg.com/ra-language-english/-/ra-language-english-5.3.4.tgz#a1ffcd848ec1b080f4dc3728332e0ceedb1f6783"
|
||||
integrity sha512-QR0ej0JKQaGmtGSh1W+O4HnoaTv/9SQBtpztAkTitPVjlCGJeNBr/IjriAxsp0ezhhCr+uZrwrCfoWjKPkjpDg==
|
||||
dependencies:
|
||||
ra-core "^5.3.2"
|
||||
ra-core "^5.3.4"
|
||||
|
||||
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.1:
|
||||
version "5.3.1"
|
||||
resolved "https://registry.yarnpkg.com/ra-language-french/-/ra-language-french-5.3.1.tgz#e7a555af44b4c227bf29ce902db40c82eb5c022a"
|
||||
integrity sha512-qJxKGDpL2KYQ7U0s5WsjcAvEbJJITduD/QXNUS4PJCDuijekiH9BwzL3kHE8PxdxJHsBS5djPEAxzD9IW8jfiw==
|
||||
ra-language-french@^5.3.4:
|
||||
version "5.3.4"
|
||||
resolved "https://registry.yarnpkg.com/ra-language-french/-/ra-language-french-5.3.4.tgz#11c16d9fcefcf1e9f82ac291fe7f6beb083a1a22"
|
||||
integrity sha512-7w+Z7Dpvo+hSa3MWcM3O6HnbGgrhi9RnDxDygDCOlV01oDgYBz+sgZE+aZUzOHkmVdvCT1hpaytGJYqiT06Sqg==
|
||||
dependencies:
|
||||
ra-core "^5.3.1"
|
||||
ra-core "^5.3.4"
|
||||
|
||||
ra-language-italian@^3.13.1:
|
||||
version "3.13.1"
|
||||
@@ -4698,10 +4772,10 @@ ra-language-russian@^4.14.2:
|
||||
dependencies:
|
||||
ra-core "^4.16.2"
|
||||
|
||||
ra-ui-materialui@^5.3.1:
|
||||
version "5.3.1"
|
||||
resolved "https://registry.yarnpkg.com/ra-ui-materialui/-/ra-ui-materialui-5.3.1.tgz#67ca58752519b6ea430d5fba13bb0e5496479e77"
|
||||
integrity sha512-ViLAtCVsdAPrdT72K1W2a00UkZZI0FSw8YTsrPBPPjLfaH1MpjEAG2cwI9ODuPDe65/GkiM1W0husWV5JveLnw==
|
||||
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"
|
||||
@@ -4716,19 +4790,19 @@ ra-ui-materialui@^5.3.1:
|
||||
react-error-boundary "^4.0.13"
|
||||
react-transition-group "^4.4.5"
|
||||
|
||||
react-admin@^5.3.1:
|
||||
version "5.3.1"
|
||||
resolved "https://registry.yarnpkg.com/react-admin/-/react-admin-5.3.1.tgz#9748328c3671c228cf45809ae2123bfc76423e53"
|
||||
integrity sha512-pxEccGTXwreI0EhPgssp0B8fWMk68fCmpHImjVZ8SJ//zXWncffwcbRwb7HbvkF56Zp3ivx9UIZ/vvuBCjN49g==
|
||||
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.1"
|
||||
ra-i18n-polyglot "^5.3.1"
|
||||
ra-language-english "^5.3.1"
|
||||
ra-ui-materialui "^5.3.1"
|
||||
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"
|
||||
@@ -4791,20 +4865,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"
|
||||
@@ -5271,11 +5345,6 @@ test-exclude@^6.0.0:
|
||||
glob "^7.1.4"
|
||||
minimatch "^3.0.4"
|
||||
|
||||
text-table@^0.2.0:
|
||||
version "0.2.0"
|
||||
resolved "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz"
|
||||
integrity sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw==
|
||||
|
||||
tmpl@1.0.5:
|
||||
version "1.0.5"
|
||||
resolved "https://registry.npmjs.org/tmpl/-/tmpl-1.0.5.tgz"
|
||||
@@ -5435,14 +5504,14 @@ typed-array-length@^1.0.6:
|
||||
is-typed-array "^1.1.13"
|
||||
possible-typed-array-names "^1.0.0"
|
||||
|
||||
typescript-eslint@^8.12.2:
|
||||
version "8.12.2"
|
||||
resolved "https://registry.yarnpkg.com/typescript-eslint/-/typescript-eslint-8.12.2.tgz#e273d69af30b478b1c410f4159d675ce7925f9a7"
|
||||
integrity sha512-UbuVUWSrHVR03q9CWx+JDHeO6B/Hr9p4U5lRH++5tq/EbFq1faYZe50ZSBePptgfIKLEti0aPQ3hFgnPVcd8ZQ==
|
||||
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.12.2"
|
||||
"@typescript-eslint/parser" "8.12.2"
|
||||
"@typescript-eslint/utils" "8.12.2"
|
||||
"@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"
|
||||
@@ -5519,10 +5588,10 @@ vite-plugin-version-mark@^0.1.2:
|
||||
resolved "https://registry.yarnpkg.com/vite-plugin-version-mark/-/vite-plugin-version-mark-0.1.2.tgz#85b2315cffce7ac2d83b6afceb313d0d1c47c4d4"
|
||||
integrity sha512-+mPRTwx6SOEfEq3/y1u+O0ju5Lz0Ac27Fx6hE5Xn1fMpIQfo3aERPB2/xxYI8lIa8GPHCX5c8ApqBKWwFNHxwA==
|
||||
|
||||
vite@^5.4.10:
|
||||
version "5.4.10"
|
||||
resolved "https://registry.yarnpkg.com/vite/-/vite-5.4.10.tgz#d358a7bd8beda6cf0f3b7a450a8c7693a4f80c18"
|
||||
integrity sha512-1hvaPshuPUtxeQ0hsVH3Mud0ZanOLwVTneA1EgbAM5LhaZEqyPWGRQ7BtaMvUrTDeEaC8pxtj6a6jku3x4z6SQ==
|
||||
vite@^5.4.11:
|
||||
version "5.4.11"
|
||||
resolved "https://registry.yarnpkg.com/vite/-/vite-5.4.11.tgz#3b415cd4aed781a356c1de5a9ebafb837715f6e5"
|
||||
integrity sha512-c7jFQRklXua0mTzneGW9QVyxFjUgwcihC4bXEtujIo2ouWCe1Ajt/amn2PCxYnhYfd5k09JX3SB7OYWFKYqj8Q==
|
||||
dependencies:
|
||||
esbuild "^0.21.3"
|
||||
postcss "^8.4.43"
|
||||
|
Reference in New Issue
Block a user