feat: more setting of ext
This commit is contained in:
@@ -42,6 +42,7 @@
|
||||
"i18next-http-backend": "^3.0.2",
|
||||
"linkify-plugin-mention": "^4.2.0",
|
||||
"linkify-react": "^4.2.0",
|
||||
"linkify-string": "^4.2.0",
|
||||
"linkifyjs": "^4.2.0",
|
||||
"localforage": "^1.10.0",
|
||||
"localforage-setitems": "^1.4.0",
|
||||
|
||||
Generated
+12
@@ -125,6 +125,9 @@ importers:
|
||||
linkify-react:
|
||||
specifier: ^4.2.0
|
||||
version: 4.2.0(linkifyjs@4.2.0)(react@19.0.0)
|
||||
linkify-string:
|
||||
specifier: ^4.2.0
|
||||
version: 4.2.0(linkifyjs@4.2.0)
|
||||
linkifyjs:
|
||||
specifier: ^4.2.0
|
||||
version: 4.2.0
|
||||
@@ -3909,6 +3912,11 @@ packages:
|
||||
linkifyjs: ^4.0.0
|
||||
react: '>= 15.0.0'
|
||||
|
||||
linkify-string@4.2.0:
|
||||
resolution: {integrity: sha512-LqOKk0+RlqibFkxjPAGOL7Mfssqj6/SdG9QWGvzeVDpoWXhaw9OXxseCtFanjIl7C6UyTTZizhyGr4IWLfijiw==}
|
||||
peerDependencies:
|
||||
linkifyjs: ^4.0.0
|
||||
|
||||
linkifyjs@4.2.0:
|
||||
resolution: {integrity: sha512-pCj3PrQyATaoTYKHrgWRF3SJwsm61udVh+vuls/Rl6SptiDhgE7ziUIudAedRY9QEfynmM7/RmLEfPUyw1HPCw==}
|
||||
|
||||
@@ -10109,6 +10117,10 @@ snapshots:
|
||||
linkifyjs: 4.2.0
|
||||
react: 19.0.0
|
||||
|
||||
linkify-string@4.2.0(linkifyjs@4.2.0):
|
||||
dependencies:
|
||||
linkifyjs: 4.2.0
|
||||
|
||||
linkifyjs@4.2.0: {}
|
||||
|
||||
loader-runner@4.3.0: {}
|
||||
|
||||
@@ -33,7 +33,7 @@
|
||||
"id": "Channel ID",
|
||||
"name": "Channel Name",
|
||||
"topic": "Channel Topic",
|
||||
"topic_placeholder": "Let everyone know how to use this channel.",
|
||||
"topic_placeholder": "Let everyone know how to use this channel.(markdown supported)",
|
||||
"visibility": "Channel Visibility",
|
||||
"public": "Public",
|
||||
"private": "Private",
|
||||
@@ -86,6 +86,12 @@
|
||||
"enable": "Enable",
|
||||
"disable": "Disable"
|
||||
},
|
||||
"admin_only_can_invite": {
|
||||
"title": "Only Admins Can Invite Users",
|
||||
"desc": "If enabled, only admins can invite new members.",
|
||||
"enable": "Enable",
|
||||
"disable": "Disable"
|
||||
},
|
||||
"enable_msg_url_preview": {
|
||||
"title": "Enable URL Preview in Message",
|
||||
"desc": "If enabled, url in message will show preview content.",
|
||||
|
||||
@@ -32,7 +32,7 @@
|
||||
"delete_desc": "Are you sure want to delete this channel?",
|
||||
"name": "Channel Name",
|
||||
"topic": "Channel Topic",
|
||||
"topic_placeholder": "Let everyone know how to use this channel.",
|
||||
"topic_placeholder": "Let everyone know how to use this channel.(markdown supported)",
|
||||
"visibility": "Channel Visibility",
|
||||
"public": "Public",
|
||||
"private": "Private"
|
||||
|
||||
@@ -33,7 +33,7 @@
|
||||
"id": "频道 ID",
|
||||
"name": "频道名",
|
||||
"topic": "频道主题",
|
||||
"topic_placeholder": "让别人知道这个频道是用来做啥的",
|
||||
"topic_placeholder": "让别人知道这个频道是用来做啥的(支持 markdown)",
|
||||
"visibility": "可见性",
|
||||
"public": "公开",
|
||||
"private": "私密",
|
||||
@@ -85,6 +85,12 @@
|
||||
"enable": "开启",
|
||||
"disable": "关闭"
|
||||
},
|
||||
"admin_only_can_invite": {
|
||||
"title": "只有管理员可以邀请新用户",
|
||||
"desc": "如果开启,只有管理员才能邀请新用户",
|
||||
"enable": "开启",
|
||||
"disable": "关闭"
|
||||
},
|
||||
"enable_msg_url_preview": {
|
||||
"title": "开启消息网址预览",
|
||||
"desc": "如果开启,消息中的网址会显示预览内容",
|
||||
|
||||
@@ -208,6 +208,7 @@ export const getEmailNotifyDelayList = () => [
|
||||
value: 12 * 60 * 60,
|
||||
},
|
||||
];
|
||||
export const KEY_ADMIN_ONLY_INVITE = `admin_only_can_invite`;
|
||||
export const KEY_ADMIN_SEE_CHANNEL_MEMBERS = `only_admin_can_see_channel_members`;
|
||||
export const KEY_MSG_URL_PREVIEW = `enable_msg_url_preview`;
|
||||
export default BASE_URL;
|
||||
|
||||
@@ -12,9 +12,13 @@ import InviteModal from "./InviteModal";
|
||||
import SearchUser from "./SearchUser";
|
||||
import UsersModal from "./UsersModal";
|
||||
import { shallowEqual } from "react-redux";
|
||||
import useServerExtSetting from "../hooks/useServerExtSetting";
|
||||
import { KEY_ADMIN_ONLY_INVITE } from "../app/config";
|
||||
|
||||
export default function AddEntriesMenu() {
|
||||
const { t } = useTranslation();
|
||||
const { getExtSetting } = useServerExtSetting();
|
||||
const onlyAdminCanInvite = getExtSetting(KEY_ADMIN_ONLY_INVITE);
|
||||
const isAdmin = useAppSelector((store) => store.authData.user?.is_admin, shallowEqual);
|
||||
const onlyAdminCreateGroup = useAppSelector(
|
||||
(store) => store.server.only_admin_can_create_group,
|
||||
@@ -62,6 +66,7 @@ export default function AddEntriesMenu() {
|
||||
"rounded flex items-center gap-2 text-sm font-semibold cursor-pointer px-2 py-2.5 md:hover:bg-gray-800/20 md:dark:hover:bg-gray-200/20";
|
||||
const iconClass = "w-5 h-5 dark:fill-gray-300";
|
||||
const canPrivateGroup = onlyAdminCreateGroup ? isAdmin : true;
|
||||
const showInvite = isAdmin || !onlyAdminCanInvite;
|
||||
return (
|
||||
<>
|
||||
<ul className="flex flex-col rounded-xl drop-shadow p-1 select-none text-gray-500 dark:text-gray-300 bg-white dark:bg-black">
|
||||
@@ -82,10 +87,12 @@ export default function AddEntriesMenu() {
|
||||
<IconMention className={iconClass} />
|
||||
{t("action.new_msg")}
|
||||
</li>
|
||||
<li className={itemClass} onClick={toggleInviteModalVisible}>
|
||||
<IconInvite className={iconClass} />
|
||||
{t("action.invite_people")}
|
||||
</li>
|
||||
{showInvite && (
|
||||
<li className={itemClass} onClick={toggleInviteModalVisible}>
|
||||
<IconInvite className={iconClass} />
|
||||
{t("action.invite_people")}
|
||||
</li>
|
||||
)}
|
||||
<li className={itemClass} onClick={toggleSearchModalVisible}>
|
||||
<IconSearch className={iconClass} />
|
||||
{t("action.search_people")}
|
||||
|
||||
@@ -16,9 +16,10 @@ import { isDarkMode } from "../utils";
|
||||
import ImagePreview from "./ImagePreview";
|
||||
|
||||
interface IProps {
|
||||
cleanMode?: boolean;
|
||||
content: string;
|
||||
}
|
||||
const MarkdownRender: FC<IProps> = ({ content }) => {
|
||||
const MarkdownRender: FC<IProps> = ({ content, cleanMode = false }) => {
|
||||
const mdContainer = useRef<HTMLDivElement | null>(null);
|
||||
useEffect(() => {
|
||||
if (mdContainer.current) {
|
||||
@@ -28,7 +29,8 @@ const MarkdownRender: FC<IProps> = ({ content }) => {
|
||||
});
|
||||
}
|
||||
}, [mdContainer]);
|
||||
|
||||
if (cleanMode)
|
||||
return <Viewer initialValue={content} theme={isDarkMode() ? "dark" : "light"}></Viewer>;
|
||||
return (
|
||||
<>
|
||||
<ImagePreview container={mdContainer.current} context="markdown" />
|
||||
|
||||
@@ -1,15 +1,15 @@
|
||||
import { FC } from "react";
|
||||
import { useAppSelector } from "@/app/store";
|
||||
import { useGetServerQuery } from "@/app/services/server";
|
||||
import { shallowEqual } from "react-redux";
|
||||
|
||||
type Props = {};
|
||||
const Meta: FC<Props> = () => {
|
||||
const Meta = () => {
|
||||
useGetServerQuery();
|
||||
const { name, logo } = useAppSelector((store) => store.server, shallowEqual);
|
||||
console.log({name});
|
||||
if(!name) return null
|
||||
return (
|
||||
<>
|
||||
{name && <title>{name} Web App</title>}
|
||||
{name && <title>{`${name} Web App`}</title>}
|
||||
{logo && <link rel="icon" href={`${logo}?ts=${new Date().getTime()}`} />}
|
||||
</>
|
||||
);
|
||||
|
||||
@@ -6,6 +6,7 @@ import clsx from "clsx";
|
||||
import { useAppSelector } from "@/app/store";
|
||||
import EditIcon from "@/assets/icons/edit.svg";
|
||||
import { shallowEqual } from "react-redux";
|
||||
import linkifyStr from "linkify-string";
|
||||
|
||||
type ChannelHeaderProps = {
|
||||
cid: number;
|
||||
@@ -15,12 +16,18 @@ const ChannelHeader = ({ cid }: ChannelHeaderProps) => {
|
||||
const { t } = useTranslation("chat");
|
||||
const isAdmin = useAppSelector((store) => store.authData.user?.is_admin, shallowEqual);
|
||||
const data = useAppSelector((store) => store.channels.byId[cid], shallowEqual);
|
||||
const desc = data.description
|
||||
? linkifyStr(data.description, { target: "_blank" })
|
||||
: t("welcome_desc", { name: data?.name });
|
||||
return (
|
||||
<div className="pt-14 px-1 md:px-0 flex flex-col items-start gap-2">
|
||||
<h2 className="font-bold text-4xl dark:text-white">
|
||||
{t("welcome_channel", { name: data?.name })}
|
||||
</h2>
|
||||
<p className="text-gray-600 dark:text-gray-300">{t("welcome_desc", { name: data?.name })} </p>
|
||||
<p
|
||||
className="text-gray-600 dark:text-gray-300 [&>a]:text-blue-500 [&>a]:hover:underline"
|
||||
dangerouslySetInnerHTML={{ __html: desc }}
|
||||
/>
|
||||
{isAdmin && (
|
||||
<NavLink
|
||||
to={`/setting/channel/${cid}/overview?f=${pathname}`}
|
||||
|
||||
@@ -0,0 +1,28 @@
|
||||
import SettingBlock from "@/components/SettingBlock";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import ServerVersionChecker from "@/components/ServerVersionChecker";
|
||||
import { KEY_ADMIN_ONLY_INVITE } from "@/app/config";
|
||||
import useServerExtSetting from "@/hooks/useServerExtSetting";
|
||||
import Toggle from "@/components/styled/Toggle";
|
||||
|
||||
type Props = {};
|
||||
|
||||
const WhoCanInviteUsers = ({}: Props) => {
|
||||
const { updateExtSetting, getExtSetting } = useServerExtSetting();
|
||||
const { t } = useTranslation("setting");
|
||||
const adminOnlyCanInvite = getExtSetting(KEY_ADMIN_ONLY_INVITE);
|
||||
const handleToggle = () => {
|
||||
updateExtSetting(KEY_ADMIN_ONLY_INVITE, !adminOnlyCanInvite);
|
||||
};
|
||||
return (
|
||||
<ServerVersionChecker empty version="0.3.50">
|
||||
<SettingBlock
|
||||
title={t("overview.admin_only_can_invite.title")}
|
||||
desc={t("overview.admin_only_can_invite.desc")}
|
||||
toggler={<Toggle onClick={handleToggle} checked={adminOnlyCanInvite} />}
|
||||
></SettingBlock>
|
||||
</ServerVersionChecker>
|
||||
);
|
||||
};
|
||||
|
||||
export default WhoCanInviteUsers;
|
||||
@@ -18,6 +18,7 @@ import ServerMsgNotify from "./ServerMsgEmailNotify";
|
||||
import GuestMode from "./GuestMode";
|
||||
import WhoCanSignUpSetting from "./WhoCanSignUpSetting";
|
||||
import UserMsgEmailNotify from "./UserMsgEmailNotify";
|
||||
import WhoCanInviteUsers from "./WhoCanInviteUsers";
|
||||
|
||||
export default function Overview() {
|
||||
const { t } = useTranslation("setting");
|
||||
@@ -42,6 +43,7 @@ export default function Overview() {
|
||||
{/* 只有 admin 能创建群组 */}
|
||||
|
||||
<EnableURLPreviewInMsg />
|
||||
<WhoCanInviteUsers />
|
||||
<OnlyAdminCanSeeChannelMembers />
|
||||
{/* 访客模式 */}
|
||||
<GuestMode />
|
||||
|
||||
@@ -15,6 +15,7 @@ export interface SystemCommon {
|
||||
chat_layout_mode?: ChatLayout;
|
||||
max_file_expiry_mode?: MessageExpireMode;
|
||||
only_admin_can_create_group: boolean;
|
||||
who_can_invite_users: boolean;
|
||||
ext_setting: null | string;
|
||||
msg_smtp_notify_enable: boolean;
|
||||
msg_smtp_notify_delay_seconds: number;
|
||||
|
||||
Reference in New Issue
Block a user