parent
4aad0493ae
commit
eee1d4060f
|
|
@ -7,6 +7,9 @@ dist-ssr
|
|||
*.log
|
||||
/.idea
|
||||
|
||||
.yarn/cache
|
||||
.yarn/install-state.gz
|
||||
|
||||
public/assets
|
||||
public/assets_*
|
||||
!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": {
|
||||
"@fontsource/bitter": "^4.5.0",
|
||||
"@insertish/vite-plugin-babel-macros": "^1.0.5",
|
||||
"color-rgba": "^2.3.0",
|
||||
"fs-extra": "^10.0.0",
|
||||
"klaw": "^3.0.0",
|
||||
"react-beautiful-dnd": "^13.1.0",
|
||||
|
|
@ -90,16 +89,16 @@
|
|||
"@fontsource/ubuntu-mono": "^4.4.5",
|
||||
"@hcaptcha/react-hcaptcha": "^0.3.6",
|
||||
"@preact/preset-vite": "^2.0.0",
|
||||
"@revoltchat/ui": "1.0.27",
|
||||
"@rollup/plugin-replace": "^2.4.2",
|
||||
"@styled-icons/boxicons-logos": "^10.34.0",
|
||||
"@styled-icons/boxicons-regular": "^10.34.0",
|
||||
"@styled-icons/boxicons-solid": "^10.37.0",
|
||||
"@styled-icons/boxicons-logos": "^10.38.0",
|
||||
"@styled-icons/boxicons-regular": "^10.38.0",
|
||||
"@styled-icons/boxicons-solid": "^10.38.0",
|
||||
"@styled-icons/simple-icons": "^10.33.0",
|
||||
"@tippyjs/react": "^4.2.5",
|
||||
"@traptitech/markdown-it-katex": "^3.4.3",
|
||||
"@traptitech/markdown-it-spoiler": "^1.1.6",
|
||||
"@trivago/prettier-plugin-sort-imports": "^2.0.2",
|
||||
"@types/color-rgba": "^2.1.0",
|
||||
"@types/lodash.defaultsdeep": "^4.6.6",
|
||||
"@types/lodash.isequal": "^4.5.5",
|
||||
"@types/markdown-it": "^12.0.2",
|
||||
|
|
@ -116,6 +115,7 @@
|
|||
"@typescript-eslint/eslint-plugin": "^4.27.0",
|
||||
"@typescript-eslint/parser": "^4.27.0",
|
||||
"classnames": "^2.3.1",
|
||||
"color-rgba": "^2.4.0",
|
||||
"dayjs": "^1.10.6",
|
||||
"detect-browser": "^5.2.0",
|
||||
"eslint": "^7.28.0",
|
||||
|
|
@ -133,7 +133,7 @@
|
|||
"markdown-it-sup": "^1.0.0",
|
||||
"mediasoup-client": "npm:@insertish/mediasoup-client@3.6.36-esnext",
|
||||
"mobx": "^6.3.2",
|
||||
"mobx-react-lite": "^3.2.0",
|
||||
"mobx-react-lite": "^3.3.0",
|
||||
"preact": "^10.5.14",
|
||||
"preact-context-menu": "^0.2.1",
|
||||
"preact-i18n": "^2.4.0-preactx",
|
||||
|
|
@ -147,7 +147,7 @@
|
|||
"react-scroll": "^1.8.2",
|
||||
"react-virtualized-auto-sizer": "^1.0.5",
|
||||
"react-virtuoso": "^1.10.4",
|
||||
"revolt.js": "6.0.0-rc.13",
|
||||
"revolt.js": "6.0.0-rc.15",
|
||||
"rimraf": "^3.0.2",
|
||||
"sass": "^1.35.1",
|
||||
"shade-blend-color": "^1.0.0",
|
||||
|
|
@ -163,5 +163,6 @@
|
|||
"main": "index.js",
|
||||
"repository": "https://github.com/revoltchat/revite.git",
|
||||
"author": "Paul <paulmakles@gmail.com>",
|
||||
"license": "MIT"
|
||||
"license": "MIT",
|
||||
"packageManager": "yarn@3.2.0"
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
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";
|
||||
|
||||
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)[])
|
||||
.filter(
|
||||
(key) =>
|
||||
key !== "GrantAllSafe" &&
|
||||
![
|
||||
"GrantAllSafe",
|
||||
"TimeoutMembers",
|
||||
"ReadMessageHistory",
|
||||
"Speak",
|
||||
"Video",
|
||||
"MuteMembers",
|
||||
"DeafenMembers",
|
||||
"MoveMembers",
|
||||
].includes(key) &&
|
||||
(!filter || filter.includes(key)),
|
||||
)
|
||||
.map((x) => (
|
||||
|
|
|
|||
|
|
@ -7,8 +7,7 @@ import { Text } from "preact-i18n";
|
|||
import { useMemo } from "preact/hooks";
|
||||
|
||||
import Checkbox from "../../ui/Checkbox";
|
||||
|
||||
import { OverrideSwitch } from "./OverrideSwitch";
|
||||
import { OverrideSwitch } from "@revoltchat/ui";
|
||||
|
||||
interface PermissionSelectProps {
|
||||
id: keyof typeof Permission;
|
||||
|
|
@ -20,6 +19,7 @@ interface PermissionSelectProps {
|
|||
type State = "Allow" | "Neutral" | "Deny";
|
||||
|
||||
const PermissionEntry = styled.label`
|
||||
gap: 8px;
|
||||
width: 100%;
|
||||
margin: 8px 0;
|
||||
display: flex;
|
||||
|
|
@ -100,9 +100,9 @@ export function PermissionSelect({
|
|||
return (
|
||||
<PermissionEntry>
|
||||
<span class="title">
|
||||
<Text id={`permissions.server.${id}.t`}>{id}</Text>
|
||||
<Text id={`permissions.${id}.t`}>{id}</Text>
|
||||
<span class="description">
|
||||
<Text id={`permissions.server.${id}.d`} />
|
||||
<Text id={`permissions.${id}.d`} />
|
||||
</span>
|
||||
</span>
|
||||
{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.
|
||||
*/
|
||||
import { ClientboundNotification } from "revolt.js/dist/websocket/notifications";
|
||||
import { ClientboundNotification } from "revolt.js/esm/websocket/notifications";
|
||||
|
||||
import { useEffect } from "preact/hooks";
|
||||
|
||||
|
|
|
|||
|
|
@ -13,7 +13,7 @@ import {
|
|||
import { Cog, UserVoice } from "@styled-icons/boxicons-solid";
|
||||
import { useHistory } from "react-router-dom";
|
||||
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 {
|
||||
ContextMenuWithData,
|
||||
|
|
|
|||
|
|
@ -9,8 +9,8 @@ import {
|
|||
LeftArrowAlt,
|
||||
} from "@styled-icons/boxicons-regular";
|
||||
import { observer } from "mobx-react-lite";
|
||||
import { Channel } from "revolt.js/dist/maps/Channels";
|
||||
import { Server } from "revolt.js/dist/maps/Servers";
|
||||
import { Channel } from "revolt.js/esm/maps/Channels";
|
||||
import { Server } from "revolt.js/esm/maps/Servers";
|
||||
|
||||
import { ContextMenuWithData, MenuItem } from "preact-context-menu";
|
||||
import { Text } from "preact-i18n";
|
||||
|
|
|
|||
|
|
@ -1,8 +1,8 @@
|
|||
/* eslint-disable react-hooks/rules-of-hooks */
|
||||
import { action, makeAutoObservable } from "mobx";
|
||||
import { Channel } from "revolt.js/dist/maps/Channels";
|
||||
import { Message } from "revolt.js/dist/maps/Messages";
|
||||
import { Nullable } from "revolt.js/dist/util/null";
|
||||
import { Channel } from "revolt.js/esm/maps/Channels";
|
||||
import { Message } from "revolt.js/esm/maps/Messages";
|
||||
import { Nullable } from "revolt.js/esm/util/null";
|
||||
|
||||
import { SimpleRenderer } from "./simple/SimpleRenderer";
|
||||
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";
|
||||
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
import { action, makeAutoObservable, runInAction } from "mobx";
|
||||
import { Channel } from "revolt.js/dist/maps/Channels";
|
||||
import { Nullable, toNullable } from "revolt.js/dist/util/null";
|
||||
import { Channel } from "revolt.js/esm/maps/Channels";
|
||||
import { Nullable, toNullable } from "revolt.js/esm/util/null";
|
||||
|
||||
import type { ProduceType, VoiceUser } from "./Types";
|
||||
import type VoiceClient from "./VoiceClient";
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
import { action, computed, makeAutoObservable, ObservableMap } from "mobx";
|
||||
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";
|
||||
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
import { action, computed, makeAutoObservable, ObservableMap } from "mobx";
|
||||
import { Channel } from "revolt.js/dist/maps/Channels";
|
||||
import { Message } from "revolt.js/dist/maps/Messages";
|
||||
import { Server } from "revolt.js/dist/maps/Servers";
|
||||
import { Channel } from "revolt.js/esm/maps/Channels";
|
||||
import { Message } from "revolt.js/esm/maps/Messages";
|
||||
import { Server } from "revolt.js/esm/maps/Servers";
|
||||
|
||||
import { mapToRecord } from "../../lib/conversion";
|
||||
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
import { action, computed, makeAutoObservable } from "mobx";
|
||||
import { API } 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 Persistent from "../interfaces/Persistent";
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@ import { Ghost } from "@styled-icons/boxicons-solid";
|
|||
import { reaction } from "mobx";
|
||||
import { observer } from "mobx-react-lite";
|
||||
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 { Text } from "preact-i18n";
|
||||
|
|
|
|||
|
|
@ -6,8 +6,8 @@ import {
|
|||
} from "@styled-icons/boxicons-regular";
|
||||
import { Notepad, Group } from "@styled-icons/boxicons-solid";
|
||||
import { observer } from "mobx-react-lite";
|
||||
import { Channel } from "revolt.js/dist/maps/Channels";
|
||||
import { User } from "revolt.js/dist/maps/Users";
|
||||
import { Channel } from "revolt.js/esm/maps/Channels";
|
||||
import { User } from "revolt.js/esm/maps/Users";
|
||||
import styled, { css } from "styled-components/macro";
|
||||
|
||||
import { isTouchscreenDevice } from "../../lib/isTouchscreenDevice";
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
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 { Text } from "preact-i18n";
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@ import { runInAction } from "mobx";
|
|||
import { observer } from "mobx-react-lite";
|
||||
import { useHistory, useParams } from "react-router-dom";
|
||||
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 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 { useContext, useEffect, useState } from "preact/hooks";
|
||||
|
|
|
|||
|
|
@ -3,8 +3,8 @@ import { X } from "@styled-icons/boxicons-regular";
|
|||
import isEqual from "lodash.isequal";
|
||||
import { observer } from "mobx-react-lite";
|
||||
import { API } from "revolt.js";
|
||||
import { Message as MessageI } from "revolt.js/dist/maps/Messages";
|
||||
import { Nullable } from "revolt.js/dist/util/null";
|
||||
import { Message as MessageI } from "revolt.js/esm/maps/Messages";
|
||||
import { Nullable } from "revolt.js/esm/util/null";
|
||||
import styled from "styled-components/macro";
|
||||
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 { observer } from "mobx-react-lite";
|
||||
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 classNames from "classnames";
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
import { ChevronRight } from "@styled-icons/boxicons-regular";
|
||||
import { UserDetail, MessageAdd, UserPlus } from "@styled-icons/boxicons-solid";
|
||||
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 classNames from "classnames";
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
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 { Text } from "preact-i18n";
|
||||
|
|
|
|||
|
|
@ -1,15 +1,14 @@
|
|||
import isEqual from "lodash.isequal";
|
||||
import { observer } from "mobx-react-lite";
|
||||
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 {
|
||||
RoleOrDefault,
|
||||
RoleSelection,
|
||||
} from "../../../components/settings/roles/RoleSelection";
|
||||
import { UnsavedChanges } from "../../../components/settings/roles/UnsavedChanges";
|
||||
import { RoleOrDefault } from "../../../components/settings/roles/RoleSelection";
|
||||
import { useRoles } from "../server/Roles";
|
||||
|
||||
interface Props {
|
||||
|
|
@ -24,10 +23,12 @@ export default observer(({ channel }: Props) => {
|
|||
{
|
||||
id: "default",
|
||||
name: "Default",
|
||||
permissions: channel.permissions,
|
||||
permissions:
|
||||
channel.permissions ??
|
||||
DEFAULT_PERMISSION_DIRECT_MESSAGE,
|
||||
},
|
||||
] as RoleOrDefault[])
|
||||
: (useRoles(channel.server!).map((role) => {
|
||||
: (useRoles(channel.server! as any).map((role) => {
|
||||
return {
|
||||
...role,
|
||||
permissions: (role.id === "default"
|
||||
|
|
@ -39,24 +40,25 @@ export default observer(({ channel }: Props) => {
|
|||
};
|
||||
}) as RoleOrDefault[]);
|
||||
|
||||
return (
|
||||
<PermissionsLayout
|
||||
channel={channel}
|
||||
editor={({ selected }) => {
|
||||
const currentRole = currentRoles.find(
|
||||
(x) => x.id === selected,
|
||||
)!;
|
||||
|
||||
if (!currentRole) return null;
|
||||
|
||||
// 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 [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(
|
||||
|
|
@ -71,29 +73,26 @@ export default observer(({ channel }: Props) => {
|
|||
}
|
||||
|
||||
return (
|
||||
<div style={{ height: "100%", overflowY: "scroll" }}>
|
||||
<h1>Select Role</h1>
|
||||
<RoleSelection
|
||||
selected={selected}
|
||||
onSelect={(id) => {
|
||||
setValue(undefined);
|
||||
setSelected(id);
|
||||
}}
|
||||
roles={currentRoles}
|
||||
/>
|
||||
{!isEqual(currentPermission, currentValue) && (
|
||||
<>
|
||||
<hr />
|
||||
<UnsavedChanges save={save} />
|
||||
</>
|
||||
<div>
|
||||
<SpaceBetween>
|
||||
<H1>Permissions for {currentRole.name}</H1>
|
||||
<Button
|
||||
palette="secondary"
|
||||
disabled={isEqual(
|
||||
currentPermission,
|
||||
currentValue,
|
||||
)}
|
||||
<hr />
|
||||
<h1>Edit Permissions</h1>
|
||||
onClick={save}>
|
||||
Save
|
||||
</Button>
|
||||
</SpaceBetween>
|
||||
<PermissionList
|
||||
value={currentValue}
|
||||
onChange={setValue}
|
||||
filter={[
|
||||
"ViewChannel",
|
||||
...(channel.channel_type === "Group"
|
||||
? []
|
||||
: ["ViewChannel" as "ViewChannel"]),
|
||||
"ReadMessageHistory",
|
||||
"SendMessage",
|
||||
"ManageMessages",
|
||||
|
|
@ -106,87 +105,7 @@ export default observer(({ channel }: Props) => {
|
|||
/>
|
||||
</div>
|
||||
);
|
||||
|
||||
/*const [selected, setSelected] = useState("default");
|
||||
|
||||
type R = { name: string; permissions: number };
|
||||
const roles: { [key: string]: R } = {};
|
||||
if (channel.channel_type !== "Group") {
|
||||
const server = channel.server;
|
||||
const a = server?.roles ?? {};
|
||||
for (const b of Object.keys(a)) {
|
||||
roles[b] = {
|
||||
name: a[b].name,
|
||||
permissions:
|
||||
channel.role_permissions?.[b] ?? a[b].permissions[1],
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
const keys = ["default", ...Object.keys(roles)];
|
||||
|
||||
const defaultRole = {
|
||||
name: "Default",
|
||||
permissions:
|
||||
(channel.channel_type === "Group"
|
||||
? channel.permissions
|
||||
: channel.default_permissions) ?? DEFAULT_PERMISSION_DM,
|
||||
};
|
||||
const selectedRole = selected === "default" ? defaultRole : roles[selected];
|
||||
|
||||
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
|
||||
contrast
|
||||
onClick={() => {
|
||||
channel.setPermissions(selected, p);
|
||||
}}>
|
||||
click here to save permissions for role
|
||||
</Button>
|
||||
</div>
|
||||
);*/
|
||||
});
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@ import { LockAlt, HelpCircle } from "@styled-icons/boxicons-solid";
|
|||
import type { AxiosError } from "axios";
|
||||
import { observer } from "mobx-react-lite";
|
||||
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 styles from "./Panes.module.scss";
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@ import { XCircle } from "@styled-icons/boxicons-regular";
|
|||
import { observer } from "mobx-react-lite";
|
||||
import { Virtuoso } from "react-virtuoso";
|
||||
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 { Text } from "preact-i18n";
|
||||
|
|
|
|||
|
|
@ -2,8 +2,8 @@ import { ChevronDown } from "@styled-icons/boxicons-regular";
|
|||
import { isEqual } from "lodash";
|
||||
import { observer } from "mobx-react-lite";
|
||||
import { Virtuoso } from "react-virtuoso";
|
||||
import { Member } from "revolt.js/dist/maps/Members";
|
||||
import { Server } from "revolt.js/dist/maps/Servers";
|
||||
import { Member } from "revolt.js/esm/maps/Members";
|
||||
import { Server } from "revolt.js/esm/maps/Servers";
|
||||
|
||||
import styles from "./Panes.module.scss";
|
||||
import { Text } from "preact-i18n";
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
import { Markdown } from "@styled-icons/boxicons-logos";
|
||||
import isEqual from "lodash.isequal";
|
||||
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 { Text } from "preact-i18n";
|
||||
|
|
|
|||
|
|
@ -116,48 +116,3 @@
|
|||
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 { 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 ColourSwatches from "../../../components/ui/ColourSwatches";
|
||||
import InputBox from "../../../components/ui/InputBox";
|
||||
import Overline from "../../../components/ui/Overline";
|
||||
import { Button, PermissionsLayout, SpaceBetween, H1 } from "@revoltchat/ui";
|
||||
|
||||
import { PermissionList } from "../../../components/settings/roles/PermissionList";
|
||||
import {
|
||||
RoleOrDefault,
|
||||
RoleSelection,
|
||||
} from "../../../components/settings/roles/RoleSelection";
|
||||
import { UnsavedChanges } from "../../../components/settings/roles/UnsavedChanges";
|
||||
import { RoleOrDefault } from "../../../components/settings/roles/RoleSelection";
|
||||
|
||||
interface Props {
|
||||
server: Server;
|
||||
}
|
||||
|
||||
/**
|
||||
* Hook to memo-ize role information.
|
||||
* @param server Target server
|
||||
* @returns Role array
|
||||
*/
|
||||
export function useRoles(server: Server) {
|
||||
return useMemo(
|
||||
() =>
|
||||
|
|
@ -38,31 +41,48 @@ export function useRoles(server: Server) {
|
|||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Roles settings menu
|
||||
*/
|
||||
export const Roles = observer(({ server }: Props) => {
|
||||
// Consolidate all permissions that we can change right now.
|
||||
const currentRoles = useRoles(server);
|
||||
|
||||
// Keep track of whatever role we're editing right now.
|
||||
const [selected, setSelected] = useState("default");
|
||||
const [value, setValue] = useState<Partial<RoleOrDefault>>({});
|
||||
const currentRole = currentRoles.find((x) => x.id === selected)!;
|
||||
const currentRoleValue = { ...currentRole, ...value };
|
||||
// Pull in modal context.
|
||||
const { openScreen } = useIntermediate();
|
||||
|
||||
// If a role gets deleted, unselect it immediately.
|
||||
useLayoutEffect(() => {
|
||||
if (!server.roles) return;
|
||||
if (!server.roles[selected]) {
|
||||
setSelected("default");
|
||||
return (
|
||||
<PermissionsLayout
|
||||
server={server}
|
||||
onCreateRole={(callback) =>
|
||||
openScreen({
|
||||
id: "special_input",
|
||||
type: "create_role",
|
||||
server: server as any,
|
||||
callback,
|
||||
})
|
||||
}
|
||||
}, [server.roles]);
|
||||
editor={({ selected }) => {
|
||||
const currentRole = currentRoles.find(
|
||||
(x) => x.id === selected,
|
||||
)!;
|
||||
|
||||
if (!currentRole) return null;
|
||||
|
||||
// Keep track of whatever role we're editing right now.
|
||||
const [value, setValue] = useState<Partial<RoleOrDefault>>({});
|
||||
|
||||
const currentRoleValue = { ...currentRole, ...value };
|
||||
|
||||
// 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;
|
||||
const { permissions: permsCurrent, ...current } =
|
||||
currentRole;
|
||||
const { permissions: permsValue, ...value } =
|
||||
currentRoleValue;
|
||||
|
||||
if (!isEqual(permsCurrent, permsValue)) {
|
||||
server.setPermissions(
|
||||
|
|
@ -83,25 +103,26 @@ export const Roles = observer(({ server }: Props) => {
|
|||
|
||||
// Delete the role from this server.
|
||||
function deleteRole() {
|
||||
setSelected("default");
|
||||
server.deleteRole(selected);
|
||||
}
|
||||
|
||||
return (
|
||||
<div style={{ height: "100%", overflowY: "scroll" }}>
|
||||
<h1>Select Role</h1>
|
||||
<RoleSelection
|
||||
selected={selected}
|
||||
onSelect={(id) => {
|
||||
setValue({});
|
||||
setSelected(id);
|
||||
}}
|
||||
roles={currentRoles}
|
||||
/>
|
||||
<div>
|
||||
<SpaceBetween>
|
||||
<H1>Edit {currentRole.name}</H1>
|
||||
<Button
|
||||
palette="secondary"
|
||||
disabled={isEqual(
|
||||
currentRole,
|
||||
currentRoleValue,
|
||||
)}
|
||||
onClick={save}>
|
||||
Save
|
||||
</Button>
|
||||
</SpaceBetween>
|
||||
<hr />
|
||||
{selected !== "default" && (
|
||||
<>
|
||||
<hr />
|
||||
<h1>Edit Role</h1>
|
||||
<section>
|
||||
<Overline type="subtle">Role Name</Overline>
|
||||
<p>
|
||||
|
|
@ -118,10 +139,15 @@ export const Roles = observer(({ server }: Props) => {
|
|||
</p>
|
||||
</section>
|
||||
<section>
|
||||
<Overline type="subtle">Role Colour</Overline>
|
||||
<Overline type="subtle">
|
||||
Role Colour
|
||||
</Overline>
|
||||
<p>
|
||||
<ColourSwatches
|
||||
value={currentRoleValue.colour ?? "gray"}
|
||||
value={
|
||||
currentRoleValue.colour ??
|
||||
"gray"
|
||||
}
|
||||
onChange={(colour) =>
|
||||
setValue({ ...value, colour })
|
||||
}
|
||||
|
|
@ -129,10 +155,14 @@ export const Roles = observer(({ server }: Props) => {
|
|||
</p>
|
||||
</section>
|
||||
<section>
|
||||
<Overline type="subtle">Role Options</Overline>
|
||||
<Overline type="subtle">
|
||||
Role Options
|
||||
</Overline>
|
||||
<p>
|
||||
<Checkbox
|
||||
checked={currentRoleValue.hoist ?? false}
|
||||
checked={
|
||||
currentRoleValue.hoist ?? false
|
||||
}
|
||||
onChange={(hoist) =>
|
||||
setValue({ ...value, hoist })
|
||||
}
|
||||
|
|
@ -143,15 +173,18 @@ export const Roles = observer(({ server }: Props) => {
|
|||
</section>
|
||||
<section>
|
||||
<Overline type="subtle">
|
||||
Experimental Role Ranking
|
||||
Role Ranking
|
||||
</Overline>
|
||||
<p>
|
||||
<InputBox
|
||||
type="number"
|
||||
value={currentRoleValue.rank ?? 0}
|
||||
onChange={(e) =>
|
||||
setValue({
|
||||
...value,
|
||||
rank: parseInt(e.currentTarget.value),
|
||||
rank: parseInt(
|
||||
e.currentTarget.value,
|
||||
),
|
||||
})
|
||||
}
|
||||
contrast
|
||||
|
|
@ -160,29 +193,31 @@ export const Roles = observer(({ server }: Props) => {
|
|||
</section>
|
||||
</>
|
||||
)}
|
||||
{!isEqual(currentRole, currentRoleValue) && (
|
||||
<>
|
||||
<hr />
|
||||
<UnsavedChanges save={save} />
|
||||
</>
|
||||
)}
|
||||
<hr />
|
||||
<h1>Edit Permissions</h1>
|
||||
<PermissionList
|
||||
value={currentRoleValue.permissions}
|
||||
onChange={(permissions) =>
|
||||
setValue({ ...value, permissions } as RoleOrDefault)
|
||||
setValue({
|
||||
...value,
|
||||
permissions,
|
||||
} as RoleOrDefault)
|
||||
}
|
||||
/>
|
||||
{selected !== "default" && (
|
||||
<>
|
||||
<hr />
|
||||
<h1>Danger Zone</h1>
|
||||
<Button contrast error onClick={deleteRole}>
|
||||
<Button
|
||||
palette="error"
|
||||
compact
|
||||
onClick={deleteRole}>
|
||||
Delete Role
|
||||
</Button>
|
||||
</>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
}}
|
||||
/>
|
||||
);
|
||||
});
|
||||
|
|
|
|||
|
|
@ -120,6 +120,9 @@ export default defineConfig({
|
|||
},
|
||||
},
|
||||
optimizeDeps: {
|
||||
exclude: ["revolt.js"],
|
||||
exclude: ["revolt.js", "@revoltchat/ui"],
|
||||
},
|
||||
resolve: {
|
||||
preserveSymlinks: true,
|
||||
},
|
||||
});
|
||||
|
|
|
|||
Loading…
Reference in New Issue