forked from abner/for-legacy-web
parent
4aad0493ae
commit
eee1d4060f
|
|
@ -7,6 +7,9 @@ dist-ssr
|
||||||
*.log
|
*.log
|
||||||
/.idea
|
/.idea
|
||||||
|
|
||||||
|
.yarn/cache
|
||||||
|
.yarn/install-state.gz
|
||||||
|
|
||||||
public/assets
|
public/assets
|
||||||
public/assets_*
|
public/assets_*
|
||||||
!public/assets_default
|
!public/assets_default
|
||||||
|
|
|
||||||
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
|
|
@ -0,0 +1,9 @@
|
||||||
|
nodeLinker: node-modules
|
||||||
|
|
||||||
|
plugins:
|
||||||
|
- path: .yarn/plugins/@yarnpkg/plugin-interactive-tools.cjs
|
||||||
|
spec: "@yarnpkg/plugin-interactive-tools"
|
||||||
|
- path: .yarn/plugins/@yarnpkg/plugin-typescript.cjs
|
||||||
|
spec: "@yarnpkg/plugin-typescript"
|
||||||
|
|
||||||
|
yarnPath: .yarn/releases/yarn-3.2.0.cjs
|
||||||
|
|
@ -1 +1 @@
|
||||||
Subproject commit c7fd514d4d83561e1802ae722501192d316cfe50
|
Subproject commit 1c8fd46b5005691f2a144151b4406d3f839a7822
|
||||||
17
package.json
17
package.json
|
|
@ -61,7 +61,6 @@
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@fontsource/bitter": "^4.5.0",
|
"@fontsource/bitter": "^4.5.0",
|
||||||
"@insertish/vite-plugin-babel-macros": "^1.0.5",
|
"@insertish/vite-plugin-babel-macros": "^1.0.5",
|
||||||
"color-rgba": "^2.3.0",
|
|
||||||
"fs-extra": "^10.0.0",
|
"fs-extra": "^10.0.0",
|
||||||
"klaw": "^3.0.0",
|
"klaw": "^3.0.0",
|
||||||
"react-beautiful-dnd": "^13.1.0",
|
"react-beautiful-dnd": "^13.1.0",
|
||||||
|
|
@ -90,16 +89,16 @@
|
||||||
"@fontsource/ubuntu-mono": "^4.4.5",
|
"@fontsource/ubuntu-mono": "^4.4.5",
|
||||||
"@hcaptcha/react-hcaptcha": "^0.3.6",
|
"@hcaptcha/react-hcaptcha": "^0.3.6",
|
||||||
"@preact/preset-vite": "^2.0.0",
|
"@preact/preset-vite": "^2.0.0",
|
||||||
|
"@revoltchat/ui": "1.0.27",
|
||||||
"@rollup/plugin-replace": "^2.4.2",
|
"@rollup/plugin-replace": "^2.4.2",
|
||||||
"@styled-icons/boxicons-logos": "^10.34.0",
|
"@styled-icons/boxicons-logos": "^10.38.0",
|
||||||
"@styled-icons/boxicons-regular": "^10.34.0",
|
"@styled-icons/boxicons-regular": "^10.38.0",
|
||||||
"@styled-icons/boxicons-solid": "^10.37.0",
|
"@styled-icons/boxicons-solid": "^10.38.0",
|
||||||
"@styled-icons/simple-icons": "^10.33.0",
|
"@styled-icons/simple-icons": "^10.33.0",
|
||||||
"@tippyjs/react": "^4.2.5",
|
"@tippyjs/react": "^4.2.5",
|
||||||
"@traptitech/markdown-it-katex": "^3.4.3",
|
"@traptitech/markdown-it-katex": "^3.4.3",
|
||||||
"@traptitech/markdown-it-spoiler": "^1.1.6",
|
"@traptitech/markdown-it-spoiler": "^1.1.6",
|
||||||
"@trivago/prettier-plugin-sort-imports": "^2.0.2",
|
"@trivago/prettier-plugin-sort-imports": "^2.0.2",
|
||||||
"@types/color-rgba": "^2.1.0",
|
|
||||||
"@types/lodash.defaultsdeep": "^4.6.6",
|
"@types/lodash.defaultsdeep": "^4.6.6",
|
||||||
"@types/lodash.isequal": "^4.5.5",
|
"@types/lodash.isequal": "^4.5.5",
|
||||||
"@types/markdown-it": "^12.0.2",
|
"@types/markdown-it": "^12.0.2",
|
||||||
|
|
@ -116,6 +115,7 @@
|
||||||
"@typescript-eslint/eslint-plugin": "^4.27.0",
|
"@typescript-eslint/eslint-plugin": "^4.27.0",
|
||||||
"@typescript-eslint/parser": "^4.27.0",
|
"@typescript-eslint/parser": "^4.27.0",
|
||||||
"classnames": "^2.3.1",
|
"classnames": "^2.3.1",
|
||||||
|
"color-rgba": "^2.4.0",
|
||||||
"dayjs": "^1.10.6",
|
"dayjs": "^1.10.6",
|
||||||
"detect-browser": "^5.2.0",
|
"detect-browser": "^5.2.0",
|
||||||
"eslint": "^7.28.0",
|
"eslint": "^7.28.0",
|
||||||
|
|
@ -133,7 +133,7 @@
|
||||||
"markdown-it-sup": "^1.0.0",
|
"markdown-it-sup": "^1.0.0",
|
||||||
"mediasoup-client": "npm:@insertish/mediasoup-client@3.6.36-esnext",
|
"mediasoup-client": "npm:@insertish/mediasoup-client@3.6.36-esnext",
|
||||||
"mobx": "^6.3.2",
|
"mobx": "^6.3.2",
|
||||||
"mobx-react-lite": "^3.2.0",
|
"mobx-react-lite": "^3.3.0",
|
||||||
"preact": "^10.5.14",
|
"preact": "^10.5.14",
|
||||||
"preact-context-menu": "^0.2.1",
|
"preact-context-menu": "^0.2.1",
|
||||||
"preact-i18n": "^2.4.0-preactx",
|
"preact-i18n": "^2.4.0-preactx",
|
||||||
|
|
@ -147,7 +147,7 @@
|
||||||
"react-scroll": "^1.8.2",
|
"react-scroll": "^1.8.2",
|
||||||
"react-virtualized-auto-sizer": "^1.0.5",
|
"react-virtualized-auto-sizer": "^1.0.5",
|
||||||
"react-virtuoso": "^1.10.4",
|
"react-virtuoso": "^1.10.4",
|
||||||
"revolt.js": "6.0.0-rc.13",
|
"revolt.js": "6.0.0-rc.15",
|
||||||
"rimraf": "^3.0.2",
|
"rimraf": "^3.0.2",
|
||||||
"sass": "^1.35.1",
|
"sass": "^1.35.1",
|
||||||
"shade-blend-color": "^1.0.0",
|
"shade-blend-color": "^1.0.0",
|
||||||
|
|
@ -163,5 +163,6 @@
|
||||||
"main": "index.js",
|
"main": "index.js",
|
||||||
"repository": "https://github.com/revoltchat/revite.git",
|
"repository": "https://github.com/revoltchat/revite.git",
|
||||||
"author": "Paul <paulmakles@gmail.com>",
|
"author": "Paul <paulmakles@gmail.com>",
|
||||||
"license": "MIT"
|
"license": "MIT",
|
||||||
|
"packageManager": "yarn@3.2.0"
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
import { API } from "revolt.js";
|
import { API } from "revolt.js";
|
||||||
import { Nullable } from "revolt.js/dist/util/null";
|
import { Nullable } from "revolt.js/esm/util/null";
|
||||||
import styled, { css } from "styled-components/macro";
|
import styled, { css } from "styled-components/macro";
|
||||||
|
|
||||||
export interface IconBaseProps<T> {
|
export interface IconBaseProps<T> {
|
||||||
|
|
|
||||||
|
|
@ -1,79 +0,0 @@
|
||||||
import { Check, Square, X } from "@styled-icons/boxicons-regular";
|
|
||||||
import styled, { css } from "styled-components";
|
|
||||||
|
|
||||||
type State = "Allow" | "Neutral" | "Deny";
|
|
||||||
|
|
||||||
const SwitchContainer = styled.div.attrs({
|
|
||||||
role: "radiogroup",
|
|
||||||
"aria-orientiation": "horizontal",
|
|
||||||
})`
|
|
||||||
flex-shrink: 0;
|
|
||||||
|
|
||||||
display: flex;
|
|
||||||
margin: 4px 16px;
|
|
||||||
overflow: hidden;
|
|
||||||
border-radius: var(--border-radius);
|
|
||||||
background: var(--secondary-background);
|
|
||||||
border: 2px solid var(--tertiary-background);
|
|
||||||
`;
|
|
||||||
|
|
||||||
const Switch = styled.div.attrs({
|
|
||||||
role: "radio",
|
|
||||||
})<{ state: State; selected: boolean }>`
|
|
||||||
padding: 4px;
|
|
||||||
cursor: pointer;
|
|
||||||
transition: 0.2s ease all;
|
|
||||||
|
|
||||||
color: ${(props) =>
|
|
||||||
props.state === "Allow"
|
|
||||||
? "var(--success)"
|
|
||||||
: props.state === "Deny"
|
|
||||||
? "var(--error)"
|
|
||||||
: "var(--tertiary-foreground)"};
|
|
||||||
|
|
||||||
${(props) =>
|
|
||||||
props.selected &&
|
|
||||||
css`
|
|
||||||
color: white;
|
|
||||||
|
|
||||||
background: ${props.state === "Allow"
|
|
||||||
? "var(--success)"
|
|
||||||
: props.state === "Deny"
|
|
||||||
? "var(--error)"
|
|
||||||
: "var(--primary-background)"};
|
|
||||||
`}
|
|
||||||
|
|
||||||
&:hover {
|
|
||||||
filter: brightness(0.8);
|
|
||||||
}
|
|
||||||
`;
|
|
||||||
|
|
||||||
interface Props {
|
|
||||||
state: State;
|
|
||||||
onChange: (state: State) => void;
|
|
||||||
}
|
|
||||||
|
|
||||||
export function OverrideSwitch({ state, onChange }: Props) {
|
|
||||||
return (
|
|
||||||
<SwitchContainer>
|
|
||||||
<Switch
|
|
||||||
onClick={() => onChange("Deny")}
|
|
||||||
state="Deny"
|
|
||||||
selected={state === "Deny"}>
|
|
||||||
<X size={24} />
|
|
||||||
</Switch>
|
|
||||||
<Switch
|
|
||||||
onClick={() => onChange("Neutral")}
|
|
||||||
state="Neutral"
|
|
||||||
selected={state === "Neutral"}>
|
|
||||||
<Square size={24} />
|
|
||||||
</Switch>
|
|
||||||
<Switch
|
|
||||||
onClick={() => onChange("Allow")}
|
|
||||||
state="Allow"
|
|
||||||
selected={state === "Allow"}>
|
|
||||||
<Check size={24} />
|
|
||||||
</Switch>
|
|
||||||
</SwitchContainer>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
@ -16,7 +16,16 @@ export function PermissionList({ value, onChange, filter }: Props) {
|
||||||
{(Object.keys(Permission) as (keyof typeof Permission)[])
|
{(Object.keys(Permission) as (keyof typeof Permission)[])
|
||||||
.filter(
|
.filter(
|
||||||
(key) =>
|
(key) =>
|
||||||
key !== "GrantAllSafe" &&
|
![
|
||||||
|
"GrantAllSafe",
|
||||||
|
"TimeoutMembers",
|
||||||
|
"ReadMessageHistory",
|
||||||
|
"Speak",
|
||||||
|
"Video",
|
||||||
|
"MuteMembers",
|
||||||
|
"DeafenMembers",
|
||||||
|
"MoveMembers",
|
||||||
|
].includes(key) &&
|
||||||
(!filter || filter.includes(key)),
|
(!filter || filter.includes(key)),
|
||||||
)
|
)
|
||||||
.map((x) => (
|
.map((x) => (
|
||||||
|
|
|
||||||
|
|
@ -7,8 +7,7 @@ import { Text } from "preact-i18n";
|
||||||
import { useMemo } from "preact/hooks";
|
import { useMemo } from "preact/hooks";
|
||||||
|
|
||||||
import Checkbox from "../../ui/Checkbox";
|
import Checkbox from "../../ui/Checkbox";
|
||||||
|
import { OverrideSwitch } from "@revoltchat/ui";
|
||||||
import { OverrideSwitch } from "./OverrideSwitch";
|
|
||||||
|
|
||||||
interface PermissionSelectProps {
|
interface PermissionSelectProps {
|
||||||
id: keyof typeof Permission;
|
id: keyof typeof Permission;
|
||||||
|
|
@ -20,6 +19,7 @@ interface PermissionSelectProps {
|
||||||
type State = "Allow" | "Neutral" | "Deny";
|
type State = "Allow" | "Neutral" | "Deny";
|
||||||
|
|
||||||
const PermissionEntry = styled.label`
|
const PermissionEntry = styled.label`
|
||||||
|
gap: 8px;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
margin: 8px 0;
|
margin: 8px 0;
|
||||||
display: flex;
|
display: flex;
|
||||||
|
|
@ -100,9 +100,9 @@ export function PermissionSelect({
|
||||||
return (
|
return (
|
||||||
<PermissionEntry>
|
<PermissionEntry>
|
||||||
<span class="title">
|
<span class="title">
|
||||||
<Text id={`permissions.server.${id}.t`}>{id}</Text>
|
<Text id={`permissions.${id}.t`}>{id}</Text>
|
||||||
<span class="description">
|
<span class="description">
|
||||||
<Text id={`permissions.server.${id}.d`} />
|
<Text id={`permissions.${id}.d`} />
|
||||||
</span>
|
</span>
|
||||||
</span>
|
</span>
|
||||||
{typeof value === "object" ? (
|
{typeof value === "object" ? (
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,12 @@
|
||||||
|
import { API } from "revolt.js";
|
||||||
|
|
||||||
|
export type RoleOrDefault = (
|
||||||
|
| API.Role
|
||||||
|
| {
|
||||||
|
name: string;
|
||||||
|
permissions: number;
|
||||||
|
colour?: string;
|
||||||
|
hoist?: boolean;
|
||||||
|
rank?: number;
|
||||||
|
}
|
||||||
|
) & { id: string };
|
||||||
|
|
@ -1,35 +0,0 @@
|
||||||
import { API } from "revolt.js";
|
|
||||||
|
|
||||||
import Checkbox from "../../ui/Checkbox";
|
|
||||||
|
|
||||||
export type RoleOrDefault = (
|
|
||||||
| API.Role
|
|
||||||
| {
|
|
||||||
name: string;
|
|
||||||
permissions: number;
|
|
||||||
colour?: string;
|
|
||||||
hoist?: boolean;
|
|
||||||
rank?: number;
|
|
||||||
}
|
|
||||||
) & { id: string };
|
|
||||||
|
|
||||||
interface Props {
|
|
||||||
selected: string;
|
|
||||||
onSelect: (id: string) => void;
|
|
||||||
|
|
||||||
roles: RoleOrDefault[];
|
|
||||||
}
|
|
||||||
|
|
||||||
export function RoleSelection({ selected, onSelect, roles }: Props) {
|
|
||||||
return (
|
|
||||||
<>
|
|
||||||
{roles.map((x) => (
|
|
||||||
<Checkbox
|
|
||||||
checked={x.id === selected}
|
|
||||||
onChange={() => onSelect(x.id)}>
|
|
||||||
{x.name}
|
|
||||||
</Checkbox>
|
|
||||||
))}
|
|
||||||
</>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
@ -1,22 +0,0 @@
|
||||||
import Tip from "../../../components/ui/Tip";
|
|
||||||
import Button from "../../ui/Button";
|
|
||||||
|
|
||||||
interface Props {
|
|
||||||
save: () => void;
|
|
||||||
}
|
|
||||||
|
|
||||||
export function UnsavedChanges({ save }: Props) {
|
|
||||||
return (
|
|
||||||
<Tip hideSeparator>
|
|
||||||
<span
|
|
||||||
style={{
|
|
||||||
display: "flex",
|
|
||||||
alignItems: "center",
|
|
||||||
gap: "8px",
|
|
||||||
}}>
|
|
||||||
You have unsaved changes!
|
|
||||||
<Button onClick={save}>Save</Button>
|
|
||||||
</span>
|
|
||||||
</Tip>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
@ -1,7 +1,7 @@
|
||||||
/**
|
/**
|
||||||
* This file monitors changes to settings and syncs them to the server.
|
* This file monitors changes to settings and syncs them to the server.
|
||||||
*/
|
*/
|
||||||
import { ClientboundNotification } from "revolt.js/dist/websocket/notifications";
|
import { ClientboundNotification } from "revolt.js/esm/websocket/notifications";
|
||||||
|
|
||||||
import { useEffect } from "preact/hooks";
|
import { useEffect } from "preact/hooks";
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -13,7 +13,7 @@ import {
|
||||||
import { Cog, UserVoice } from "@styled-icons/boxicons-solid";
|
import { Cog, UserVoice } from "@styled-icons/boxicons-solid";
|
||||||
import { useHistory } from "react-router-dom";
|
import { useHistory } from "react-router-dom";
|
||||||
import { Channel, Message, Server, User, API } from "revolt.js";
|
import { Channel, Message, Server, User, API } from "revolt.js";
|
||||||
import { Permission, UserPermission } from "revolt.js/dist/api/permissions";
|
import { Permission, UserPermission } from "revolt.js/esm/api/permissions";
|
||||||
|
|
||||||
import {
|
import {
|
||||||
ContextMenuWithData,
|
ContextMenuWithData,
|
||||||
|
|
|
||||||
|
|
@ -9,8 +9,8 @@ import {
|
||||||
LeftArrowAlt,
|
LeftArrowAlt,
|
||||||
} from "@styled-icons/boxicons-regular";
|
} from "@styled-icons/boxicons-regular";
|
||||||
import { observer } from "mobx-react-lite";
|
import { observer } from "mobx-react-lite";
|
||||||
import { Channel } from "revolt.js/dist/maps/Channels";
|
import { Channel } from "revolt.js/esm/maps/Channels";
|
||||||
import { Server } from "revolt.js/dist/maps/Servers";
|
import { Server } from "revolt.js/esm/maps/Servers";
|
||||||
|
|
||||||
import { ContextMenuWithData, MenuItem } from "preact-context-menu";
|
import { ContextMenuWithData, MenuItem } from "preact-context-menu";
|
||||||
import { Text } from "preact-i18n";
|
import { Text } from "preact-i18n";
|
||||||
|
|
|
||||||
|
|
@ -1,8 +1,8 @@
|
||||||
/* eslint-disable react-hooks/rules-of-hooks */
|
/* eslint-disable react-hooks/rules-of-hooks */
|
||||||
import { action, makeAutoObservable } from "mobx";
|
import { action, makeAutoObservable } from "mobx";
|
||||||
import { Channel } from "revolt.js/dist/maps/Channels";
|
import { Channel } from "revolt.js/esm/maps/Channels";
|
||||||
import { Message } from "revolt.js/dist/maps/Messages";
|
import { Message } from "revolt.js/esm/maps/Messages";
|
||||||
import { Nullable } from "revolt.js/dist/util/null";
|
import { Nullable } from "revolt.js/esm/util/null";
|
||||||
|
|
||||||
import { SimpleRenderer } from "./simple/SimpleRenderer";
|
import { SimpleRenderer } from "./simple/SimpleRenderer";
|
||||||
import { RendererRoutines, ScrollState } from "./types";
|
import { RendererRoutines, ScrollState } from "./types";
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
import { Message } from "revolt.js/dist/maps/Messages";
|
import { Message } from "revolt.js/esm/maps/Messages";
|
||||||
|
|
||||||
import { ChannelRenderer } from "./Singleton";
|
import { ChannelRenderer } from "./Singleton";
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
import { action, makeAutoObservable, runInAction } from "mobx";
|
import { action, makeAutoObservable, runInAction } from "mobx";
|
||||||
import { Channel } from "revolt.js/dist/maps/Channels";
|
import { Channel } from "revolt.js/esm/maps/Channels";
|
||||||
import { Nullable, toNullable } from "revolt.js/dist/util/null";
|
import { Nullable, toNullable } from "revolt.js/esm/util/null";
|
||||||
|
|
||||||
import type { ProduceType, VoiceUser } from "./Types";
|
import type { ProduceType, VoiceUser } from "./Types";
|
||||||
import type VoiceClient from "./VoiceClient";
|
import type VoiceClient from "./VoiceClient";
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
import { action, computed, makeAutoObservable, ObservableMap } from "mobx";
|
import { action, computed, makeAutoObservable, ObservableMap } from "mobx";
|
||||||
import { API } from "revolt.js";
|
import { API } from "revolt.js";
|
||||||
import { Nullable } from "revolt.js/dist/util/null";
|
import { Nullable } from "revolt.js/esm/util/null";
|
||||||
|
|
||||||
import { mapToRecord } from "../../lib/conversion";
|
import { mapToRecord } from "../../lib/conversion";
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,7 @@
|
||||||
import { action, computed, makeAutoObservable, ObservableMap } from "mobx";
|
import { action, computed, makeAutoObservable, ObservableMap } from "mobx";
|
||||||
import { Channel } from "revolt.js/dist/maps/Channels";
|
import { Channel } from "revolt.js/esm/maps/Channels";
|
||||||
import { Message } from "revolt.js/dist/maps/Messages";
|
import { Message } from "revolt.js/esm/maps/Messages";
|
||||||
import { Server } from "revolt.js/dist/maps/Servers";
|
import { Server } from "revolt.js/esm/maps/Servers";
|
||||||
|
|
||||||
import { mapToRecord } from "../../lib/conversion";
|
import { mapToRecord } from "../../lib/conversion";
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,7 @@
|
||||||
import { action, computed, makeAutoObservable } from "mobx";
|
import { action, computed, makeAutoObservable } from "mobx";
|
||||||
import { API } from "revolt.js";
|
import { API } from "revolt.js";
|
||||||
import { Client } from "revolt.js";
|
import { Client } from "revolt.js";
|
||||||
import { Nullable } from "revolt.js/dist/util/null";
|
import { Nullable } from "revolt.js/esm/util/null";
|
||||||
|
|
||||||
import { isDebug } from "../../revision";
|
import { isDebug } from "../../revision";
|
||||||
import Persistent from "../interfaces/Persistent";
|
import Persistent from "../interfaces/Persistent";
|
||||||
|
|
|
||||||
|
|
@ -3,7 +3,7 @@ import { Ghost } from "@styled-icons/boxicons-solid";
|
||||||
import { reaction } from "mobx";
|
import { reaction } from "mobx";
|
||||||
import { observer } from "mobx-react-lite";
|
import { observer } from "mobx-react-lite";
|
||||||
import { Redirect, useParams } from "react-router-dom";
|
import { Redirect, useParams } from "react-router-dom";
|
||||||
import { Channel as ChannelI } from "revolt.js/dist/maps/Channels";
|
import { Channel as ChannelI } from "revolt.js/esm/maps/Channels";
|
||||||
import styled from "styled-components/macro";
|
import styled from "styled-components/macro";
|
||||||
|
|
||||||
import { Text } from "preact-i18n";
|
import { Text } from "preact-i18n";
|
||||||
|
|
|
||||||
|
|
@ -6,8 +6,8 @@ import {
|
||||||
} from "@styled-icons/boxicons-regular";
|
} from "@styled-icons/boxicons-regular";
|
||||||
import { Notepad, Group } from "@styled-icons/boxicons-solid";
|
import { Notepad, Group } from "@styled-icons/boxicons-solid";
|
||||||
import { observer } from "mobx-react-lite";
|
import { observer } from "mobx-react-lite";
|
||||||
import { Channel } from "revolt.js/dist/maps/Channels";
|
import { Channel } from "revolt.js/esm/maps/Channels";
|
||||||
import { User } from "revolt.js/dist/maps/Users";
|
import { User } from "revolt.js/esm/maps/Users";
|
||||||
import styled, { css } from "styled-components/macro";
|
import styled, { css } from "styled-components/macro";
|
||||||
|
|
||||||
import { isTouchscreenDevice } from "../../lib/isTouchscreenDevice";
|
import { isTouchscreenDevice } from "../../lib/isTouchscreenDevice";
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
import { observer } from "mobx-react-lite";
|
import { observer } from "mobx-react-lite";
|
||||||
import { Channel } from "revolt.js/dist/maps/Channels";
|
import { Channel } from "revolt.js/esm/maps/Channels";
|
||||||
import styled from "styled-components/macro";
|
import styled from "styled-components/macro";
|
||||||
|
|
||||||
import { Text } from "preact-i18n";
|
import { Text } from "preact-i18n";
|
||||||
|
|
|
||||||
|
|
@ -2,7 +2,7 @@ import { runInAction } from "mobx";
|
||||||
import { observer } from "mobx-react-lite";
|
import { observer } from "mobx-react-lite";
|
||||||
import { useHistory, useParams } from "react-router-dom";
|
import { useHistory, useParams } from "react-router-dom";
|
||||||
import { animateScroll } from "react-scroll";
|
import { animateScroll } from "react-scroll";
|
||||||
import { Channel } from "revolt.js/dist/maps/Channels";
|
import { Channel } from "revolt.js/esm/maps/Channels";
|
||||||
import styled from "styled-components/macro";
|
import styled from "styled-components/macro";
|
||||||
import useResizeObserver from "use-resize-observer";
|
import useResizeObserver from "use-resize-observer";
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
import { Message } from "revolt.js/dist/maps/Messages";
|
import { Message } from "revolt.js/esm/maps/Messages";
|
||||||
import styled from "styled-components/macro";
|
import styled from "styled-components/macro";
|
||||||
|
|
||||||
import { useContext, useEffect, useState } from "preact/hooks";
|
import { useContext, useEffect, useState } from "preact/hooks";
|
||||||
|
|
|
||||||
|
|
@ -3,8 +3,8 @@ import { X } from "@styled-icons/boxicons-regular";
|
||||||
import isEqual from "lodash.isequal";
|
import isEqual from "lodash.isequal";
|
||||||
import { observer } from "mobx-react-lite";
|
import { observer } from "mobx-react-lite";
|
||||||
import { API } from "revolt.js";
|
import { API } from "revolt.js";
|
||||||
import { Message as MessageI } from "revolt.js/dist/maps/Messages";
|
import { Message as MessageI } from "revolt.js/esm/maps/Messages";
|
||||||
import { Nullable } from "revolt.js/dist/util/null";
|
import { Nullable } from "revolt.js/esm/util/null";
|
||||||
import styled from "styled-components/macro";
|
import styled from "styled-components/macro";
|
||||||
import { decodeTime } from "ulid";
|
import { decodeTime } from "ulid";
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -2,7 +2,7 @@ import { X, Plus } from "@styled-icons/boxicons-regular";
|
||||||
import { PhoneCall, Envelope, UserX } from "@styled-icons/boxicons-solid";
|
import { PhoneCall, Envelope, UserX } from "@styled-icons/boxicons-solid";
|
||||||
import { observer } from "mobx-react-lite";
|
import { observer } from "mobx-react-lite";
|
||||||
import { useHistory } from "react-router-dom";
|
import { useHistory } from "react-router-dom";
|
||||||
import { User } from "revolt.js/dist/maps/Users";
|
import { User } from "revolt.js/esm/maps/Users";
|
||||||
|
|
||||||
import styles from "./Friend.module.scss";
|
import styles from "./Friend.module.scss";
|
||||||
import classNames from "classnames";
|
import classNames from "classnames";
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,7 @@
|
||||||
import { ChevronRight } from "@styled-icons/boxicons-regular";
|
import { ChevronRight } from "@styled-icons/boxicons-regular";
|
||||||
import { UserDetail, MessageAdd, UserPlus } from "@styled-icons/boxicons-solid";
|
import { UserDetail, MessageAdd, UserPlus } from "@styled-icons/boxicons-solid";
|
||||||
import { observer } from "mobx-react-lite";
|
import { observer } from "mobx-react-lite";
|
||||||
import { User } from "revolt.js/dist/maps/Users";
|
import { User } from "revolt.js/esm/maps/Users";
|
||||||
|
|
||||||
import styles from "./Friend.module.scss";
|
import styles from "./Friend.module.scss";
|
||||||
import classNames from "classnames";
|
import classNames from "classnames";
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
import { observer } from "mobx-react-lite";
|
import { observer } from "mobx-react-lite";
|
||||||
import { Channel } from "revolt.js/dist/maps/Channels";
|
import { Channel } from "revolt.js/esm/maps/Channels";
|
||||||
import styled from "styled-components/macro";
|
import styled from "styled-components/macro";
|
||||||
|
|
||||||
import { Text } from "preact-i18n";
|
import { Text } from "preact-i18n";
|
||||||
|
|
|
||||||
|
|
@ -1,15 +1,14 @@
|
||||||
import isEqual from "lodash.isequal";
|
import isEqual from "lodash.isequal";
|
||||||
import { observer } from "mobx-react-lite";
|
import { observer } from "mobx-react-lite";
|
||||||
import { Channel, API } from "revolt.js";
|
import { Channel, API } from "revolt.js";
|
||||||
|
import { DEFAULT_PERMISSION_DIRECT_MESSAGE } from "revolt.js/esm/api/permissions";
|
||||||
|
|
||||||
import { useLayoutEffect, useState } from "preact/hooks";
|
import { useState } from "preact/hooks";
|
||||||
|
|
||||||
|
import { PermissionsLayout, Button, SpaceBetween, H1 } from "@revoltchat/ui";
|
||||||
|
|
||||||
import { PermissionList } from "../../../components/settings/roles/PermissionList";
|
import { PermissionList } from "../../../components/settings/roles/PermissionList";
|
||||||
import {
|
import { RoleOrDefault } from "../../../components/settings/roles/RoleSelection";
|
||||||
RoleOrDefault,
|
|
||||||
RoleSelection,
|
|
||||||
} from "../../../components/settings/roles/RoleSelection";
|
|
||||||
import { UnsavedChanges } from "../../../components/settings/roles/UnsavedChanges";
|
|
||||||
import { useRoles } from "../server/Roles";
|
import { useRoles } from "../server/Roles";
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
|
|
@ -24,10 +23,12 @@ export default observer(({ channel }: Props) => {
|
||||||
{
|
{
|
||||||
id: "default",
|
id: "default",
|
||||||
name: "Default",
|
name: "Default",
|
||||||
permissions: channel.permissions,
|
permissions:
|
||||||
|
channel.permissions ??
|
||||||
|
DEFAULT_PERMISSION_DIRECT_MESSAGE,
|
||||||
},
|
},
|
||||||
] as RoleOrDefault[])
|
] as RoleOrDefault[])
|
||||||
: (useRoles(channel.server!).map((role) => {
|
: (useRoles(channel.server! as any).map((role) => {
|
||||||
return {
|
return {
|
||||||
...role,
|
...role,
|
||||||
permissions: (role.id === "default"
|
permissions: (role.id === "default"
|
||||||
|
|
@ -39,154 +40,72 @@ export default observer(({ channel }: Props) => {
|
||||||
};
|
};
|
||||||
}) as RoleOrDefault[]);
|
}) as RoleOrDefault[]);
|
||||||
|
|
||||||
// Keep track of whatever role we're editing right now.
|
|
||||||
const [selected, setSelected] = useState("default");
|
|
||||||
const [value, setValue] = useState<API.OverrideField | number | undefined>(
|
|
||||||
undefined,
|
|
||||||
);
|
|
||||||
const currentPermission = currentRoles.find(
|
|
||||||
(x) => x.id === selected,
|
|
||||||
)!.permissions;
|
|
||||||
const currentValue = value ?? currentPermission;
|
|
||||||
|
|
||||||
// If a role gets deleted, unselect it immediately.
|
|
||||||
useLayoutEffect(() => {
|
|
||||||
if (!channel?.server?.roles) return;
|
|
||||||
if (!channel.server.roles[selected]) {
|
|
||||||
setSelected("default");
|
|
||||||
}
|
|
||||||
}, [channel.server?.roles]);
|
|
||||||
|
|
||||||
// Upload new role information to server.
|
|
||||||
function save() {
|
|
||||||
channel.setPermissions(
|
|
||||||
selected,
|
|
||||||
typeof currentValue === "number"
|
|
||||||
? currentValue
|
|
||||||
: ({
|
|
||||||
allow: currentValue.a,
|
|
||||||
deny: currentValue.d,
|
|
||||||
} as any),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div style={{ height: "100%", overflowY: "scroll" }}>
|
<PermissionsLayout
|
||||||
<h1>Select Role</h1>
|
channel={channel}
|
||||||
<RoleSelection
|
editor={({ selected }) => {
|
||||||
selected={selected}
|
const currentRole = currentRoles.find(
|
||||||
onSelect={(id) => {
|
(x) => x.id === selected,
|
||||||
setValue(undefined);
|
)!;
|
||||||
setSelected(id);
|
|
||||||
}}
|
|
||||||
roles={currentRoles}
|
|
||||||
/>
|
|
||||||
{!isEqual(currentPermission, currentValue) && (
|
|
||||||
<>
|
|
||||||
<hr />
|
|
||||||
<UnsavedChanges save={save} />
|
|
||||||
</>
|
|
||||||
)}
|
|
||||||
<hr />
|
|
||||||
<h1>Edit Permissions</h1>
|
|
||||||
<PermissionList
|
|
||||||
value={currentValue}
|
|
||||||
onChange={setValue}
|
|
||||||
filter={[
|
|
||||||
"ViewChannel",
|
|
||||||
"ReadMessageHistory",
|
|
||||||
"SendMessage",
|
|
||||||
"ManageMessages",
|
|
||||||
"ManageWebhooks",
|
|
||||||
"InviteOthers",
|
|
||||||
"SendEmbeds",
|
|
||||||
"UploadFiles",
|
|
||||||
"Masquerade",
|
|
||||||
]}
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
|
|
||||||
/*const [selected, setSelected] = useState("default");
|
if (!currentRole) return null;
|
||||||
|
|
||||||
type R = { name: string; permissions: number };
|
// Keep track of whatever role we're editing right now.
|
||||||
const roles: { [key: string]: R } = {};
|
const [value, setValue] = useState<
|
||||||
if (channel.channel_type !== "Group") {
|
API.OverrideField | number | undefined
|
||||||
const server = channel.server;
|
>(undefined);
|
||||||
const a = server?.roles ?? {};
|
const currentPermission = currentRoles.find(
|
||||||
for (const b of Object.keys(a)) {
|
(x) => x.id === selected,
|
||||||
roles[b] = {
|
)!.permissions;
|
||||||
name: a[b].name,
|
const currentValue = value ?? currentPermission;
|
||||||
permissions:
|
|
||||||
channel.role_permissions?.[b] ?? a[b].permissions[1],
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const keys = ["default", ...Object.keys(roles)];
|
// Upload new role information to server.
|
||||||
|
function save() {
|
||||||
const defaultRole = {
|
channel.setPermissions(
|
||||||
name: "Default",
|
selected,
|
||||||
permissions:
|
typeof currentValue === "number"
|
||||||
(channel.channel_type === "Group"
|
? currentValue
|
||||||
? channel.permissions
|
: ({
|
||||||
: channel.default_permissions) ?? DEFAULT_PERMISSION_DM,
|
allow: currentValue.a,
|
||||||
};
|
deny: currentValue.d,
|
||||||
const selectedRole = selected === "default" ? defaultRole : roles[selected];
|
} as any),
|
||||||
|
|
||||||
if (!selectedRole) {
|
|
||||||
useEffect(() => setSelected("default"), []);
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
const [p, setPerm] = useState(selectedRole.permissions >>> 0);
|
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
setPerm(selectedRole.permissions >>> 0);
|
|
||||||
}, [selected, selectedRole.permissions]);
|
|
||||||
|
|
||||||
return (
|
|
||||||
<div>
|
|
||||||
<Tip warning>This section is under construction.</Tip>
|
|
||||||
<h2>select role</h2>
|
|
||||||
{selected}
|
|
||||||
{keys.map((id) => {
|
|
||||||
const role: R = id === "default" ? defaultRole : roles[id];
|
|
||||||
|
|
||||||
return (
|
|
||||||
<Checkbox
|
|
||||||
key={id}
|
|
||||||
checked={selected === id}
|
|
||||||
onChange={(selected) => selected && setSelected(id)}>
|
|
||||||
{role.name}
|
|
||||||
</Checkbox>
|
|
||||||
);
|
|
||||||
})}
|
|
||||||
<h2>channel permissions</h2>
|
|
||||||
{Object.keys(ChannelPermission).map((perm) => {
|
|
||||||
if (perm === "View") return null;
|
|
||||||
|
|
||||||
const value =
|
|
||||||
ChannelPermission[perm as keyof typeof ChannelPermission];
|
|
||||||
if (value & DEFAULT_PERMISSION_DM) {
|
|
||||||
return (
|
|
||||||
<Checkbox
|
|
||||||
checked={(p & value) > 0}
|
|
||||||
onChange={(c) =>
|
|
||||||
setPerm(c ? p | value : p ^ value)
|
|
||||||
}>
|
|
||||||
{perm}
|
|
||||||
</Checkbox>
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
})}
|
|
||||||
<Button
|
return (
|
||||||
contrast
|
<div>
|
||||||
onClick={() => {
|
<SpaceBetween>
|
||||||
channel.setPermissions(selected, p);
|
<H1>Permissions for {currentRole.name}</H1>
|
||||||
}}>
|
<Button
|
||||||
click here to save permissions for role
|
palette="secondary"
|
||||||
</Button>
|
disabled={isEqual(
|
||||||
</div>
|
currentPermission,
|
||||||
);*/
|
currentValue,
|
||||||
|
)}
|
||||||
|
onClick={save}>
|
||||||
|
Save
|
||||||
|
</Button>
|
||||||
|
</SpaceBetween>
|
||||||
|
<PermissionList
|
||||||
|
value={currentValue}
|
||||||
|
onChange={setValue}
|
||||||
|
filter={[
|
||||||
|
...(channel.channel_type === "Group"
|
||||||
|
? []
|
||||||
|
: ["ViewChannel" as "ViewChannel"]),
|
||||||
|
"ReadMessageHistory",
|
||||||
|
"SendMessage",
|
||||||
|
"ManageMessages",
|
||||||
|
"ManageWebhooks",
|
||||||
|
"InviteOthers",
|
||||||
|
"SendEmbeds",
|
||||||
|
"UploadFiles",
|
||||||
|
"Masquerade",
|
||||||
|
]}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
);
|
||||||
});
|
});
|
||||||
|
|
|
||||||
|
|
@ -4,7 +4,7 @@ import { LockAlt, HelpCircle } from "@styled-icons/boxicons-solid";
|
||||||
import type { AxiosError } from "axios";
|
import type { AxiosError } from "axios";
|
||||||
import { observer } from "mobx-react-lite";
|
import { observer } from "mobx-react-lite";
|
||||||
import { API } from "revolt.js";
|
import { API } from "revolt.js";
|
||||||
import { User } from "revolt.js/dist/maps/Users";
|
import { User } from "revolt.js/esm/maps/Users";
|
||||||
import styled from "styled-components/macro";
|
import styled from "styled-components/macro";
|
||||||
|
|
||||||
import styles from "./Panes.module.scss";
|
import styles from "./Panes.module.scss";
|
||||||
|
|
|
||||||
|
|
@ -2,7 +2,7 @@ import { XCircle } from "@styled-icons/boxicons-regular";
|
||||||
import { observer } from "mobx-react-lite";
|
import { observer } from "mobx-react-lite";
|
||||||
import { Virtuoso } from "react-virtuoso";
|
import { Virtuoso } from "react-virtuoso";
|
||||||
import { API } from "revolt.js";
|
import { API } from "revolt.js";
|
||||||
import { Server } from "revolt.js/dist/maps/Servers";
|
import { Server } from "revolt.js/esm/maps/Servers";
|
||||||
|
|
||||||
import styles from "./Panes.module.scss";
|
import styles from "./Panes.module.scss";
|
||||||
import { Text } from "preact-i18n";
|
import { Text } from "preact-i18n";
|
||||||
|
|
|
||||||
|
|
@ -2,8 +2,8 @@ import { ChevronDown } from "@styled-icons/boxicons-regular";
|
||||||
import { isEqual } from "lodash";
|
import { isEqual } from "lodash";
|
||||||
import { observer } from "mobx-react-lite";
|
import { observer } from "mobx-react-lite";
|
||||||
import { Virtuoso } from "react-virtuoso";
|
import { Virtuoso } from "react-virtuoso";
|
||||||
import { Member } from "revolt.js/dist/maps/Members";
|
import { Member } from "revolt.js/esm/maps/Members";
|
||||||
import { Server } from "revolt.js/dist/maps/Servers";
|
import { Server } from "revolt.js/esm/maps/Servers";
|
||||||
|
|
||||||
import styles from "./Panes.module.scss";
|
import styles from "./Panes.module.scss";
|
||||||
import { Text } from "preact-i18n";
|
import { Text } from "preact-i18n";
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,7 @@
|
||||||
import { Markdown } from "@styled-icons/boxicons-logos";
|
import { Markdown } from "@styled-icons/boxicons-logos";
|
||||||
import isEqual from "lodash.isequal";
|
import isEqual from "lodash.isequal";
|
||||||
import { observer } from "mobx-react-lite";
|
import { observer } from "mobx-react-lite";
|
||||||
import { Server } from "revolt.js/dist/maps/Servers";
|
import { Server } from "revolt.js/esm/maps/Servers";
|
||||||
|
|
||||||
import styles from "./Panes.module.scss";
|
import styles from "./Panes.module.scss";
|
||||||
import { Text } from "preact-i18n";
|
import { Text } from "preact-i18n";
|
||||||
|
|
|
||||||
|
|
@ -116,48 +116,3 @@
|
||||||
flex-grow: 1;
|
flex-grow: 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.roles {
|
|
||||||
gap: 12px;
|
|
||||||
height: 100%;
|
|
||||||
display: flex;
|
|
||||||
|
|
||||||
.list {
|
|
||||||
width: 160px;
|
|
||||||
flex-shrink: 0;
|
|
||||||
overflow-y: scroll;
|
|
||||||
}
|
|
||||||
|
|
||||||
.permissions {
|
|
||||||
flex-grow: 1;
|
|
||||||
padding: 0 8px;
|
|
||||||
overflow-y: scroll;
|
|
||||||
}
|
|
||||||
|
|
||||||
.title {
|
|
||||||
gap: 8px;
|
|
||||||
display: flex;
|
|
||||||
margin-bottom: 1em;
|
|
||||||
align-items: center;
|
|
||||||
|
|
||||||
h1,
|
|
||||||
h2 {
|
|
||||||
margin: 0;
|
|
||||||
min-width: 0;
|
|
||||||
flex-grow: 1;
|
|
||||||
overflow: hidden;
|
|
||||||
white-space: nowrap;
|
|
||||||
text-overflow: ellipsis;
|
|
||||||
}
|
|
||||||
|
|
||||||
svg {
|
|
||||||
cursor: pointer;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.actions {
|
|
||||||
gap: 8px;
|
|
||||||
display: flex;
|
|
||||||
padding: 8px 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
|
||||||
|
|
@ -1,26 +1,29 @@
|
||||||
import isEqual from "lodash.isequal";
|
import isEqual from "lodash.isequal";
|
||||||
import { observer } from "mobx-react-lite";
|
import { observer } from "mobx-react-lite";
|
||||||
import { Server } from "revolt.js/dist/maps/Servers";
|
import { Server } from "revolt.js/esm/maps/Servers";
|
||||||
|
|
||||||
import { useLayoutEffect, useMemo, useState } from "preact/hooks";
|
import { useMemo, useState } from "preact/hooks";
|
||||||
|
|
||||||
|
import { useIntermediate } from "../../../context/intermediate/Intermediate";
|
||||||
|
|
||||||
import Button from "../../../components/ui/Button";
|
|
||||||
import Checkbox from "../../../components/ui/Checkbox";
|
import Checkbox from "../../../components/ui/Checkbox";
|
||||||
import ColourSwatches from "../../../components/ui/ColourSwatches";
|
import ColourSwatches from "../../../components/ui/ColourSwatches";
|
||||||
import InputBox from "../../../components/ui/InputBox";
|
import InputBox from "../../../components/ui/InputBox";
|
||||||
import Overline from "../../../components/ui/Overline";
|
import Overline from "../../../components/ui/Overline";
|
||||||
|
import { Button, PermissionsLayout, SpaceBetween, H1 } from "@revoltchat/ui";
|
||||||
|
|
||||||
import { PermissionList } from "../../../components/settings/roles/PermissionList";
|
import { PermissionList } from "../../../components/settings/roles/PermissionList";
|
||||||
import {
|
import { RoleOrDefault } from "../../../components/settings/roles/RoleSelection";
|
||||||
RoleOrDefault,
|
|
||||||
RoleSelection,
|
|
||||||
} from "../../../components/settings/roles/RoleSelection";
|
|
||||||
import { UnsavedChanges } from "../../../components/settings/roles/UnsavedChanges";
|
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
server: Server;
|
server: Server;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Hook to memo-ize role information.
|
||||||
|
* @param server Target server
|
||||||
|
* @returns Role array
|
||||||
|
*/
|
||||||
export function useRoles(server: Server) {
|
export function useRoles(server: Server) {
|
||||||
return useMemo(
|
return useMemo(
|
||||||
() =>
|
() =>
|
||||||
|
|
@ -38,151 +41,183 @@ export function useRoles(server: Server) {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Roles settings menu
|
||||||
|
*/
|
||||||
export const Roles = observer(({ server }: Props) => {
|
export const Roles = observer(({ server }: Props) => {
|
||||||
// Consolidate all permissions that we can change right now.
|
// Consolidate all permissions that we can change right now.
|
||||||
const currentRoles = useRoles(server);
|
const currentRoles = useRoles(server);
|
||||||
|
|
||||||
// Keep track of whatever role we're editing right now.
|
// Pull in modal context.
|
||||||
const [selected, setSelected] = useState("default");
|
const { openScreen } = useIntermediate();
|
||||||
const [value, setValue] = useState<Partial<RoleOrDefault>>({});
|
|
||||||
const currentRole = currentRoles.find((x) => x.id === selected)!;
|
|
||||||
const currentRoleValue = { ...currentRole, ...value };
|
|
||||||
|
|
||||||
// If a role gets deleted, unselect it immediately.
|
|
||||||
useLayoutEffect(() => {
|
|
||||||
if (!server.roles) return;
|
|
||||||
if (!server.roles[selected]) {
|
|
||||||
setSelected("default");
|
|
||||||
}
|
|
||||||
}, [server.roles]);
|
|
||||||
|
|
||||||
// Calculate permissions we have access to on this server.
|
|
||||||
const current = server.permission;
|
|
||||||
|
|
||||||
// Upload new role information to server.
|
|
||||||
function save() {
|
|
||||||
const { permissions: permsCurrent, ...current } = currentRole;
|
|
||||||
const { permissions: permsValue, ...value } = currentRoleValue;
|
|
||||||
|
|
||||||
if (!isEqual(permsCurrent, permsValue)) {
|
|
||||||
server.setPermissions(
|
|
||||||
selected,
|
|
||||||
typeof permsValue === "number"
|
|
||||||
? permsValue
|
|
||||||
: {
|
|
||||||
allow: permsValue.a,
|
|
||||||
deny: permsValue.d,
|
|
||||||
},
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!isEqual(current, value)) {
|
|
||||||
server.editRole(selected, value);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Delete the role from this server.
|
|
||||||
function deleteRole() {
|
|
||||||
setSelected("default");
|
|
||||||
server.deleteRole(selected);
|
|
||||||
}
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div style={{ height: "100%", overflowY: "scroll" }}>
|
<PermissionsLayout
|
||||||
<h1>Select Role</h1>
|
server={server}
|
||||||
<RoleSelection
|
onCreateRole={(callback) =>
|
||||||
selected={selected}
|
openScreen({
|
||||||
onSelect={(id) => {
|
id: "special_input",
|
||||||
setValue({});
|
type: "create_role",
|
||||||
setSelected(id);
|
server: server as any,
|
||||||
}}
|
callback,
|
||||||
roles={currentRoles}
|
})
|
||||||
/>
|
}
|
||||||
{selected !== "default" && (
|
editor={({ selected }) => {
|
||||||
<>
|
const currentRole = currentRoles.find(
|
||||||
<hr />
|
(x) => x.id === selected,
|
||||||
<h1>Edit Role</h1>
|
)!;
|
||||||
<section>
|
|
||||||
<Overline type="subtle">Role Name</Overline>
|
if (!currentRole) return null;
|
||||||
<p>
|
|
||||||
<InputBox
|
// Keep track of whatever role we're editing right now.
|
||||||
value={currentRoleValue.name}
|
const [value, setValue] = useState<Partial<RoleOrDefault>>({});
|
||||||
onChange={(e) =>
|
|
||||||
setValue({
|
const currentRoleValue = { ...currentRole, ...value };
|
||||||
...value,
|
|
||||||
name: e.currentTarget.value,
|
// Calculate permissions we have access to on this server.
|
||||||
})
|
const current = server.permission;
|
||||||
}
|
|
||||||
contrast
|
// Upload new role information to server.
|
||||||
/>
|
function save() {
|
||||||
</p>
|
const { permissions: permsCurrent, ...current } =
|
||||||
</section>
|
currentRole;
|
||||||
<section>
|
const { permissions: permsValue, ...value } =
|
||||||
<Overline type="subtle">Role Colour</Overline>
|
currentRoleValue;
|
||||||
<p>
|
|
||||||
<ColourSwatches
|
if (!isEqual(permsCurrent, permsValue)) {
|
||||||
value={currentRoleValue.colour ?? "gray"}
|
server.setPermissions(
|
||||||
onChange={(colour) =>
|
selected,
|
||||||
setValue({ ...value, colour })
|
typeof permsValue === "number"
|
||||||
}
|
? permsValue
|
||||||
/>
|
: {
|
||||||
</p>
|
allow: permsValue.a,
|
||||||
</section>
|
deny: permsValue.d,
|
||||||
<section>
|
},
|
||||||
<Overline type="subtle">Role Options</Overline>
|
);
|
||||||
<p>
|
}
|
||||||
<Checkbox
|
|
||||||
checked={currentRoleValue.hoist ?? false}
|
if (!isEqual(current, value)) {
|
||||||
onChange={(hoist) =>
|
server.editRole(selected, value);
|
||||||
setValue({ ...value, hoist })
|
}
|
||||||
}
|
|
||||||
description="Display this role above others.">
|
|
||||||
Hoist Role
|
|
||||||
</Checkbox>
|
|
||||||
</p>
|
|
||||||
</section>
|
|
||||||
<section>
|
|
||||||
<Overline type="subtle">
|
|
||||||
Experimental Role Ranking
|
|
||||||
</Overline>
|
|
||||||
<p>
|
|
||||||
<InputBox
|
|
||||||
value={currentRoleValue.rank ?? 0}
|
|
||||||
onChange={(e) =>
|
|
||||||
setValue({
|
|
||||||
...value,
|
|
||||||
rank: parseInt(e.currentTarget.value),
|
|
||||||
})
|
|
||||||
}
|
|
||||||
contrast
|
|
||||||
/>
|
|
||||||
</p>
|
|
||||||
</section>
|
|
||||||
</>
|
|
||||||
)}
|
|
||||||
{!isEqual(currentRole, currentRoleValue) && (
|
|
||||||
<>
|
|
||||||
<hr />
|
|
||||||
<UnsavedChanges save={save} />
|
|
||||||
</>
|
|
||||||
)}
|
|
||||||
<hr />
|
|
||||||
<h1>Edit Permissions</h1>
|
|
||||||
<PermissionList
|
|
||||||
value={currentRoleValue.permissions}
|
|
||||||
onChange={(permissions) =>
|
|
||||||
setValue({ ...value, permissions } as RoleOrDefault)
|
|
||||||
}
|
}
|
||||||
/>
|
|
||||||
{selected !== "default" && (
|
// Delete the role from this server.
|
||||||
<>
|
function deleteRole() {
|
||||||
<hr />
|
server.deleteRole(selected);
|
||||||
<h1>Danger Zone</h1>
|
}
|
||||||
<Button contrast error onClick={deleteRole}>
|
|
||||||
Delete Role
|
return (
|
||||||
</Button>
|
<div>
|
||||||
</>
|
<SpaceBetween>
|
||||||
)}
|
<H1>Edit {currentRole.name}</H1>
|
||||||
</div>
|
<Button
|
||||||
|
palette="secondary"
|
||||||
|
disabled={isEqual(
|
||||||
|
currentRole,
|
||||||
|
currentRoleValue,
|
||||||
|
)}
|
||||||
|
onClick={save}>
|
||||||
|
Save
|
||||||
|
</Button>
|
||||||
|
</SpaceBetween>
|
||||||
|
<hr />
|
||||||
|
{selected !== "default" && (
|
||||||
|
<>
|
||||||
|
<section>
|
||||||
|
<Overline type="subtle">Role Name</Overline>
|
||||||
|
<p>
|
||||||
|
<InputBox
|
||||||
|
value={currentRoleValue.name}
|
||||||
|
onChange={(e) =>
|
||||||
|
setValue({
|
||||||
|
...value,
|
||||||
|
name: e.currentTarget.value,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
contrast
|
||||||
|
/>
|
||||||
|
</p>
|
||||||
|
</section>
|
||||||
|
<section>
|
||||||
|
<Overline type="subtle">
|
||||||
|
Role Colour
|
||||||
|
</Overline>
|
||||||
|
<p>
|
||||||
|
<ColourSwatches
|
||||||
|
value={
|
||||||
|
currentRoleValue.colour ??
|
||||||
|
"gray"
|
||||||
|
}
|
||||||
|
onChange={(colour) =>
|
||||||
|
setValue({ ...value, colour })
|
||||||
|
}
|
||||||
|
/>
|
||||||
|
</p>
|
||||||
|
</section>
|
||||||
|
<section>
|
||||||
|
<Overline type="subtle">
|
||||||
|
Role Options
|
||||||
|
</Overline>
|
||||||
|
<p>
|
||||||
|
<Checkbox
|
||||||
|
checked={
|
||||||
|
currentRoleValue.hoist ?? false
|
||||||
|
}
|
||||||
|
onChange={(hoist) =>
|
||||||
|
setValue({ ...value, hoist })
|
||||||
|
}
|
||||||
|
description="Display this role above others.">
|
||||||
|
Hoist Role
|
||||||
|
</Checkbox>
|
||||||
|
</p>
|
||||||
|
</section>
|
||||||
|
<section>
|
||||||
|
<Overline type="subtle">
|
||||||
|
Role Ranking
|
||||||
|
</Overline>
|
||||||
|
<p>
|
||||||
|
<InputBox
|
||||||
|
type="number"
|
||||||
|
value={currentRoleValue.rank ?? 0}
|
||||||
|
onChange={(e) =>
|
||||||
|
setValue({
|
||||||
|
...value,
|
||||||
|
rank: parseInt(
|
||||||
|
e.currentTarget.value,
|
||||||
|
),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
contrast
|
||||||
|
/>
|
||||||
|
</p>
|
||||||
|
</section>
|
||||||
|
</>
|
||||||
|
)}
|
||||||
|
<h1>Edit Permissions</h1>
|
||||||
|
<PermissionList
|
||||||
|
value={currentRoleValue.permissions}
|
||||||
|
onChange={(permissions) =>
|
||||||
|
setValue({
|
||||||
|
...value,
|
||||||
|
permissions,
|
||||||
|
} as RoleOrDefault)
|
||||||
|
}
|
||||||
|
/>
|
||||||
|
{selected !== "default" && (
|
||||||
|
<>
|
||||||
|
<hr />
|
||||||
|
<h1>Danger Zone</h1>
|
||||||
|
<Button
|
||||||
|
palette="error"
|
||||||
|
compact
|
||||||
|
onClick={deleteRole}>
|
||||||
|
Delete Role
|
||||||
|
</Button>
|
||||||
|
</>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}}
|
||||||
|
/>
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
|
||||||
|
|
@ -120,6 +120,9 @@ export default defineConfig({
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
optimizeDeps: {
|
optimizeDeps: {
|
||||||
exclude: ["revolt.js"],
|
exclude: ["revolt.js", "@revoltchat/ui"],
|
||||||
|
},
|
||||||
|
resolve: {
|
||||||
|
preserveSymlinks: true,
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue