Merge branch 'master' into french-translation
This commit is contained in:
commit
ccf53288ce
20
.github/dependabot.yml
vendored
Normal file
20
.github/dependabot.yml
vendored
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
version: 2
|
||||||
|
updates:
|
||||||
|
- package-ecosystem: "npm"
|
||||||
|
directory: "/"
|
||||||
|
schedule:
|
||||||
|
interval: "weekly"
|
||||||
|
ignore:
|
||||||
|
# Major updates for react-admin have breaking changes
|
||||||
|
- dependency-name: "react-admin"
|
||||||
|
update-types: ["version-update:semver-major"]
|
||||||
|
|
||||||
|
- package-ecosystem: "docker"
|
||||||
|
directory: "/"
|
||||||
|
schedule:
|
||||||
|
interval: "weekly"
|
||||||
|
|
||||||
|
- package-ecosystem: "github-actions"
|
||||||
|
directory: "/"
|
||||||
|
schedule:
|
||||||
|
interval: "weekly"
|
6
.github/workflows/build-test.yml
vendored
6
.github/workflows/build-test.yml
vendored
@ -10,11 +10,11 @@ jobs:
|
|||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
- name: Checkout
|
- name: Checkout
|
||||||
uses: actions/checkout@v2
|
uses: actions/checkout@v3
|
||||||
- name: Setup node
|
- name: Setup node
|
||||||
uses: actions/setup-node@v2
|
uses: actions/setup-node@v3
|
||||||
with:
|
with:
|
||||||
node-version: 14
|
node-version: 16
|
||||||
- name: Install dependencies
|
- name: Install dependencies
|
||||||
run: yarn --frozen-lockfile
|
run: yarn --frozen-lockfile
|
||||||
- name: Run tests
|
- name: Run tests
|
||||||
|
10
.github/workflows/docker-release.yml
vendored
10
.github/workflows/docker-release.yml
vendored
@ -17,13 +17,13 @@ jobs:
|
|||||||
|
|
||||||
steps:
|
steps:
|
||||||
- name: Checkout
|
- name: Checkout
|
||||||
uses: actions/checkout@v2
|
uses: actions/checkout@v3
|
||||||
- name: Set up QEMU
|
- name: Set up QEMU
|
||||||
uses: docker/setup-qemu-action@v1
|
uses: docker/setup-qemu-action@v2
|
||||||
- name: Set up Docker Buildx
|
- name: Set up Docker Buildx
|
||||||
uses: docker/setup-buildx-action@v1
|
uses: docker/setup-buildx-action@v2
|
||||||
- name: Login to DockerHub
|
- name: Login to DockerHub
|
||||||
uses: docker/login-action@v1
|
uses: docker/login-action@v2
|
||||||
with:
|
with:
|
||||||
username: ${{ secrets.DOCKERHUB_USERNAME }}
|
username: ${{ secrets.DOCKERHUB_USERNAME }}
|
||||||
password: ${{ secrets.DOCKERHUB_TOKEN }}
|
password: ${{ secrets.DOCKERHUB_TOKEN }}
|
||||||
@ -43,7 +43,7 @@ jobs:
|
|||||||
esac
|
esac
|
||||||
echo "::set-output name=tag::$tag"
|
echo "::set-output name=tag::$tag"
|
||||||
- name: Build and Push Tag
|
- name: Build and Push Tag
|
||||||
uses: docker/build-push-action@v2
|
uses: docker/build-push-action@v3
|
||||||
with:
|
with:
|
||||||
context: .
|
context: .
|
||||||
push: true
|
push: true
|
||||||
|
8
.github/workflows/edge_ghpage.yml
vendored
8
.github/workflows/edge_ghpage.yml
vendored
@ -10,17 +10,17 @@ jobs:
|
|||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
- name: Checkout 🛎️
|
- name: Checkout 🛎️
|
||||||
uses: actions/checkout@v2.3.1
|
uses: actions/checkout@v3
|
||||||
- uses: actions/setup-node@v2
|
- uses: actions/setup-node@v3
|
||||||
with:
|
with:
|
||||||
node-version: "14"
|
node-version: "16"
|
||||||
- name: Install and Build 🔧
|
- name: Install and Build 🔧
|
||||||
run: |
|
run: |
|
||||||
yarn install
|
yarn install
|
||||||
yarn build
|
yarn build
|
||||||
|
|
||||||
- name: Deploy 🚀
|
- name: Deploy 🚀
|
||||||
uses: JamesIves/github-pages-deploy-action@4.1.5
|
uses: JamesIves/github-pages-deploy-action@v4.4.1
|
||||||
with:
|
with:
|
||||||
branch: gh-pages
|
branch: gh-pages
|
||||||
folder: build
|
folder: build
|
||||||
|
8
.github/workflows/github-release.yml
vendored
8
.github/workflows/github-release.yml
vendored
@ -13,10 +13,10 @@ jobs:
|
|||||||
packages: write
|
packages: write
|
||||||
|
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v2
|
- uses: actions/checkout@v3
|
||||||
- uses: actions/setup-node@v2
|
- uses: actions/setup-node@v3
|
||||||
with:
|
with:
|
||||||
node-version: "14"
|
node-version: "16"
|
||||||
- run: yarn install
|
- run: yarn install
|
||||||
- run: yarn build
|
- run: yarn build
|
||||||
- run: |
|
- run: |
|
||||||
@ -24,7 +24,7 @@ jobs:
|
|||||||
mkdir -p dist
|
mkdir -p dist
|
||||||
cp -r build synapse-admin-$version
|
cp -r build synapse-admin-$version
|
||||||
tar chvzf dist/synapse-admin-$version.tar.gz synapse-admin-$version
|
tar chvzf dist/synapse-admin-$version.tar.gz synapse-admin-$version
|
||||||
- uses: softprops/action-gh-release@b7e450da2a4b4cb4bfbae528f788167786cfcedf
|
- uses: softprops/action-gh-release@de2c0eb89ae2a093876385947365aca7b0e5f844
|
||||||
with:
|
with:
|
||||||
files: dist/*.tar.gz
|
files: dist/*.tar.gz
|
||||||
env:
|
env:
|
||||||
|
@ -6,6 +6,6 @@
|
|||||||
"singleQuote": false,
|
"singleQuote": false,
|
||||||
"trailingComma": "es5",
|
"trailingComma": "es5",
|
||||||
"bracketSpacing": true,
|
"bracketSpacing": true,
|
||||||
"jsxBracketSameLine": false,
|
"bracketSameLine": false,
|
||||||
"arrowParens": "avoid"
|
"arrowParens": "avoid"
|
||||||
}
|
}
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
|
dist: focal
|
||||||
language: node_js
|
language: node_js
|
||||||
node_js:
|
node_js:
|
||||||
- lts/*
|
- 17
|
||||||
|
|
||||||
cache: yarn
|
cache: yarn
|
||||||
|
12
README.md
12
README.md
@ -1,5 +1,9 @@
|
|||||||
[](https://travis-ci.org/Awesome-Technologies/synapse-admin)
|
[](https://github.com/Awesome-Technologies/synapse-admin/blob/master/LICENSE)
|
||||||
|
[](https://app.travis-ci.com/github/Awesome-Technologies/synapse-admin)
|
||||||
[](https://github.com/Awesome-Technologies/synapse-admin/actions/workflows/build-test.yml)
|
[](https://github.com/Awesome-Technologies/synapse-admin/actions/workflows/build-test.yml)
|
||||||
|
[](https://awesome-technologies.github.io/synapse-admin/)
|
||||||
|
[](https://hub.docker.com/r/awesometechnologies/synapse-admin)
|
||||||
|
[](https://github.com/Awesome-Technologies/synapse-admin/releases)
|
||||||
|
|
||||||
# Synapse admin ui
|
# Synapse admin ui
|
||||||
|
|
||||||
@ -9,7 +13,7 @@ This project is built using [react-admin](https://marmelab.com/react-admin/).
|
|||||||
|
|
||||||
### Supported Synapse
|
### Supported Synapse
|
||||||
|
|
||||||
It needs at least [Synapse](https://github.com/matrix-org/synapse) v1.42.0 for all functions to work as expected!
|
It needs at least [Synapse](https://github.com/matrix-org/synapse) v1.52.0 for all functions to work as expected!
|
||||||
|
|
||||||
You get your server version with the request `/_synapse/admin/v1/server_version`.
|
You get your server version with the request `/_synapse/admin/v1/server_version`.
|
||||||
See also [Synapse version API](https://matrix-org.github.io/synapse/develop/admin_api/version_api.html).
|
See also [Synapse version API](https://matrix-org.github.io/synapse/develop/admin_api/version_api.html).
|
||||||
@ -82,8 +86,8 @@ or by editing it in the [.env](.env) file. See also the
|
|||||||
context: https://github.com/Awesome-Technologies/synapse-admin.git
|
context: https://github.com/Awesome-Technologies/synapse-admin.git
|
||||||
# args:
|
# args:
|
||||||
# - NODE_OPTIONS="--max_old_space_size=1024"
|
# - NODE_OPTIONS="--max_old_space_size=1024"
|
||||||
# # see #266
|
# # see #266, PUBLIC_URL must be without surrounding quotation marks
|
||||||
# - PUBLIC_URL="/synapse-admin"
|
# - PUBLIC_URL=/synapse-admin
|
||||||
# - REACT_APP_SERVER="https://matrix.example.com"
|
# - REACT_APP_SERVER="https://matrix.example.com"
|
||||||
ports:
|
ports:
|
||||||
- "8080:80"
|
- "8080:80"
|
||||||
|
@ -12,10 +12,15 @@ services:
|
|||||||
# replace the context definition with this:
|
# replace the context definition with this:
|
||||||
# context: https://github.com/Awesome-Technologies/synapse-admin.git
|
# context: https://github.com/Awesome-Technologies/synapse-admin.git
|
||||||
|
|
||||||
|
# args:
|
||||||
# if you're building on an architecture other than amd64, make sure
|
# if you're building on an architecture other than amd64, make sure
|
||||||
# to define a maximum ram for node. otherwise the build will fail.
|
# to define a maximum ram for node. otherwise the build will fail.
|
||||||
# args:
|
|
||||||
# - NODE_OPTIONS="--max_old_space_size=1024"
|
# - NODE_OPTIONS="--max_old_space_size=1024"
|
||||||
|
# default is /
|
||||||
|
# - PUBLIC_URL=/synapse-admin
|
||||||
|
# You can use a fixed homeserver, so that the user can no longer
|
||||||
|
# define it himself
|
||||||
|
# - REACT_APP_SERVER="https://matrix.example.com"
|
||||||
ports:
|
ports:
|
||||||
- "8080:80"
|
- "8080:80"
|
||||||
restart: unless-stopped
|
restart: unless-stopped
|
||||||
|
15
package.json
15
package.json
@ -10,17 +10,22 @@
|
|||||||
"url": "https://github.com/Awesome-Technologies/synapse-admin"
|
"url": "https://github.com/Awesome-Technologies/synapse-admin"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@testing-library/jest-dom": "^5.1.1",
|
"@testing-library/jest-dom": "^5.16.5",
|
||||||
"@testing-library/react": "^11.2.6",
|
"@testing-library/react": "^11.2.6",
|
||||||
"@testing-library/user-event": "^13.1.8",
|
"@testing-library/user-event": "^14.4.3",
|
||||||
"eslint": "^7.25.0",
|
"eslint": "^8.32.0",
|
||||||
"eslint-config-prettier": "^8.3.0",
|
"eslint-config-prettier": "^8.3.0",
|
||||||
"eslint-plugin-prettier": "^3.1.2",
|
"eslint-config-react-app": "^7.0.1",
|
||||||
|
"eslint-plugin-prettier": "^4.2.1",
|
||||||
"jest-fetch-mock": "^3.0.3",
|
"jest-fetch-mock": "^3.0.3",
|
||||||
"prettier": "^2.2.0",
|
"prettier": "^2.2.0",
|
||||||
"ra-test": "^3.15.0"
|
"ra-test": "^3.15.0"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
|
"@emotion/react": "^11.7.1",
|
||||||
|
"@emotion/styled": "^11.6.0",
|
||||||
|
"@mui/icons-material": "^5.3.1",
|
||||||
|
"@mui/material": "^5.4.0",
|
||||||
"papaparse": "^5.2.0",
|
"papaparse": "^5.2.0",
|
||||||
"prop-types": "^15.7.2",
|
"prop-types": "^15.7.2",
|
||||||
"ra-language-chinese": "^2.0.10",
|
"ra-language-chinese": "^2.0.10",
|
||||||
@ -29,7 +34,7 @@
|
|||||||
"react": "^17.0.0",
|
"react": "^17.0.0",
|
||||||
"react-admin": "^3.19.7",
|
"react-admin": "^3.19.7",
|
||||||
"react-dom": "^17.0.2",
|
"react-dom": "^17.0.2",
|
||||||
"react-scripts": "^4.0.0"
|
"react-scripts": "^5.0.1"
|
||||||
},
|
},
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"start": "REACT_APP_VERSION=$(git describe --tags) react-scripts start",
|
"start": "REACT_APP_VERSION=$(git describe --tags) react-scripts start",
|
||||||
|
21
src/App.js
21
src/App.js
@ -7,13 +7,15 @@ import { UserList, UserCreate, UserEdit } from "./components/users";
|
|||||||
import { RoomList, RoomShow } from "./components/rooms";
|
import { RoomList, RoomShow } from "./components/rooms";
|
||||||
import { ReportList, ReportShow } from "./components/EventReports";
|
import { ReportList, ReportShow } from "./components/EventReports";
|
||||||
import LoginPage from "./components/LoginPage";
|
import LoginPage from "./components/LoginPage";
|
||||||
import UserIcon from "@material-ui/icons/Group";
|
import ConfirmationNumberIcon from "@mui/icons-material/ConfirmationNumber";
|
||||||
import ConfirmationNumberIcon from "@material-ui/icons/ConfirmationNumber";
|
import CloudQueueIcon from "@mui/icons-material/CloudQueue";
|
||||||
import EqualizerIcon from "@material-ui/icons/Equalizer";
|
import EqualizerIcon from "@mui/icons-material/Equalizer";
|
||||||
|
import UserIcon from "@mui/icons-material/Group";
|
||||||
import { UserMediaStatsList } from "./components/statistics";
|
import { UserMediaStatsList } from "./components/statistics";
|
||||||
import RoomIcon from "@material-ui/icons/ViewList";
|
import RoomIcon from "@mui/icons-material/ViewList";
|
||||||
import ReportIcon from "@material-ui/icons/Warning";
|
import ReportIcon from "@mui/icons-material/Warning";
|
||||||
import FolderSharedIcon from "@material-ui/icons/FolderShared";
|
import FolderSharedIcon from "@mui/icons-material/FolderShared";
|
||||||
|
import { DestinationList, DestinationShow } from "./components/destinations";
|
||||||
import { ImportFeature } from "./components/ImportFeature";
|
import { ImportFeature } from "./components/ImportFeature";
|
||||||
import {
|
import {
|
||||||
RegistrationTokenCreate,
|
RegistrationTokenCreate,
|
||||||
@ -74,6 +76,12 @@ const App = () => (
|
|||||||
list={RoomDirectoryList}
|
list={RoomDirectoryList}
|
||||||
icon={FolderSharedIcon}
|
icon={FolderSharedIcon}
|
||||||
/>
|
/>
|
||||||
|
<Resource
|
||||||
|
name="destinations"
|
||||||
|
list={DestinationList}
|
||||||
|
show={DestinationShow}
|
||||||
|
icon={CloudQueueIcon}
|
||||||
|
/>
|
||||||
<Resource
|
<Resource
|
||||||
name="registration_tokens"
|
name="registration_tokens"
|
||||||
list={RegistrationTokenList}
|
list={RegistrationTokenList}
|
||||||
@ -90,6 +98,7 @@ const App = () => (
|
|||||||
<Resource name="servernotices" />
|
<Resource name="servernotices" />
|
||||||
<Resource name="forward_extremities" />
|
<Resource name="forward_extremities" />
|
||||||
<Resource name="room_state" />
|
<Resource name="room_state" />
|
||||||
|
<Resource name="destination_rooms" />
|
||||||
</Admin>
|
</Admin>
|
||||||
);
|
);
|
||||||
|
|
||||||
|
@ -12,8 +12,8 @@ import {
|
|||||||
TextField,
|
TextField,
|
||||||
useTranslate,
|
useTranslate,
|
||||||
} from "react-admin";
|
} from "react-admin";
|
||||||
import PageviewIcon from "@material-ui/icons/Pageview";
|
import PageviewIcon from "@mui/icons-material/Pageview";
|
||||||
import ViewListIcon from "@material-ui/icons/ViewList";
|
import ViewListIcon from "@mui/icons-material/ViewList";
|
||||||
|
|
||||||
const date_format = {
|
const date_format = {
|
||||||
year: "numeric",
|
year: "numeric",
|
||||||
|
@ -6,19 +6,19 @@ import {
|
|||||||
Title,
|
Title,
|
||||||
} from "react-admin";
|
} from "react-admin";
|
||||||
import { parse as parseCsv, unparse as unparseCsv } from "papaparse";
|
import { parse as parseCsv, unparse as unparseCsv } from "papaparse";
|
||||||
import GetAppIcon from "@material-ui/icons/GetApp";
|
import GetAppIcon from "@mui/icons-material/GetApp";
|
||||||
import {
|
import {
|
||||||
Button,
|
Button,
|
||||||
Card,
|
Card,
|
||||||
CardActions,
|
CardActions,
|
||||||
CardContent,
|
CardContent,
|
||||||
CardHeader,
|
CardHeader,
|
||||||
FormControlLabel,
|
|
||||||
Checkbox,
|
Checkbox,
|
||||||
|
Container,
|
||||||
|
FormControlLabel,
|
||||||
NativeSelect,
|
NativeSelect,
|
||||||
} from "@material-ui/core";
|
} from "@mui/material";
|
||||||
import { useTranslate } from "ra-core";
|
import { useTranslate } from "ra-core";
|
||||||
import Container from "@material-ui/core/Container/Container";
|
|
||||||
import { generateRandomUser } from "./users";
|
import { generateRandomUser } from "./users";
|
||||||
|
|
||||||
const LOGGING = true;
|
const LOGGING = true;
|
||||||
|
@ -21,9 +21,9 @@ import {
|
|||||||
MenuItem,
|
MenuItem,
|
||||||
Select,
|
Select,
|
||||||
TextField,
|
TextField,
|
||||||
} from "@material-ui/core";
|
} from "@mui/material";
|
||||||
import { makeStyles } from "@material-ui/core/styles";
|
import { makeStyles } from "@material-ui/core/styles";
|
||||||
import LockIcon from "@material-ui/icons/Lock";
|
import LockIcon from "@mui/icons-material/Lock";
|
||||||
|
|
||||||
const useStyles = makeStyles(theme => ({
|
const useStyles = makeStyles(theme => ({
|
||||||
main: {
|
main: {
|
||||||
@ -169,7 +169,7 @@ const LoginPage = ({ theme }) => {
|
|||||||
: typeof error === "undefined" || !error.message
|
: typeof error === "undefined" || !error.message
|
||||||
? "ra.auth.sign_in_error"
|
? "ra.auth.sign_in_error"
|
||||||
: error.message,
|
: error.message,
|
||||||
"warning"
|
{ type: "warning" }
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
@ -269,7 +269,7 @@ const LoginPage = ({ theme }) => {
|
|||||||
autoFocus
|
autoFocus
|
||||||
name="username"
|
name="username"
|
||||||
component={renderInput}
|
component={renderInput}
|
||||||
label={translate("ra.auth.username")}
|
label="ra.auth.username"
|
||||||
disabled={loading || !supportPassAuth}
|
disabled={loading || !supportPassAuth}
|
||||||
onBlur={handleUsernameChange}
|
onBlur={handleUsernameChange}
|
||||||
resettable
|
resettable
|
||||||
@ -280,7 +280,7 @@ const LoginPage = ({ theme }) => {
|
|||||||
<PasswordInput
|
<PasswordInput
|
||||||
name="password"
|
name="password"
|
||||||
component={renderInput}
|
component={renderInput}
|
||||||
label={translate("ra.auth.password")}
|
label="ra.auth.password"
|
||||||
type="password"
|
type="password"
|
||||||
disabled={loading || !supportPassAuth}
|
disabled={loading || !supportPassAuth}
|
||||||
resettable
|
resettable
|
||||||
@ -291,7 +291,7 @@ const LoginPage = ({ theme }) => {
|
|||||||
<TextInput
|
<TextInput
|
||||||
name="base_url"
|
name="base_url"
|
||||||
component={renderInput}
|
component={renderInput}
|
||||||
label={translate("synapseadmin.auth.base_url")}
|
label="synapseadmin.auth.base_url"
|
||||||
disabled={cfg_base_url || loading}
|
disabled={cfg_base_url || loading}
|
||||||
resettable
|
resettable
|
||||||
fullWidth
|
fullWidth
|
||||||
|
@ -1,10 +1,10 @@
|
|||||||
// in src/Menu.js
|
// in src/Menu.js
|
||||||
import * as React from "react";
|
import * as React from "react";
|
||||||
import { useSelector } from "react-redux";
|
import { useSelector } from "react-redux";
|
||||||
import { useMediaQuery } from "@material-ui/core";
|
import { useMediaQuery } from "@mui/material";
|
||||||
import { MenuItemLink, getResources } from "react-admin";
|
import { MenuItemLink, getResources } from "react-admin";
|
||||||
import DefaultIcon from "@material-ui/icons/ViewList";
|
import DefaultIcon from "@mui/icons-material/ViewList";
|
||||||
import LabelIcon from "@material-ui/icons/Label";
|
import LabelIcon from "@mui/icons-material/Label";
|
||||||
|
|
||||||
const Menu = ({ onMenuClick, logout }) => {
|
const Menu = ({ onMenuClick, logout }) => {
|
||||||
const isXSmall = useMediaQuery(theme => theme.breakpoints.down("xs"));
|
const isXSmall = useMediaQuery(theme => theme.breakpoints.down("xs"));
|
||||||
|
@ -1,8 +1,7 @@
|
|||||||
import React, { Fragment } from "react";
|
import React, { Fragment } from "react";
|
||||||
import Avatar from "@material-ui/core/Avatar";
|
import { Avatar, Chip } from "@mui/material";
|
||||||
import { Chip } from "@material-ui/core";
|
|
||||||
import { connect } from "react-redux";
|
import { connect } from "react-redux";
|
||||||
import FolderSharedIcon from "@material-ui/icons/FolderShared";
|
import FolderSharedIcon from "@mui/icons-material/FolderShared";
|
||||||
import { makeStyles } from "@material-ui/core/styles";
|
import { makeStyles } from "@material-ui/core/styles";
|
||||||
import {
|
import {
|
||||||
BooleanField,
|
BooleanField,
|
||||||
@ -19,6 +18,7 @@ import {
|
|||||||
useMutation,
|
useMutation,
|
||||||
useNotify,
|
useNotify,
|
||||||
useTranslate,
|
useTranslate,
|
||||||
|
useRecordContext,
|
||||||
useRefresh,
|
useRefresh,
|
||||||
useUnselectAll,
|
useUnselectAll,
|
||||||
} from "react-admin";
|
} from "react-admin";
|
||||||
@ -87,7 +87,9 @@ export const RoomDirectoryBulkSaveButton = ({ selectedIds }) => {
|
|||||||
refresh();
|
refresh();
|
||||||
},
|
},
|
||||||
onFailure: error =>
|
onFailure: error =>
|
||||||
notify("resources.room_directory.action.send_failure", "error"),
|
notify("resources.room_directory.action.send_failure", {
|
||||||
|
type: "error",
|
||||||
|
}),
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
@ -103,7 +105,8 @@ export const RoomDirectoryBulkSaveButton = ({ selectedIds }) => {
|
|||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
export const RoomDirectorySaveButton = ({ record }) => {
|
export const RoomDirectorySaveButton = props => {
|
||||||
|
const record = useRecordContext();
|
||||||
const notify = useNotify();
|
const notify = useNotify();
|
||||||
const refresh = useRefresh();
|
const refresh = useRefresh();
|
||||||
const [create, { loading }] = useCreate("room_directory");
|
const [create, { loading }] = useCreate("room_directory");
|
||||||
@ -119,7 +122,9 @@ export const RoomDirectorySaveButton = ({ record }) => {
|
|||||||
refresh();
|
refresh();
|
||||||
},
|
},
|
||||||
onFailure: error =>
|
onFailure: error =>
|
||||||
notify("resources.room_directory.action.send_failure", "error"),
|
notify("resources.room_directory.action.send_failure", {
|
||||||
|
type: "error",
|
||||||
|
}),
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
@ -177,7 +182,6 @@ export const FilterableRoomDirectoryList = ({
|
|||||||
...props
|
...props
|
||||||
}) => {
|
}) => {
|
||||||
const classes = useStyles();
|
const classes = useStyles();
|
||||||
const translate = useTranslate();
|
|
||||||
const filter = roomDirectoryFilters;
|
const filter = roomDirectoryFilters;
|
||||||
const roomIdFilter = filter && filter.room_id ? true : false;
|
const roomIdFilter = filter && filter.room_id ? true : false;
|
||||||
const topicFilter = filter && filter.topic ? true : false;
|
const topicFilter = filter && filter.topic ? true : false;
|
||||||
@ -196,48 +200,48 @@ export const FilterableRoomDirectoryList = ({
|
|||||||
source="avatar_src"
|
source="avatar_src"
|
||||||
sortable={false}
|
sortable={false}
|
||||||
className={classes.small}
|
className={classes.small}
|
||||||
label={translate("resources.rooms.fields.avatar")}
|
label="resources.rooms.fields.avatar"
|
||||||
/>
|
/>
|
||||||
<TextField
|
<TextField
|
||||||
source="name"
|
source="name"
|
||||||
sortable={false}
|
sortable={false}
|
||||||
label={translate("resources.rooms.fields.name")}
|
label="resources.rooms.fields.name"
|
||||||
/>
|
/>
|
||||||
{roomIdFilter && (
|
{roomIdFilter && (
|
||||||
<TextField
|
<TextField
|
||||||
source="room_id"
|
source="room_id"
|
||||||
sortable={false}
|
sortable={false}
|
||||||
label={translate("resources.rooms.fields.room_id")}
|
label="resources.rooms.fields.room_id"
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
{canonicalAliasFilter && (
|
{canonicalAliasFilter && (
|
||||||
<TextField
|
<TextField
|
||||||
source="canonical_alias"
|
source="canonical_alias"
|
||||||
sortable={false}
|
sortable={false}
|
||||||
label={translate("resources.rooms.fields.canonical_alias")}
|
label="resources.rooms.fields.canonical_alias"
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
{topicFilter && (
|
{topicFilter && (
|
||||||
<TextField
|
<TextField
|
||||||
source="topic"
|
source="topic"
|
||||||
sortable={false}
|
sortable={false}
|
||||||
label={translate("resources.rooms.fields.topic")}
|
label="resources.rooms.fields.topic"
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
<NumberField
|
<NumberField
|
||||||
source="num_joined_members"
|
source="num_joined_members"
|
||||||
sortable={false}
|
sortable={false}
|
||||||
label={translate("resources.rooms.fields.joined_members")}
|
label="resources.rooms.fields.joined_members"
|
||||||
/>
|
/>
|
||||||
<BooleanField
|
<BooleanField
|
||||||
source="world_readable"
|
source="world_readable"
|
||||||
sortable={false}
|
sortable={false}
|
||||||
label={translate("resources.room_directory.fields.world_readable")}
|
label="resources.room_directory.fields.world_readable"
|
||||||
/>
|
/>
|
||||||
<BooleanField
|
<BooleanField
|
||||||
source="guest_can_join"
|
source="guest_can_join"
|
||||||
sortable={false}
|
sortable={false}
|
||||||
label={translate("resources.room_directory.fields.guest_can_join")}
|
label="resources.room_directory.fields.guest_can_join"
|
||||||
/>
|
/>
|
||||||
</Datagrid>
|
</Datagrid>
|
||||||
</List>
|
</List>
|
||||||
|
@ -9,15 +9,18 @@ import {
|
|||||||
useCreate,
|
useCreate,
|
||||||
useMutation,
|
useMutation,
|
||||||
useNotify,
|
useNotify,
|
||||||
|
useRecordContext,
|
||||||
useTranslate,
|
useTranslate,
|
||||||
useUnselectAll,
|
useUnselectAll,
|
||||||
} from "react-admin";
|
} from "react-admin";
|
||||||
import MessageIcon from "@material-ui/icons/Message";
|
import MessageIcon from "@mui/icons-material/Message";
|
||||||
import IconCancel from "@material-ui/icons/Cancel";
|
import IconCancel from "@mui/icons-material/Cancel";
|
||||||
import Dialog from "@material-ui/core/Dialog";
|
import {
|
||||||
import DialogContent from "@material-ui/core/DialogContent";
|
Dialog,
|
||||||
import DialogContentText from "@material-ui/core/DialogContentText";
|
DialogContent,
|
||||||
import DialogTitle from "@material-ui/core/DialogTitle";
|
DialogContentText,
|
||||||
|
DialogTitle,
|
||||||
|
} from "@mui/material";
|
||||||
|
|
||||||
const ServerNoticeDialog = ({ open, loading, onClose, onSend }) => {
|
const ServerNoticeDialog = ({ open, loading, onClose, onSend }) => {
|
||||||
const translate = useTranslate();
|
const translate = useTranslate();
|
||||||
@ -64,7 +67,8 @@ const ServerNoticeDialog = ({ open, loading, onClose, onSend }) => {
|
|||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
export const ServerNoticeButton = ({ record }) => {
|
export const ServerNoticeButton = props => {
|
||||||
|
const record = useRecordContext();
|
||||||
const [open, setOpen] = useState(false);
|
const [open, setOpen] = useState(false);
|
||||||
const notify = useNotify();
|
const notify = useNotify();
|
||||||
const [create, { loading }] = useCreate("servernotices");
|
const [create, { loading }] = useCreate("servernotices");
|
||||||
@ -81,7 +85,9 @@ export const ServerNoticeButton = ({ record }) => {
|
|||||||
handleDialogClose();
|
handleDialogClose();
|
||||||
},
|
},
|
||||||
onFailure: () =>
|
onFailure: () =>
|
||||||
notify("resources.servernotices.action.send_failure", "error"),
|
notify("resources.servernotices.action.send_failure", {
|
||||||
|
type: "error",
|
||||||
|
}),
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
@ -127,7 +133,9 @@ export const ServerNoticeBulkButton = ({ selectedIds }) => {
|
|||||||
handleDialogClose();
|
handleDialogClose();
|
||||||
},
|
},
|
||||||
onFailure: error =>
|
onFailure: error =>
|
||||||
notify("resources.servernotices.action.send_failure", "error"),
|
notify("resources.servernotices.action.send_failure", {
|
||||||
|
type: "error",
|
||||||
|
}),
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
185
src/components/destinations.js
Normal file
185
src/components/destinations.js
Normal file
@ -0,0 +1,185 @@
|
|||||||
|
import React from "react";
|
||||||
|
import {
|
||||||
|
Button,
|
||||||
|
Datagrid,
|
||||||
|
DateField,
|
||||||
|
Filter,
|
||||||
|
List,
|
||||||
|
Pagination,
|
||||||
|
ReferenceField,
|
||||||
|
ReferenceManyField,
|
||||||
|
SearchInput,
|
||||||
|
Show,
|
||||||
|
Tab,
|
||||||
|
TabbedShowLayout,
|
||||||
|
TextField,
|
||||||
|
TopToolbar,
|
||||||
|
useRecordContext,
|
||||||
|
useDelete,
|
||||||
|
useNotify,
|
||||||
|
useRefresh,
|
||||||
|
useTranslate,
|
||||||
|
} from "react-admin";
|
||||||
|
import AutorenewIcon from "@material-ui/icons/Autorenew";
|
||||||
|
import FolderSharedIcon from "@material-ui/icons/FolderShared";
|
||||||
|
import ViewListIcon from "@material-ui/icons/ViewList";
|
||||||
|
|
||||||
|
const DestinationPagination = props => (
|
||||||
|
<Pagination {...props} rowsPerPageOptions={[10, 25, 50, 100, 500, 1000]} />
|
||||||
|
);
|
||||||
|
|
||||||
|
const date_format = {
|
||||||
|
year: "numeric",
|
||||||
|
month: "2-digit",
|
||||||
|
day: "2-digit",
|
||||||
|
hour: "2-digit",
|
||||||
|
minute: "2-digit",
|
||||||
|
second: "2-digit",
|
||||||
|
};
|
||||||
|
|
||||||
|
const destinationRowStyle = (record, index) => ({
|
||||||
|
backgroundColor: record.retry_last_ts > 0 ? "#ffcccc" : "white",
|
||||||
|
});
|
||||||
|
|
||||||
|
const DestinationFilter = ({ ...props }) => {
|
||||||
|
return (
|
||||||
|
<Filter {...props}>
|
||||||
|
<SearchInput source="destination" alwaysOn />
|
||||||
|
</Filter>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export const DestinationReconnectButton = props => {
|
||||||
|
const record = useRecordContext();
|
||||||
|
const refresh = useRefresh();
|
||||||
|
const notify = useNotify();
|
||||||
|
const [handleReconnect, { isLoading }] = useDelete("destinations");
|
||||||
|
|
||||||
|
// Reconnect is not required if no error has occurred. (`failure_ts`)
|
||||||
|
if (!record || !record.failure_ts) return null;
|
||||||
|
|
||||||
|
const handleClick = e => {
|
||||||
|
// Prevents redirection to the detail page when clicking in the list
|
||||||
|
e.stopPropagation();
|
||||||
|
|
||||||
|
handleReconnect(
|
||||||
|
{ payload: { id: record.id } },
|
||||||
|
{
|
||||||
|
onSuccess: () => {
|
||||||
|
notify("ra.notification.updated", {
|
||||||
|
messageArgs: { smart_count: 1 },
|
||||||
|
});
|
||||||
|
refresh();
|
||||||
|
},
|
||||||
|
onFailure: () => {
|
||||||
|
notify("ra.message.error", { type: "error" });
|
||||||
|
},
|
||||||
|
}
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Button
|
||||||
|
label="resources.destinations.action.reconnect"
|
||||||
|
onClick={handleClick}
|
||||||
|
disabled={isLoading}
|
||||||
|
>
|
||||||
|
<AutorenewIcon />
|
||||||
|
</Button>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
const DestinationShowActions = props => (
|
||||||
|
<TopToolbar>
|
||||||
|
<DestinationReconnectButton />
|
||||||
|
</TopToolbar>
|
||||||
|
);
|
||||||
|
|
||||||
|
const DestinationTitle = props => {
|
||||||
|
const record = useRecordContext();
|
||||||
|
const translate = useTranslate();
|
||||||
|
return (
|
||||||
|
<span>
|
||||||
|
{translate("resources.destinations.name", 1)} {record.destination}
|
||||||
|
</span>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export const DestinationList = props => {
|
||||||
|
return (
|
||||||
|
<List
|
||||||
|
{...props}
|
||||||
|
filters={<DestinationFilter />}
|
||||||
|
pagination={<DestinationPagination />}
|
||||||
|
sort={{ field: "destination", order: "ASC" }}
|
||||||
|
bulkActionButtons={false}
|
||||||
|
>
|
||||||
|
<Datagrid
|
||||||
|
rowStyle={destinationRowStyle}
|
||||||
|
rowClick={(id, basePath, record) => `${basePath}/${id}/show/rooms`}
|
||||||
|
>
|
||||||
|
<TextField source="destination" />
|
||||||
|
<DateField source="failure_ts" showTime options={date_format} />
|
||||||
|
<DateField source="retry_last_ts" showTime options={date_format} />
|
||||||
|
<TextField source="retry_interval" />
|
||||||
|
<TextField source="last_successful_stream_ordering" />
|
||||||
|
<DestinationReconnectButton />
|
||||||
|
</Datagrid>
|
||||||
|
</List>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export const DestinationShow = props => {
|
||||||
|
const translate = useTranslate();
|
||||||
|
return (
|
||||||
|
<Show
|
||||||
|
actions={<DestinationShowActions />}
|
||||||
|
title={<DestinationTitle />}
|
||||||
|
{...props}
|
||||||
|
>
|
||||||
|
<TabbedShowLayout>
|
||||||
|
<Tab label="status" icon={<ViewListIcon />}>
|
||||||
|
<TextField source="destination" />
|
||||||
|
<DateField source="failure_ts" showTime options={date_format} />
|
||||||
|
<DateField source="retry_last_ts" showTime options={date_format} />
|
||||||
|
<TextField source="retry_interval" />
|
||||||
|
<TextField source="last_successful_stream_ordering" />
|
||||||
|
</Tab>
|
||||||
|
|
||||||
|
<Tab
|
||||||
|
label={translate("resources.rooms.name", { smart_count: 2 })}
|
||||||
|
icon={<FolderSharedIcon />}
|
||||||
|
path="rooms"
|
||||||
|
>
|
||||||
|
<ReferenceManyField
|
||||||
|
reference="destination_rooms"
|
||||||
|
target="destination"
|
||||||
|
addLabel={false}
|
||||||
|
pagination={<DestinationPagination />}
|
||||||
|
perPage={50}
|
||||||
|
>
|
||||||
|
<Datagrid
|
||||||
|
style={{ width: "100%" }}
|
||||||
|
rowClick={(id, basePath, record) => `/rooms/${id}/show`}
|
||||||
|
>
|
||||||
|
<TextField
|
||||||
|
source="room_id"
|
||||||
|
label="resources.rooms.fields.room_id"
|
||||||
|
/>
|
||||||
|
<TextField source="stream_ordering" sortable={false} />
|
||||||
|
<ReferenceField
|
||||||
|
label="resources.rooms.fields.name"
|
||||||
|
source="id"
|
||||||
|
reference="rooms"
|
||||||
|
sortable={false}
|
||||||
|
link=""
|
||||||
|
>
|
||||||
|
<TextField source="name" sortable={false} />
|
||||||
|
</ReferenceField>
|
||||||
|
</Datagrid>
|
||||||
|
</ReferenceManyField>
|
||||||
|
</Tab>
|
||||||
|
</TabbedShowLayout>
|
||||||
|
</Show>
|
||||||
|
);
|
||||||
|
};
|
@ -1,14 +1,15 @@
|
|||||||
import React, { Fragment, useState } from "react";
|
import React, { Fragment, useState } from "react";
|
||||||
import {
|
import {
|
||||||
Button,
|
Button,
|
||||||
useMutation,
|
useDelete,
|
||||||
useNotify,
|
useNotify,
|
||||||
Confirm,
|
Confirm,
|
||||||
|
useRecordContext,
|
||||||
useRefresh,
|
useRefresh,
|
||||||
} from "react-admin";
|
} from "react-admin";
|
||||||
import ActionDelete from "@material-ui/icons/Delete";
|
import ActionDelete from "@mui/icons-material/Delete";
|
||||||
import { makeStyles } from "@material-ui/core/styles";
|
import { makeStyles } from "@material-ui/core/styles";
|
||||||
import { alpha } from "@material-ui/core/styles/colorManipulator";
|
import { alpha } from "@mui/material/styles";
|
||||||
import classnames from "classnames";
|
import classnames from "classnames";
|
||||||
|
|
||||||
const useStyles = makeStyles(
|
const useStyles = makeStyles(
|
||||||
@ -28,13 +29,13 @@ const useStyles = makeStyles(
|
|||||||
);
|
);
|
||||||
|
|
||||||
export const DeviceRemoveButton = props => {
|
export const DeviceRemoveButton = props => {
|
||||||
const { record } = props;
|
const record = useRecordContext();
|
||||||
const classes = useStyles(props);
|
const classes = useStyles(props);
|
||||||
const [open, setOpen] = useState(false);
|
const [open, setOpen] = useState(false);
|
||||||
const refresh = useRefresh();
|
const refresh = useRefresh();
|
||||||
const notify = useNotify();
|
const notify = useNotify();
|
||||||
|
|
||||||
const [removeDevice, { loading }] = useMutation();
|
const [removeDevice, { isLoading }] = useDelete("devices");
|
||||||
|
|
||||||
if (!record) return null;
|
if (!record) return null;
|
||||||
|
|
||||||
@ -43,21 +44,15 @@ export const DeviceRemoveButton = props => {
|
|||||||
|
|
||||||
const handleConfirm = () => {
|
const handleConfirm = () => {
|
||||||
removeDevice(
|
removeDevice(
|
||||||
{
|
{ payload: { id: record.id, user_id: record.user_id } },
|
||||||
type: "delete",
|
|
||||||
resource: "devices",
|
|
||||||
payload: {
|
|
||||||
id: record.id,
|
|
||||||
user_id: record.user_id,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
onSuccess: () => {
|
onSuccess: () => {
|
||||||
notify("resources.devices.action.erase.success");
|
notify("resources.devices.action.erase.success");
|
||||||
refresh();
|
refresh();
|
||||||
},
|
},
|
||||||
onFailure: () =>
|
onFailure: () => {
|
||||||
notify("resources.devices.action.erase.failure", "error"),
|
notify("resources.devices.action.erase.failure", { type: "error" });
|
||||||
|
},
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
setOpen(false);
|
setOpen(false);
|
||||||
@ -74,7 +69,7 @@ export const DeviceRemoveButton = props => {
|
|||||||
</Button>
|
</Button>
|
||||||
<Confirm
|
<Confirm
|
||||||
isOpen={open}
|
isOpen={open}
|
||||||
loading={loading}
|
loading={isLoading}
|
||||||
onConfirm={handleConfirm}
|
onConfirm={handleConfirm}
|
||||||
onClose={handleDialogClose}
|
onClose={handleDialogClose}
|
||||||
title="resources.devices.action.erase.title"
|
title="resources.devices.action.erase.title"
|
||||||
|
@ -1,8 +1,7 @@
|
|||||||
import React, { Fragment, useState } from "react";
|
import React, { Fragment, useState } from "react";
|
||||||
import classnames from "classnames";
|
import classnames from "classnames";
|
||||||
import { alpha } from "@material-ui/core/styles/colorManipulator";
|
import { alpha } from "@mui/material/styles";
|
||||||
import { makeStyles } from "@material-ui/core/styles";
|
import { makeStyles } from "@material-ui/core/styles";
|
||||||
import { Tooltip } from "@material-ui/core";
|
|
||||||
import {
|
import {
|
||||||
BooleanInput,
|
BooleanInput,
|
||||||
Button,
|
Button,
|
||||||
@ -14,19 +13,23 @@ import {
|
|||||||
useCreate,
|
useCreate,
|
||||||
useDelete,
|
useDelete,
|
||||||
useNotify,
|
useNotify,
|
||||||
|
useRecordContext,
|
||||||
useRefresh,
|
useRefresh,
|
||||||
useTranslate,
|
useTranslate,
|
||||||
} from "react-admin";
|
} from "react-admin";
|
||||||
import BlockIcon from "@material-ui/icons/Block";
|
import BlockIcon from "@mui/icons-material/Block";
|
||||||
import ClearIcon from "@material-ui/icons/Clear";
|
import ClearIcon from "@mui/icons-material/Clear";
|
||||||
import DeleteSweepIcon from "@material-ui/icons/DeleteSweep";
|
import DeleteSweepIcon from "@mui/icons-material/DeleteSweep";
|
||||||
import Dialog from "@material-ui/core/Dialog";
|
import {
|
||||||
import DialogContent from "@material-ui/core/DialogContent";
|
Dialog,
|
||||||
import DialogContentText from "@material-ui/core/DialogContentText";
|
DialogContent,
|
||||||
import DialogTitle from "@material-ui/core/DialogTitle";
|
DialogContentText,
|
||||||
import IconCancel from "@material-ui/icons/Cancel";
|
DialogTitle,
|
||||||
import LockIcon from "@material-ui/icons/Lock";
|
Tooltip,
|
||||||
import LockOpenIcon from "@material-ui/icons/LockOpen";
|
} from "@mui/material";
|
||||||
|
import IconCancel from "@mui/icons-material/Cancel";
|
||||||
|
import LockIcon from "@mui/icons-material/Lock";
|
||||||
|
import LockOpenIcon from "@mui/icons-material/LockOpen";
|
||||||
|
|
||||||
const useStyles = makeStyles(
|
const useStyles = makeStyles(
|
||||||
theme => ({
|
theme => ({
|
||||||
@ -127,7 +130,9 @@ export const DeleteMediaButton = props => {
|
|||||||
handleDialogClose();
|
handleDialogClose();
|
||||||
},
|
},
|
||||||
onFailure: () =>
|
onFailure: () =>
|
||||||
notify("resources.delete_media.action.send_failure", "error"),
|
notify("resources.delete_media.action.send_failure", {
|
||||||
|
type: "error",
|
||||||
|
}),
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
@ -152,7 +157,7 @@ export const DeleteMediaButton = props => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
export const ProtectMediaButton = props => {
|
export const ProtectMediaButton = props => {
|
||||||
const { record } = props;
|
const record = useRecordContext();
|
||||||
const translate = useTranslate();
|
const translate = useTranslate();
|
||||||
const refresh = useRefresh();
|
const refresh = useRefresh();
|
||||||
const notify = useNotify();
|
const notify = useNotify();
|
||||||
@ -170,7 +175,9 @@ export const ProtectMediaButton = props => {
|
|||||||
refresh();
|
refresh();
|
||||||
},
|
},
|
||||||
onFailure: () =>
|
onFailure: () =>
|
||||||
notify("resources.protect_media.action.send_failure", "error"),
|
notify("resources.protect_media.action.send_failure", {
|
||||||
|
type: "error",
|
||||||
|
}),
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
@ -184,7 +191,9 @@ export const ProtectMediaButton = props => {
|
|||||||
refresh();
|
refresh();
|
||||||
},
|
},
|
||||||
onFailure: () =>
|
onFailure: () =>
|
||||||
notify("resources.protect_media.action.send_failure", "error"),
|
notify("resources.protect_media.action.send_failure", {
|
||||||
|
type: "error",
|
||||||
|
}),
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
@ -244,7 +253,7 @@ export const ProtectMediaButton = props => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
export const QuarantineMediaButton = props => {
|
export const QuarantineMediaButton = props => {
|
||||||
const { record } = props;
|
const record = useRecordContext();
|
||||||
const translate = useTranslate();
|
const translate = useTranslate();
|
||||||
const refresh = useRefresh();
|
const refresh = useRefresh();
|
||||||
const notify = useNotify();
|
const notify = useNotify();
|
||||||
@ -262,7 +271,9 @@ export const QuarantineMediaButton = props => {
|
|||||||
refresh();
|
refresh();
|
||||||
},
|
},
|
||||||
onFailure: () =>
|
onFailure: () =>
|
||||||
notify("resources.quarantine_media.action.send_failure", "error"),
|
notify("resources.quarantine_media.action.send_failure", {
|
||||||
|
type: "error",
|
||||||
|
}),
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
@ -276,7 +287,9 @@ export const QuarantineMediaButton = props => {
|
|||||||
refresh();
|
refresh();
|
||||||
},
|
},
|
||||||
onFailure: () =>
|
onFailure: () =>
|
||||||
notify("resources.quarantine_media.action.send_failure", "error"),
|
notify("resources.quarantine_media.action.send_failure", {
|
||||||
|
type: "error",
|
||||||
|
}),
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
@ -25,15 +25,15 @@ import {
|
|||||||
import get from "lodash/get";
|
import get from "lodash/get";
|
||||||
import PropTypes from "prop-types";
|
import PropTypes from "prop-types";
|
||||||
import { makeStyles } from "@material-ui/core/styles";
|
import { makeStyles } from "@material-ui/core/styles";
|
||||||
import { Tooltip, Typography, Chip } from "@material-ui/core";
|
import { Tooltip, Typography, Chip } from "@mui/material";
|
||||||
import FastForwardIcon from "@material-ui/icons/FastForward";
|
import FastForwardIcon from "@mui/icons-material/FastForward";
|
||||||
import HttpsIcon from "@material-ui/icons/Https";
|
import HttpsIcon from "@mui/icons-material/Https";
|
||||||
import NoEncryptionIcon from "@material-ui/icons/NoEncryption";
|
import NoEncryptionIcon from "@mui/icons-material/NoEncryption";
|
||||||
import PageviewIcon from "@material-ui/icons/Pageview";
|
import PageviewIcon from "@mui/icons-material/Pageview";
|
||||||
import UserIcon from "@material-ui/icons/Group";
|
import UserIcon from "@mui/icons-material/Group";
|
||||||
import ViewListIcon from "@material-ui/icons/ViewList";
|
import ViewListIcon from "@mui/icons-material/ViewList";
|
||||||
import VisibilityIcon from "@material-ui/icons/Visibility";
|
import VisibilityIcon from "@mui/icons-material/Visibility";
|
||||||
import EventIcon from "@material-ui/icons/Event";
|
import EventIcon from "@mui/icons-material/Event";
|
||||||
import {
|
import {
|
||||||
RoomDirectoryBulkDeleteButton,
|
RoomDirectoryBulkDeleteButton,
|
||||||
RoomDirectoryBulkSaveButton,
|
RoomDirectoryBulkSaveButton,
|
||||||
@ -87,7 +87,8 @@ const EncryptionField = ({ source, record = {}, emptyText }) => {
|
|||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
const RoomTitle = ({ record }) => {
|
const RoomTitle = props => {
|
||||||
|
const record = useRecordContext();
|
||||||
const translate = useTranslate();
|
const translate = useTranslate();
|
||||||
var name = "";
|
var name = "";
|
||||||
if (record) {
|
if (record) {
|
||||||
@ -354,7 +355,7 @@ const RoomFilter = ({ ...props }) => {
|
|||||||
|
|
||||||
const RoomNameField = props => {
|
const RoomNameField = props => {
|
||||||
const { source } = props;
|
const { source } = props;
|
||||||
const record = useRecordContext(props);
|
const record = useRecordContext();
|
||||||
return (
|
return (
|
||||||
<span>{record[source] || record["canonical_alias"] || record["id"]}</span>
|
<span>{record[source] || record["canonical_alias"] || record["id"]}</span>
|
||||||
);
|
);
|
||||||
|
@ -1,14 +1,14 @@
|
|||||||
import React, { cloneElement, Fragment } from "react";
|
import React, { cloneElement, Fragment } from "react";
|
||||||
import Avatar from "@material-ui/core/Avatar";
|
import Avatar from "@mui/material/Avatar";
|
||||||
import AssignmentIndIcon from "@material-ui/icons/AssignmentInd";
|
import AssignmentIndIcon from "@mui/icons-material/AssignmentInd";
|
||||||
import ContactMailIcon from "@material-ui/icons/ContactMail";
|
import ContactMailIcon from "@mui/icons-material/ContactMail";
|
||||||
import DevicesIcon from "@material-ui/icons/Devices";
|
import DevicesIcon from "@mui/icons-material/Devices";
|
||||||
import GetAppIcon from "@material-ui/icons/GetApp";
|
import GetAppIcon from "@mui/icons-material/GetApp";
|
||||||
import NotificationsIcon from "@material-ui/icons/Notifications";
|
import NotificationsIcon from "@mui/icons-material/Notifications";
|
||||||
import PermMediaIcon from "@material-ui/icons/PermMedia";
|
import PermMediaIcon from "@mui/icons-material/PermMedia";
|
||||||
import PersonPinIcon from "@material-ui/icons/PersonPin";
|
import PersonPinIcon from "@mui/icons-material/PersonPin";
|
||||||
import SettingsInputComponentIcon from "@material-ui/icons/SettingsInputComponent";
|
import SettingsInputComponentIcon from "@mui/icons-material/SettingsInputComponent";
|
||||||
import ViewListIcon from "@material-ui/icons/ViewList";
|
import ViewListIcon from "@mui/icons-material/ViewList";
|
||||||
import {
|
import {
|
||||||
ArrayInput,
|
ArrayInput,
|
||||||
ArrayField,
|
ArrayField,
|
||||||
@ -39,6 +39,7 @@ import {
|
|||||||
maxLength,
|
maxLength,
|
||||||
regex,
|
regex,
|
||||||
required,
|
required,
|
||||||
|
useRecordContext,
|
||||||
useTranslate,
|
useTranslate,
|
||||||
Pagination,
|
Pagination,
|
||||||
CreateButton,
|
CreateButton,
|
||||||
@ -71,6 +72,16 @@ const useStyles = makeStyles({
|
|||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
|
const choices_medium = [
|
||||||
|
{ id: "email", name: "resources.users.email" },
|
||||||
|
{ id: "msisdn", name: "resources.users.msisdn" },
|
||||||
|
];
|
||||||
|
|
||||||
|
const choices_type = [
|
||||||
|
{ id: "bot", name: "bot" },
|
||||||
|
{ id: "support", name: "support" },
|
||||||
|
];
|
||||||
|
|
||||||
const date_format = {
|
const date_format = {
|
||||||
year: "numeric",
|
year: "numeric",
|
||||||
month: "2-digit",
|
month: "2-digit",
|
||||||
@ -249,20 +260,31 @@ export function generateRandomUser() {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
const UserEditToolbar = props => {
|
const UserEditToolbar = props => (
|
||||||
|
<Toolbar {...props}>
|
||||||
|
<SaveButton submitOnEnter={true} disabled={props.pristine} />
|
||||||
|
</Toolbar>
|
||||||
|
);
|
||||||
|
|
||||||
|
const UserEditActions = ({ data }) => {
|
||||||
const translate = useTranslate();
|
const translate = useTranslate();
|
||||||
|
var userStatus = "";
|
||||||
|
if (data) {
|
||||||
|
userStatus = data.deactivated;
|
||||||
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Toolbar {...props}>
|
<TopToolbar>
|
||||||
<SaveButton submitOnEnter={true} disabled={props.pristine} />
|
{!userStatus && <ServerNoticeButton record={data} />}
|
||||||
<DeleteButton
|
<DeleteButton
|
||||||
|
record={data}
|
||||||
label="resources.users.action.erase"
|
label="resources.users.action.erase"
|
||||||
confirmTitle={translate("resources.users.helper.erase", {
|
confirmTitle={translate("resources.users.helper.erase", {
|
||||||
smart_count: 1,
|
smart_count: 1,
|
||||||
})}
|
})}
|
||||||
mutationMode="pessimistic"
|
mutationMode="pessimistic"
|
||||||
/>
|
/>
|
||||||
<ServerNoticeButton />
|
</TopToolbar>
|
||||||
</Toolbar>
|
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -276,15 +298,19 @@ export const UserCreate = props => (
|
|||||||
autoComplete="new-password"
|
autoComplete="new-password"
|
||||||
validate={maxLength(512)}
|
validate={maxLength(512)}
|
||||||
/>
|
/>
|
||||||
|
<SelectInput
|
||||||
|
source="user_type"
|
||||||
|
choices={choices_type}
|
||||||
|
translateChoice={false}
|
||||||
|
allowEmpty={true}
|
||||||
|
resettable
|
||||||
|
/>
|
||||||
<BooleanInput source="admin" />
|
<BooleanInput source="admin" />
|
||||||
<ArrayInput source="threepids">
|
<ArrayInput source="threepids">
|
||||||
<SimpleFormIterator disableReordering>
|
<SimpleFormIterator disableReordering>
|
||||||
<SelectInput
|
<SelectInput
|
||||||
source="medium"
|
source="medium"
|
||||||
choices={[
|
choices={choices_medium}
|
||||||
{ id: "email", name: "resources.users.email" },
|
|
||||||
{ id: "msisdn", name: "resources.users.msisdn" },
|
|
||||||
]}
|
|
||||||
validate={required()}
|
validate={required()}
|
||||||
/>
|
/>
|
||||||
<TextInput source="address" validate={validateAddress} />
|
<TextInput source="address" validate={validateAddress} />
|
||||||
@ -304,7 +330,8 @@ export const UserCreate = props => (
|
|||||||
</Create>
|
</Create>
|
||||||
);
|
);
|
||||||
|
|
||||||
const UserTitle = ({ record }) => {
|
const UserTitle = props => {
|
||||||
|
const record = useRecordContext();
|
||||||
const translate = useTranslate();
|
const translate = useTranslate();
|
||||||
return (
|
return (
|
||||||
<span>
|
<span>
|
||||||
@ -315,11 +342,12 @@ const UserTitle = ({ record }) => {
|
|||||||
</span>
|
</span>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
export const UserEdit = props => {
|
export const UserEdit = props => {
|
||||||
const classes = useStyles();
|
const classes = useStyles();
|
||||||
const translate = useTranslate();
|
const translate = useTranslate();
|
||||||
return (
|
return (
|
||||||
<Edit {...props} title={<UserTitle />}>
|
<Edit {...props} title={<UserTitle />} actions={<UserEditActions />}>
|
||||||
<TabbedForm toolbar={<UserEditToolbar />}>
|
<TabbedForm toolbar={<UserEditToolbar />}>
|
||||||
<FormTab
|
<FormTab
|
||||||
label={translate("resources.users.name", { smart_count: 1 })}
|
label={translate("resources.users.name", { smart_count: 1 })}
|
||||||
@ -332,7 +360,18 @@ export const UserEdit = props => {
|
|||||||
/>
|
/>
|
||||||
<TextInput source="id" disabled />
|
<TextInput source="id" disabled />
|
||||||
<TextInput source="displayname" />
|
<TextInput source="displayname" />
|
||||||
<PasswordInput source="password" autoComplete="new-password" />
|
<PasswordInput
|
||||||
|
source="password"
|
||||||
|
autoComplete="new-password"
|
||||||
|
helperText="resources.users.helper.password"
|
||||||
|
/>
|
||||||
|
<SelectInput
|
||||||
|
source="user_type"
|
||||||
|
choices={choices_type}
|
||||||
|
translateChoice={false}
|
||||||
|
allowEmpty={true}
|
||||||
|
resettable
|
||||||
|
/>
|
||||||
<BooleanInput source="admin" />
|
<BooleanInput source="admin" />
|
||||||
<BooleanInput
|
<BooleanInput
|
||||||
source="deactivated"
|
source="deactivated"
|
||||||
@ -349,13 +388,7 @@ export const UserEdit = props => {
|
|||||||
>
|
>
|
||||||
<ArrayInput source="threepids">
|
<ArrayInput source="threepids">
|
||||||
<SimpleFormIterator disableReordering>
|
<SimpleFormIterator disableReordering>
|
||||||
<SelectInput
|
<SelectInput source="medium" choices={choices_medium} />
|
||||||
source="medium"
|
|
||||||
choices={[
|
|
||||||
{ id: "email", name: "resources.users.email" },
|
|
||||||
{ id: "msisdn", name: "resources.users.msisdn" },
|
|
||||||
]}
|
|
||||||
/>
|
|
||||||
<TextInput source="address" />
|
<TextInput source="address" />
|
||||||
</SimpleFormIterator>
|
</SimpleFormIterator>
|
||||||
</ArrayInput>
|
</ArrayInput>
|
||||||
|
@ -121,8 +121,11 @@ const de = {
|
|||||||
creation_ts_ms: "Zeitpunkt der Erstellung",
|
creation_ts_ms: "Zeitpunkt der Erstellung",
|
||||||
consent_version: "Zugestimmte Geschäftsbedingungen",
|
consent_version: "Zugestimmte Geschäftsbedingungen",
|
||||||
auth_provider: "Provider",
|
auth_provider: "Provider",
|
||||||
|
user_type: "Benutzertyp",
|
||||||
},
|
},
|
||||||
helper: {
|
helper: {
|
||||||
|
password:
|
||||||
|
"Durch die Änderung des Passworts wird der Benutzer von allen Sitzungen abgemeldet.",
|
||||||
deactivate:
|
deactivate:
|
||||||
"Sie müssen ein Passwort angeben, um ein Konto wieder zu aktivieren.",
|
"Sie müssen ein Passwort angeben, um ein Konto wieder zu aktivieren.",
|
||||||
erase: "DSGVO konformes Löschen der Benutzerdaten",
|
erase: "DSGVO konformes Löschen der Benutzerdaten",
|
||||||
@ -352,6 +355,18 @@ const de = {
|
|||||||
send_failure: "Beim Entfernen ist ein Fehler aufgetreten.",
|
send_failure: "Beim Entfernen ist ein Fehler aufgetreten.",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
destinations: {
|
||||||
|
name: "Föderation",
|
||||||
|
fields: {
|
||||||
|
destination: "Ziel",
|
||||||
|
failure_ts: "Fehlerzeitpunkt",
|
||||||
|
retry_last_ts: "Letzter Wiederholungsversuch",
|
||||||
|
retry_interval: "Wiederholungsintervall",
|
||||||
|
last_successful_stream_ordering: "letzte erfogreicher Stream",
|
||||||
|
stream_ordering: "Stream",
|
||||||
|
},
|
||||||
|
action: { reconnect: "Neu verbinden" },
|
||||||
|
},
|
||||||
registration_tokens: {
|
registration_tokens: {
|
||||||
name: "Registrierungstoken",
|
name: "Registrierungstoken",
|
||||||
fields: {
|
fields: {
|
||||||
|
@ -120,8 +120,10 @@ const en = {
|
|||||||
creation_ts_ms: "Creation timestamp",
|
creation_ts_ms: "Creation timestamp",
|
||||||
consent_version: "Consent version",
|
consent_version: "Consent version",
|
||||||
auth_provider: "Provider",
|
auth_provider: "Provider",
|
||||||
|
user_type: "User type",
|
||||||
},
|
},
|
||||||
helper: {
|
helper: {
|
||||||
|
password: "Changing password will log user out of all sessions.",
|
||||||
deactivate: "You must provide a password to re-activate an account.",
|
deactivate: "You must provide a password to re-activate an account.",
|
||||||
erase: "Mark the user as GDPR-erased",
|
erase: "Mark the user as GDPR-erased",
|
||||||
},
|
},
|
||||||
@ -350,6 +352,18 @@ const en = {
|
|||||||
send_failure: "An error has occurred.",
|
send_failure: "An error has occurred.",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
destinations: {
|
||||||
|
name: "Federation",
|
||||||
|
fields: {
|
||||||
|
destination: "Destination",
|
||||||
|
failure_ts: "Failure timestamp",
|
||||||
|
retry_last_ts: "Last retry timestamp",
|
||||||
|
retry_interval: "Retry interval",
|
||||||
|
last_successful_stream_ordering: "Last successful stream",
|
||||||
|
stream_ordering: "Stream",
|
||||||
|
},
|
||||||
|
action: { reconnect: "Reconnect" },
|
||||||
|
},
|
||||||
},
|
},
|
||||||
registration_tokens: {
|
registration_tokens: {
|
||||||
name: "Registration tokens",
|
name: "Registration tokens",
|
||||||
|
@ -41,14 +41,16 @@ const resourceMap = {
|
|||||||
data: "users",
|
data: "users",
|
||||||
total: json => json.total,
|
total: json => json.total,
|
||||||
create: data => ({
|
create: data => ({
|
||||||
endpoint: `/_synapse/admin/v2/users/@${data.id}:${localStorage.getItem(
|
endpoint: `/_synapse/admin/v2/users/@${encodeURIComponent(
|
||||||
"home_server"
|
data.id
|
||||||
)}`,
|
)}:${localStorage.getItem("home_server")}`,
|
||||||
body: data,
|
body: data,
|
||||||
method: "PUT",
|
method: "PUT",
|
||||||
}),
|
}),
|
||||||
delete: params => ({
|
delete: params => ({
|
||||||
endpoint: `/_synapse/admin/v1/deactivate/${params.id}`,
|
endpoint: `/_synapse/admin/v1/deactivate/${encodeURIComponent(
|
||||||
|
params.id
|
||||||
|
)}`,
|
||||||
body: { erase: true },
|
body: { erase: true },
|
||||||
method: "POST",
|
method: "POST",
|
||||||
}),
|
}),
|
||||||
@ -69,7 +71,7 @@ const resourceMap = {
|
|||||||
return json.total_rooms;
|
return json.total_rooms;
|
||||||
},
|
},
|
||||||
delete: params => ({
|
delete: params => ({
|
||||||
endpoint: `/_synapse/admin/v1/rooms/${params.id}`,
|
endpoint: `/_synapse/admin/v2/rooms/${params.id}`,
|
||||||
body: { block: false },
|
body: { block: false },
|
||||||
}),
|
}),
|
||||||
},
|
},
|
||||||
@ -92,10 +94,12 @@ const resourceMap = {
|
|||||||
return json.total;
|
return json.total;
|
||||||
},
|
},
|
||||||
reference: id => ({
|
reference: id => ({
|
||||||
endpoint: `/_synapse/admin/v2/users/${id}/devices`,
|
endpoint: `/_synapse/admin/v2/users/${encodeURIComponent(id)}/devices`,
|
||||||
}),
|
}),
|
||||||
delete: params => ({
|
delete: params => ({
|
||||||
endpoint: `/_synapse/admin/v2/users/${params.user_id}/devices/${params.id}`,
|
endpoint: `/_synapse/admin/v2/users/${encodeURIComponent(
|
||||||
|
params.user_id
|
||||||
|
)}/devices/${params.id}`,
|
||||||
}),
|
}),
|
||||||
},
|
},
|
||||||
connections: {
|
connections: {
|
||||||
@ -137,7 +141,7 @@ const resourceMap = {
|
|||||||
id: p.pushkey,
|
id: p.pushkey,
|
||||||
}),
|
}),
|
||||||
reference: id => ({
|
reference: id => ({
|
||||||
endpoint: `/_synapse/admin/v1/users/${id}/pushers`,
|
endpoint: `/_synapse/admin/v1/users/${encodeURIComponent(id)}/pushers`,
|
||||||
}),
|
}),
|
||||||
data: "pushers",
|
data: "pushers",
|
||||||
total: json => {
|
total: json => {
|
||||||
@ -149,7 +153,9 @@ const resourceMap = {
|
|||||||
id: jr,
|
id: jr,
|
||||||
}),
|
}),
|
||||||
reference: id => ({
|
reference: id => ({
|
||||||
endpoint: `/_synapse/admin/v1/users/${id}/joined_rooms`,
|
endpoint: `/_synapse/admin/v1/users/${encodeURIComponent(
|
||||||
|
id
|
||||||
|
)}/joined_rooms`,
|
||||||
}),
|
}),
|
||||||
data: "joined_rooms",
|
data: "joined_rooms",
|
||||||
total: json => {
|
total: json => {
|
||||||
@ -162,7 +168,7 @@ const resourceMap = {
|
|||||||
id: um.media_id,
|
id: um.media_id,
|
||||||
}),
|
}),
|
||||||
reference: id => ({
|
reference: id => ({
|
||||||
endpoint: `/_synapse/admin/v1/users/${id}/media`,
|
endpoint: `/_synapse/admin/v1/users/${encodeURIComponent(id)}/media`,
|
||||||
}),
|
}),
|
||||||
data: "media",
|
data: "media",
|
||||||
total: json => {
|
total: json => {
|
||||||
@ -275,6 +281,34 @@ const resourceMap = {
|
|||||||
method: "PUT",
|
method: "PUT",
|
||||||
}),
|
}),
|
||||||
},
|
},
|
||||||
|
destinations: {
|
||||||
|
path: "/_synapse/admin/v1/federation/destinations",
|
||||||
|
map: dst => ({
|
||||||
|
...dst,
|
||||||
|
id: dst.destination,
|
||||||
|
}),
|
||||||
|
data: "destinations",
|
||||||
|
total: json => {
|
||||||
|
return json.total;
|
||||||
|
},
|
||||||
|
delete: params => ({
|
||||||
|
endpoint: `/_synapse/admin/v1/federation/destinations/${params.id}/reset_connection`,
|
||||||
|
method: "POST",
|
||||||
|
}),
|
||||||
|
},
|
||||||
|
destination_rooms: {
|
||||||
|
map: dstroom => ({
|
||||||
|
...dstroom,
|
||||||
|
id: dstroom.room_id,
|
||||||
|
}),
|
||||||
|
reference: id => ({
|
||||||
|
endpoint: `/_synapse/admin/v1/federation/destinations/${id}/rooms`,
|
||||||
|
}),
|
||||||
|
data: "rooms",
|
||||||
|
total: json => {
|
||||||
|
return json.total;
|
||||||
|
},
|
||||||
|
},
|
||||||
registration_tokens: {
|
registration_tokens: {
|
||||||
path: "/_synapse/admin/v1/registration_tokens",
|
path: "/_synapse/admin/v1/registration_tokens",
|
||||||
map: rt => ({
|
map: rt => ({
|
||||||
@ -298,7 +332,8 @@ const resourceMap = {
|
|||||||
|
|
||||||
function filterNullValues(key, value) {
|
function filterNullValues(key, value) {
|
||||||
// Filtering out null properties
|
// Filtering out null properties
|
||||||
if (value === null) {
|
// to reset user_type from user, it must be null
|
||||||
|
if (value === null && key !== "user_type") {
|
||||||
return undefined;
|
return undefined;
|
||||||
}
|
}
|
||||||
return value;
|
return value;
|
||||||
@ -315,8 +350,15 @@ function getSearchOrder(order) {
|
|||||||
const dataProvider = {
|
const dataProvider = {
|
||||||
getList: (resource, params) => {
|
getList: (resource, params) => {
|
||||||
console.log("getList " + resource);
|
console.log("getList " + resource);
|
||||||
const { user_id, name, guests, deactivated, search_term, valid } =
|
const {
|
||||||
params.filter;
|
user_id,
|
||||||
|
name,
|
||||||
|
guests,
|
||||||
|
deactivated,
|
||||||
|
search_term,
|
||||||
|
destination,
|
||||||
|
valid,
|
||||||
|
} = params.filter;
|
||||||
const { page, perPage } = params.pagination;
|
const { page, perPage } = params.pagination;
|
||||||
const { field, order } = params.sort;
|
const { field, order } = params.sort;
|
||||||
const from = (page - 1) * perPage;
|
const from = (page - 1) * perPage;
|
||||||
@ -326,6 +368,7 @@ const dataProvider = {
|
|||||||
user_id: user_id,
|
user_id: user_id,
|
||||||
search_term: search_term,
|
search_term: search_term,
|
||||||
name: name,
|
name: name,
|
||||||
|
destination: destination,
|
||||||
guests: guests,
|
guests: guests,
|
||||||
deactivated: deactivated,
|
deactivated: deactivated,
|
||||||
valid: valid,
|
valid: valid,
|
||||||
@ -354,9 +397,11 @@ const dataProvider = {
|
|||||||
const res = resourceMap[resource];
|
const res = resourceMap[resource];
|
||||||
|
|
||||||
const endpoint_url = homeserver + res.path;
|
const endpoint_url = homeserver + res.path;
|
||||||
return jsonClient(`${endpoint_url}/${params.id}`).then(({ json }) => ({
|
return jsonClient(`${endpoint_url}/${encodeURIComponent(params.id)}`).then(
|
||||||
data: res.map(json),
|
({ json }) => ({
|
||||||
}));
|
data: res.map(json),
|
||||||
|
})
|
||||||
|
);
|
||||||
},
|
},
|
||||||
|
|
||||||
getMany: (resource, params) => {
|
getMany: (resource, params) => {
|
||||||
@ -368,7 +413,9 @@ const dataProvider = {
|
|||||||
|
|
||||||
const endpoint_url = homeserver + res.path;
|
const endpoint_url = homeserver + res.path;
|
||||||
return Promise.all(
|
return Promise.all(
|
||||||
params.ids.map(id => jsonClient(`${endpoint_url}/${id}`))
|
params.ids.map(id =>
|
||||||
|
jsonClient(`${endpoint_url}/${encodeURIComponent(id)}`)
|
||||||
|
)
|
||||||
).then(responses => ({
|
).then(responses => ({
|
||||||
data: responses.map(({ json }) => res.map(json)),
|
data: responses.map(({ json }) => res.map(json)),
|
||||||
total: responses.length,
|
total: responses.length,
|
||||||
@ -409,7 +456,7 @@ const dataProvider = {
|
|||||||
const res = resourceMap[resource];
|
const res = resourceMap[resource];
|
||||||
|
|
||||||
const endpoint_url = homeserver + res.path;
|
const endpoint_url = homeserver + res.path;
|
||||||
return jsonClient(`${endpoint_url}/${params.data.id}`, {
|
return jsonClient(`${endpoint_url}/${encodeURIComponent(params.data.id)}`, {
|
||||||
method: "PUT",
|
method: "PUT",
|
||||||
body: JSON.stringify(params.data, filterNullValues),
|
body: JSON.stringify(params.data, filterNullValues),
|
||||||
}).then(({ json }) => ({
|
}).then(({ json }) => ({
|
||||||
@ -426,10 +473,13 @@ const dataProvider = {
|
|||||||
|
|
||||||
const endpoint_url = homeserver + res.path;
|
const endpoint_url = homeserver + res.path;
|
||||||
return Promise.all(
|
return Promise.all(
|
||||||
params.ids.map(id => jsonClient(`${endpoint_url}/${id}`), {
|
params.ids.map(
|
||||||
method: "PUT",
|
id => jsonClient(`${endpoint_url}/${encodeURIComponent(id)}`),
|
||||||
body: JSON.stringify(params.data, filterNullValues),
|
{
|
||||||
})
|
method: "PUT",
|
||||||
|
body: JSON.stringify(params.data, filterNullValues),
|
||||||
|
}
|
||||||
|
)
|
||||||
).then(responses => ({
|
).then(responses => ({
|
||||||
data: responses.map(({ json }) => json),
|
data: responses.map(({ json }) => json),
|
||||||
}));
|
}));
|
||||||
|
Loading…
Reference in New Issue
Block a user