mirror of
https://github.com/toeverything/AFFiNE.git
synced 2026-02-26 10:45:57 +08:00
@@ -18,6 +18,7 @@ import {
|
||||
} from '../../../components/ui/popover';
|
||||
import { useDebouncedValue } from '../../../hooks/use-debounced-value';
|
||||
import { useServerConfig } from '../../common';
|
||||
import type { WorkspaceFlagFilter } from '../schema';
|
||||
|
||||
interface DataTableToolbarProps<TData> {
|
||||
table?: Table<TData>;
|
||||
@@ -25,19 +26,21 @@ interface DataTableToolbarProps<TData> {
|
||||
onKeywordChange: (keyword: string) => void;
|
||||
selectedFeatures: FeatureType[];
|
||||
onFeaturesChange: (features: FeatureType[]) => void;
|
||||
flags: WorkspaceFlagFilter;
|
||||
onFlagsChange: (flags: WorkspaceFlagFilter) => void;
|
||||
sort: AdminWorkspaceSort | undefined;
|
||||
onSortChange: (sort: AdminWorkspaceSort | undefined) => void;
|
||||
disabled?: boolean;
|
||||
}
|
||||
|
||||
const sortOptions: { value: AdminWorkspaceSort; label: string }[] = [
|
||||
{ value: AdminWorkspaceSort.SnapshotSize, label: 'Snapshot size' },
|
||||
{ value: AdminWorkspaceSort.CreatedAt, label: 'Created time' },
|
||||
{ value: AdminWorkspaceSort.BlobCount, label: 'Blob count' },
|
||||
{ value: AdminWorkspaceSort.BlobSize, label: 'Blob size' },
|
||||
{ value: AdminWorkspaceSort.SnapshotCount, label: 'Snapshot count' },
|
||||
{ value: AdminWorkspaceSort.SnapshotSize, label: 'Snapshot size' },
|
||||
{ value: AdminWorkspaceSort.MemberCount, label: 'Member count' },
|
||||
{ value: AdminWorkspaceSort.PublicPageCount, label: 'Public pages' },
|
||||
{ value: AdminWorkspaceSort.CreatedAt, label: 'Created time' },
|
||||
];
|
||||
|
||||
export function DataTableToolbar<TData>({
|
||||
@@ -45,6 +48,8 @@ export function DataTableToolbar<TData>({
|
||||
onKeywordChange,
|
||||
selectedFeatures,
|
||||
onFeaturesChange,
|
||||
flags,
|
||||
onFlagsChange,
|
||||
sort,
|
||||
onSortChange,
|
||||
disabled = false,
|
||||
@@ -80,6 +85,35 @@ export function DataTableToolbar<TData>({
|
||||
[sort]
|
||||
);
|
||||
|
||||
const flagOptions: { key: keyof WorkspaceFlagFilter; label: string }[] = [
|
||||
{ key: 'public', label: 'Public' },
|
||||
{ key: 'enableSharing', label: 'Enable sharing' },
|
||||
{ key: 'enableAi', label: 'Enable AI' },
|
||||
{ key: 'enableUrlPreview', label: 'Enable URL preview' },
|
||||
{ key: 'enableDocEmbedding', label: 'Enable doc embedding' },
|
||||
];
|
||||
|
||||
const flagLabel = (value: boolean | undefined) => {
|
||||
if (value === true) return 'On';
|
||||
if (value === false) return 'Off';
|
||||
return 'Any';
|
||||
};
|
||||
|
||||
const handleFlagToggle = useCallback(
|
||||
(key: keyof WorkspaceFlagFilter) => {
|
||||
const current = flags[key];
|
||||
const next =
|
||||
current === undefined ? true : current === true ? false : undefined;
|
||||
onFlagsChange({ ...flags, [key]: next });
|
||||
},
|
||||
[flags, onFlagsChange]
|
||||
);
|
||||
|
||||
const hasFlagFilter = useMemo(
|
||||
() => Object.values(flags).some(v => v !== undefined),
|
||||
[flags]
|
||||
);
|
||||
|
||||
return (
|
||||
<div className="flex items-center justify-between gap-y-2 gap-x-4 flex-wrap">
|
||||
<FeatureFilterPopover
|
||||
@@ -119,6 +153,37 @@ export function DataTableToolbar<TData>({
|
||||
</div>
|
||||
</PopoverContent>
|
||||
</Popover>
|
||||
<Popover open={disabled ? false : undefined}>
|
||||
<PopoverTrigger asChild>
|
||||
<Button
|
||||
variant={hasFlagFilter ? 'secondary' : 'outline'}
|
||||
size="sm"
|
||||
className="h-8 px-2 lg:px-3"
|
||||
disabled={disabled}
|
||||
>
|
||||
Flags
|
||||
</Button>
|
||||
</PopoverTrigger>
|
||||
<PopoverContent className="w-[260px] p-2">
|
||||
<div className="flex flex-col gap-1">
|
||||
{flagOptions.map(option => (
|
||||
<Button
|
||||
key={option.key}
|
||||
variant="ghost"
|
||||
className="justify-between"
|
||||
size="sm"
|
||||
disabled={disabled}
|
||||
onClick={() => handleFlagToggle(option.key)}
|
||||
>
|
||||
<span>{option.label}</span>
|
||||
<span className="text-xs text-muted-foreground">
|
||||
{flagLabel(flags[option.key])}
|
||||
</span>
|
||||
</Button>
|
||||
))}
|
||||
</div>
|
||||
</PopoverContent>
|
||||
</Popover>
|
||||
<div className="flex">
|
||||
<Input
|
||||
placeholder="Search Workspace / Owner"
|
||||
|
||||
@@ -3,6 +3,7 @@ import type { ColumnDef, PaginationState } from '@tanstack/react-table';
|
||||
import type { Dispatch, SetStateAction } from 'react';
|
||||
|
||||
import { SharedDataTable } from '../../../components/shared/data-table';
|
||||
import type { WorkspaceFlagFilter } from '../schema';
|
||||
import { DataTableToolbar } from './data-table-toolbar';
|
||||
|
||||
interface DataTableProps<TData, TValue> {
|
||||
@@ -14,6 +15,8 @@ interface DataTableProps<TData, TValue> {
|
||||
onKeywordChange: (value: string) => void;
|
||||
selectedFeatures: FeatureType[];
|
||||
onFeaturesChange: (features: FeatureType[]) => void;
|
||||
flags: WorkspaceFlagFilter;
|
||||
onFlagsChange: Dispatch<SetStateAction<WorkspaceFlagFilter>>;
|
||||
sort: AdminWorkspaceSort | undefined;
|
||||
onSortChange: (sort: AdminWorkspaceSort | undefined) => void;
|
||||
loading?: boolean;
|
||||
@@ -34,6 +37,8 @@ export function DataTable<TData extends { id: string }, TValue>({
|
||||
onKeywordChange,
|
||||
selectedFeatures,
|
||||
onFeaturesChange,
|
||||
flags,
|
||||
onFlagsChange,
|
||||
sort,
|
||||
onSortChange,
|
||||
onPaginationChange,
|
||||
@@ -46,7 +51,7 @@ export function DataTable<TData extends { id: string }, TValue>({
|
||||
totalCount={workspacesCount}
|
||||
pagination={pagination}
|
||||
onPaginationChange={onPaginationChange}
|
||||
resetFiltersDeps={[keyword, selectedFeatures, sort]}
|
||||
resetFiltersDeps={[keyword, selectedFeatures, sort, flags]}
|
||||
renderToolbar={table => (
|
||||
<DataTableToolbar
|
||||
table={table}
|
||||
@@ -54,6 +59,8 @@ export function DataTable<TData extends { id: string }, TValue>({
|
||||
onKeywordChange={onKeywordChange}
|
||||
selectedFeatures={selectedFeatures}
|
||||
onFeaturesChange={onFeaturesChange}
|
||||
flags={flags}
|
||||
onFlagsChange={onFlagsChange}
|
||||
sort={sort}
|
||||
onSortChange={onSortChange}
|
||||
disabled={loading}
|
||||
|
||||
@@ -86,6 +86,7 @@ function WorkspacePanelContent({
|
||||
flags: {
|
||||
public: workspace.public,
|
||||
enableAi: workspace.enableAi,
|
||||
enableSharing: workspace.enableSharing,
|
||||
enableUrlPreview: workspace.enableUrlPreview,
|
||||
enableDocEmbedding: workspace.enableDocEmbedding,
|
||||
name: workspace.name ?? '',
|
||||
@@ -110,6 +111,7 @@ function WorkspacePanelContent({
|
||||
return (
|
||||
flags.public !== baseline.flags.public ||
|
||||
flags.enableAi !== baseline.flags.enableAi ||
|
||||
flags.enableSharing !== baseline.flags.enableSharing ||
|
||||
flags.enableUrlPreview !== baseline.flags.enableUrlPreview ||
|
||||
flags.enableDocEmbedding !== baseline.flags.enableDocEmbedding ||
|
||||
flags.name !== baseline.flags.name ||
|
||||
@@ -134,6 +136,7 @@ function WorkspacePanelContent({
|
||||
id: workspace.id,
|
||||
public: flags.public,
|
||||
enableAi: flags.enableAi,
|
||||
enableSharing: flags.enableSharing,
|
||||
enableUrlPreview: flags.enableUrlPreview,
|
||||
enableDocEmbedding: flags.enableDocEmbedding,
|
||||
name: flags.name || null,
|
||||
@@ -231,6 +234,15 @@ function WorkspacePanelContent({
|
||||
}
|
||||
/>
|
||||
<Separator />
|
||||
<FlagItem
|
||||
label="Allow Workspace Sharing"
|
||||
description="Allow pages in this workspace to be shared publicly"
|
||||
checked={flags.enableSharing}
|
||||
onCheckedChange={value =>
|
||||
setFlags(prev => ({ ...prev, enableSharing: value }))
|
||||
}
|
||||
/>
|
||||
<Separator />
|
||||
<FlagItem
|
||||
label="Enable Doc Embedding"
|
||||
description="Allow document embedding for search"
|
||||
|
||||
@@ -4,11 +4,13 @@ import { useState } from 'react';
|
||||
import { Header } from '../header';
|
||||
import { useColumns } from './components/columns';
|
||||
import { DataTable } from './components/data-table';
|
||||
import type { WorkspaceFlagFilter } from './schema';
|
||||
import { useWorkspaceList } from './use-workspace-list';
|
||||
|
||||
export function WorkspacePage() {
|
||||
const [keyword, setKeyword] = useState('');
|
||||
const [featureFilters, setFeatureFilters] = useState<FeatureType[]>([]);
|
||||
const [flagFilters, setFlagFilters] = useState<WorkspaceFlagFilter>({});
|
||||
const [sort, setSort] = useState<AdminWorkspaceSort | undefined>(
|
||||
AdminWorkspaceSort.CreatedAt
|
||||
);
|
||||
@@ -18,6 +20,7 @@ export function WorkspacePage() {
|
||||
keyword,
|
||||
features: featureFilters,
|
||||
orderBy: sort,
|
||||
flags: flagFilters,
|
||||
});
|
||||
|
||||
const columns = useColumns();
|
||||
@@ -36,6 +39,8 @@ export function WorkspacePage() {
|
||||
onKeywordChange={setKeyword}
|
||||
selectedFeatures={featureFilters}
|
||||
onFeaturesChange={setFeatureFilters}
|
||||
flags={flagFilters}
|
||||
onFlagsChange={setFlagFilters}
|
||||
sort={sort}
|
||||
onSortChange={setSort}
|
||||
loading={loading}
|
||||
|
||||
@@ -16,3 +16,11 @@ export type WorkspaceUpdateInput =
|
||||
AdminUpdateWorkspaceMutation['adminUpdateWorkspace'];
|
||||
|
||||
export type WorkspaceFeatureFilter = FeatureType[];
|
||||
|
||||
export type WorkspaceFlagFilter = {
|
||||
public?: boolean;
|
||||
enableAi?: boolean;
|
||||
enableSharing?: boolean;
|
||||
enableUrlPreview?: boolean;
|
||||
enableDocEmbedding?: boolean;
|
||||
};
|
||||
|
||||
@@ -7,10 +7,13 @@ import {
|
||||
} from '@affine/graphql';
|
||||
import { useEffect, useMemo, useState } from 'react';
|
||||
|
||||
import type { WorkspaceFlagFilter } from './schema';
|
||||
|
||||
export const useWorkspaceList = (filter?: {
|
||||
keyword?: string;
|
||||
features?: FeatureType[];
|
||||
orderBy?: AdminWorkspaceSort;
|
||||
flags?: WorkspaceFlagFilter;
|
||||
}) => {
|
||||
const [pagination, setPagination] = useState({
|
||||
pageIndex: 0,
|
||||
@@ -21,8 +24,10 @@ export const useWorkspaceList = (filter?: {
|
||||
() =>
|
||||
`${filter?.keyword ?? ''}-${[...(filter?.features ?? [])]
|
||||
.sort()
|
||||
.join(',')}-${filter?.orderBy ?? ''}`,
|
||||
[filter?.features, filter?.keyword, filter?.orderBy]
|
||||
.join(',')}-${filter?.orderBy ?? ''}-${JSON.stringify(
|
||||
filter?.flags ?? {}
|
||||
)}`,
|
||||
[filter?.features, filter?.flags, filter?.keyword, filter?.orderBy]
|
||||
);
|
||||
|
||||
useEffect(() => {
|
||||
@@ -40,10 +45,20 @@ export const useWorkspaceList = (filter?: {
|
||||
? filter.features
|
||||
: undefined,
|
||||
orderBy: filter?.orderBy,
|
||||
public: filter?.flags?.public,
|
||||
enableAi: filter?.flags?.enableAi,
|
||||
enableSharing: filter?.flags?.enableSharing,
|
||||
enableUrlPreview: filter?.flags?.enableUrlPreview,
|
||||
enableDocEmbedding: filter?.flags?.enableDocEmbedding,
|
||||
},
|
||||
}),
|
||||
[
|
||||
filter?.features,
|
||||
filter?.flags?.enableAi,
|
||||
filter?.flags?.enableDocEmbedding,
|
||||
filter?.flags?.enableSharing,
|
||||
filter?.flags?.enableUrlPreview,
|
||||
filter?.flags?.public,
|
||||
filter?.keyword,
|
||||
filter?.orderBy,
|
||||
pagination.pageIndex,
|
||||
|
||||
@@ -21,11 +21,19 @@ export const SharingPanel = () => {
|
||||
export const Sharing = () => {
|
||||
const t = useI18n();
|
||||
const shareSetting = useService(WorkspaceShareSettingService).sharePreview;
|
||||
const enableSharing = useLiveData(shareSetting.enableSharing$);
|
||||
const enableUrlPreview = useLiveData(shareSetting.enableUrlPreview$);
|
||||
const loading = useLiveData(shareSetting.isLoading$);
|
||||
const permissionService = useService(WorkspacePermissionService);
|
||||
const isOwner = useLiveData(permissionService.permission.isOwner$);
|
||||
|
||||
const handleToggleSharing = useAsyncCallback(
|
||||
async (checked: boolean) => {
|
||||
await shareSetting.setEnableSharing(checked);
|
||||
},
|
||||
[shareSetting]
|
||||
);
|
||||
|
||||
const handleCheck = useAsyncCallback(
|
||||
async (checked: boolean) => {
|
||||
await shareSetting.setEnableUrlPreview(checked);
|
||||
@@ -51,6 +59,20 @@ export const Sharing = () => {
|
||||
disabled={loading}
|
||||
/>
|
||||
</SettingRow>
|
||||
<SettingRow
|
||||
name={t[
|
||||
'com.affine.settings.workspace.sharing.workspace-sharing.title'
|
||||
]()}
|
||||
desc={t[
|
||||
'com.affine.settings.workspace.sharing.workspace-sharing.description'
|
||||
]()}
|
||||
>
|
||||
<Switch
|
||||
checked={enableSharing ?? true}
|
||||
onChange={handleToggleSharing}
|
||||
disabled={loading}
|
||||
/>
|
||||
</SettingRow>
|
||||
</SettingWrapper>
|
||||
);
|
||||
};
|
||||
|
||||
@@ -1,8 +1,11 @@
|
||||
import { useEnableCloud } from '@affine/core/components/hooks/affine/use-enable-cloud';
|
||||
import { WorkspaceShareSettingService } from '@affine/core/modules/share-setting';
|
||||
import type { Workspace } from '@affine/core/modules/workspace';
|
||||
import { useI18n } from '@affine/i18n';
|
||||
import { track } from '@affine/track';
|
||||
import type { Store } from '@blocksuite/affine/store';
|
||||
import { useCallback } from 'react';
|
||||
import { useLiveData, useService } from '@toeverything/infra';
|
||||
import { useCallback, useEffect } from 'react';
|
||||
|
||||
import { ShareMenu } from './share-menu';
|
||||
export { CloudSvg } from './cloud-svg';
|
||||
@@ -14,6 +17,10 @@ type SharePageModalProps = {
|
||||
};
|
||||
|
||||
export const SharePageButton = ({ workspace, page }: SharePageModalProps) => {
|
||||
const t = useI18n();
|
||||
const shareSetting = useService(WorkspaceShareSettingService).sharePreview;
|
||||
const enableSharing = useLiveData(shareSetting.enableSharing$);
|
||||
|
||||
const confirmEnableCloud = useEnableCloud();
|
||||
const handleOpenShareModal = useCallback((open: boolean) => {
|
||||
if (open) {
|
||||
@@ -21,6 +28,18 @@ export const SharePageButton = ({ workspace, page }: SharePageModalProps) => {
|
||||
}
|
||||
}, []);
|
||||
|
||||
useEffect(() => {
|
||||
if (workspace.meta.flavour === 'local') {
|
||||
return;
|
||||
}
|
||||
shareSetting.revalidate();
|
||||
}, [shareSetting, workspace.meta.flavour]);
|
||||
|
||||
const sharingDisabled = enableSharing === false;
|
||||
const disabledReason = sharingDisabled
|
||||
? t['com.affine.share-menu.workspace-sharing.disabled.tooltip']()
|
||||
: undefined;
|
||||
|
||||
return (
|
||||
<ShareMenu
|
||||
workspaceMetadata={workspace.meta}
|
||||
@@ -31,6 +50,8 @@ export const SharePageButton = ({ workspace, page }: SharePageModalProps) => {
|
||||
})
|
||||
}
|
||||
onOpenShareModal={handleOpenShareModal}
|
||||
disabled={sharingDisabled}
|
||||
disabledReason={disabledReason}
|
||||
/>
|
||||
);
|
||||
};
|
||||
|
||||
@@ -35,6 +35,8 @@ export interface ShareMenuProps extends PropsWithChildren {
|
||||
onOpenShareModal?: (open: boolean) => void;
|
||||
openPaywallModal?: () => void;
|
||||
hittingPaywall?: boolean;
|
||||
disabled?: boolean;
|
||||
disabledReason?: string;
|
||||
}
|
||||
|
||||
export enum ShareMenuTab {
|
||||
@@ -203,7 +205,7 @@ export const ShareMenuContent = (props: ShareMenuProps) => {
|
||||
};
|
||||
|
||||
const DefaultShareButton = forwardRef(function DefaultShareButton(
|
||||
_,
|
||||
props: { disabled?: boolean; tooltip?: string },
|
||||
ref: Ref<HTMLButtonElement>
|
||||
) {
|
||||
const t = useI18n();
|
||||
@@ -211,18 +213,26 @@ const DefaultShareButton = forwardRef(function DefaultShareButton(
|
||||
const shared = useLiveData(shareInfoService.shareInfo.isShared$);
|
||||
|
||||
useEffect(() => {
|
||||
if (props.disabled) {
|
||||
return;
|
||||
}
|
||||
shareInfoService.shareInfo.revalidate();
|
||||
}, [shareInfoService]);
|
||||
}, [props.disabled, shareInfoService]);
|
||||
|
||||
const tooltip =
|
||||
props.tooltip ??
|
||||
(shared
|
||||
? t['com.affine.share-menu.option.link.readonly.description']()
|
||||
: t['com.affine.share-menu.option.link.no-access.description']());
|
||||
|
||||
return (
|
||||
<Tooltip
|
||||
content={
|
||||
shared
|
||||
? t['com.affine.share-menu.option.link.readonly.description']()
|
||||
: t['com.affine.share-menu.option.link.no-access.description']()
|
||||
}
|
||||
>
|
||||
<Button ref={ref} className={styles.button} variant="primary">
|
||||
<Tooltip content={tooltip}>
|
||||
<Button
|
||||
ref={ref}
|
||||
className={styles.button}
|
||||
variant="primary"
|
||||
disabled={props.disabled}
|
||||
>
|
||||
<div className={styles.buttonContainer}>
|
||||
{shared ? <PublishIcon fontSize={16} /> : <LockIcon fontSize={16} />}
|
||||
{t['com.affine.share-menu.shareButton']()}
|
||||
@@ -233,6 +243,13 @@ const DefaultShareButton = forwardRef(function DefaultShareButton(
|
||||
});
|
||||
|
||||
const LocalShareMenu = (props: ShareMenuProps) => {
|
||||
if (props.disabled) {
|
||||
return (
|
||||
<div data-testid="local-share-menu-button">
|
||||
<DefaultShareButton disabled tooltip={props.disabledReason} />
|
||||
</div>
|
||||
);
|
||||
}
|
||||
return (
|
||||
<Menu
|
||||
items={<ShareMenuContent {...props} />}
|
||||
@@ -254,6 +271,13 @@ const LocalShareMenu = (props: ShareMenuProps) => {
|
||||
};
|
||||
|
||||
const CloudShareMenu = (props: ShareMenuProps) => {
|
||||
if (props.disabled) {
|
||||
return (
|
||||
<div data-testid="cloud-share-menu-button">
|
||||
<DefaultShareButton disabled tooltip={props.disabledReason} />
|
||||
</div>
|
||||
);
|
||||
}
|
||||
return (
|
||||
<Menu
|
||||
items={<ShareMenuContent {...props} />}
|
||||
|
||||
@@ -16,6 +16,7 @@ import type { WorkspaceService } from '../../workspace';
|
||||
import type { WorkspaceShareSettingStore } from '../stores/share-setting';
|
||||
|
||||
type EnableAi = GetWorkspaceConfigQuery['workspace']['enableAi'];
|
||||
type EnableSharing = GetWorkspaceConfigQuery['workspace']['enableSharing'];
|
||||
type EnableUrlPreview =
|
||||
GetWorkspaceConfigQuery['workspace']['enableUrlPreview'];
|
||||
|
||||
@@ -23,6 +24,7 @@ const logger = new DebugLogger('affine:workspace-permission');
|
||||
|
||||
export class WorkspaceShareSetting extends Entity {
|
||||
enableAi$ = new LiveData<EnableAi | null>(null);
|
||||
enableSharing$ = new LiveData<EnableSharing | null>(null);
|
||||
enableUrlPreview$ = new LiveData<EnableUrlPreview | null>(null);
|
||||
inviteLink$ = new LiveData<InviteLink | null>(null);
|
||||
isLoading$ = new LiveData(false);
|
||||
@@ -48,12 +50,13 @@ export class WorkspaceShareSetting extends Entity {
|
||||
tap(value => {
|
||||
if (value) {
|
||||
this.enableAi$.next(value.enableAi);
|
||||
this.enableSharing$.next(value.enableSharing);
|
||||
this.enableUrlPreview$.next(value.enableUrlPreview);
|
||||
this.inviteLink$.next(value.inviteLink);
|
||||
}
|
||||
}),
|
||||
catchErrorInto(this.error$, error => {
|
||||
logger.error('Failed to fetch enableUrlPreview', error);
|
||||
logger.error('Failed to fetch workspace share settings', error);
|
||||
}),
|
||||
onStart(() => this.isLoading$.setValue(true)),
|
||||
onComplete(() => this.isLoading$.setValue(false))
|
||||
@@ -74,6 +77,14 @@ export class WorkspaceShareSetting extends Entity {
|
||||
await this.waitForRevalidation();
|
||||
}
|
||||
|
||||
async setEnableSharing(enableSharing: EnableSharing) {
|
||||
await this.store.updateWorkspaceEnableSharing(
|
||||
this.workspaceService.workspace.id,
|
||||
enableSharing
|
||||
);
|
||||
await this.waitForRevalidation();
|
||||
}
|
||||
|
||||
async setEnableAi(enableAi: EnableAi) {
|
||||
await this.store.updateWorkspaceEnableAi(
|
||||
this.workspaceService.workspace.id,
|
||||
|
||||
@@ -2,6 +2,7 @@ import type { WorkspaceServerService } from '@affine/core/modules/cloud';
|
||||
import {
|
||||
getWorkspaceConfigQuery,
|
||||
setEnableAiMutation,
|
||||
setEnableSharingMutation,
|
||||
setEnableUrlPreviewMutation,
|
||||
} from '@affine/graphql';
|
||||
import { Store } from '@toeverything/infra';
|
||||
@@ -47,6 +48,26 @@ export class WorkspaceShareSettingStore extends Store {
|
||||
});
|
||||
}
|
||||
|
||||
async updateWorkspaceEnableSharing(
|
||||
workspaceId: string,
|
||||
enableSharing: boolean,
|
||||
signal?: AbortSignal
|
||||
) {
|
||||
if (!this.workspaceServerService.server) {
|
||||
throw new Error('No Server');
|
||||
}
|
||||
await this.workspaceServerService.server.gql({
|
||||
query: setEnableSharingMutation,
|
||||
variables: {
|
||||
id: workspaceId,
|
||||
enableSharing,
|
||||
},
|
||||
context: {
|
||||
signal,
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
async updateWorkspaceEnableUrlPreview(
|
||||
workspaceId: string,
|
||||
enableUrlPreview: boolean,
|
||||
|
||||
@@ -6346,6 +6346,14 @@ export function useAFFiNEI18N(): {
|
||||
* `Always enable url preview`
|
||||
*/
|
||||
["com.affine.settings.workspace.sharing.url-preview.title"](): string;
|
||||
/**
|
||||
* `Control whether pages in this workspace can be shared publicly. Turn off to block new shares and external access for existing shares.`
|
||||
*/
|
||||
["com.affine.settings.workspace.sharing.workspace-sharing.description"](): string;
|
||||
/**
|
||||
* `Allow workspace page sharing`
|
||||
*/
|
||||
["com.affine.settings.workspace.sharing.workspace-sharing.title"](): string;
|
||||
/**
|
||||
* `AFFiNE AI`
|
||||
*/
|
||||
@@ -6605,6 +6613,10 @@ export function useAFFiNEI18N(): {
|
||||
* `Anyone can access this link`
|
||||
*/
|
||||
["com.affine.share-menu.option.link.readonly.description"](): string;
|
||||
/**
|
||||
* `Sharing for this workspace is turned off. Please contact an admin to enable it.`
|
||||
*/
|
||||
["com.affine.share-menu.workspace-sharing.disabled.tooltip"](): string;
|
||||
/**
|
||||
* `Can manage`
|
||||
*/
|
||||
|
||||
@@ -1591,6 +1591,8 @@
|
||||
"com.affine.settings.workspace.sharing.title": "Sharing",
|
||||
"com.affine.settings.workspace.sharing.url-preview.description": "Allow URL unfurling by Slack & other social apps, even if a doc is only accessible by workspace members.",
|
||||
"com.affine.settings.workspace.sharing.url-preview.title": "Always enable url preview",
|
||||
"com.affine.settings.workspace.sharing.workspace-sharing.description": "Control whether pages in this workspace can be shared publicly. Turn off to block new shares and external access for existing shares.",
|
||||
"com.affine.settings.workspace.sharing.workspace-sharing.title": "Allow workspace page sharing",
|
||||
"com.affine.settings.workspace.affine-ai.title": "AFFiNE AI",
|
||||
"com.affine.settings.workspace.affine-ai.label": "Allow AFFiNE AI Assistant",
|
||||
"com.affine.settings.workspace.affine-ai.description": "Allow workspace members to use AFFiNE AI features. This setting doesn't affect billing. Workspace members use AFFiNE AI through their personal accounts.",
|
||||
@@ -1655,6 +1657,7 @@
|
||||
"com.affine.share-menu.option.link.no-access.description": "Only workspace members can access this link",
|
||||
"com.affine.share-menu.option.link.readonly": "Read only",
|
||||
"com.affine.share-menu.option.link.readonly.description": "Anyone can access this link",
|
||||
"com.affine.share-menu.workspace-sharing.disabled.tooltip": "Sharing for this workspace is turned off. Please contact an admin to enable it.",
|
||||
"com.affine.share-menu.option.permission.can-manage": "Can manage",
|
||||
"com.affine.share-menu.option.permission.can-edit": "Can edit",
|
||||
"com.affine.share-menu.option.permission.can-read": "Can read",
|
||||
|
||||
@@ -1589,6 +1589,8 @@
|
||||
"com.affine.settings.workspace.sharing.title": "分享",
|
||||
"com.affine.settings.workspace.sharing.url-preview.description": "允许 Slack 和其他社交应用程序展开 URL,即使文档仅由工作区成员访问。",
|
||||
"com.affine.settings.workspace.sharing.url-preview.title": "始终启用 URL 预览",
|
||||
"com.affine.settings.workspace.sharing.workspace-sharing.description": "控制此工作区的页面是否允许公开分享。关闭后,禁止新的分享且现有分享外部无法访问。",
|
||||
"com.affine.settings.workspace.sharing.workspace-sharing.title": "允许工作区页面分享",
|
||||
"com.affine.settings.workspace.affine-ai.title": "AFFiNE AI",
|
||||
"com.affine.settings.workspace.affine-ai.label": "启用 AFFiNE AI 助手",
|
||||
"com.affine.settings.workspace.affine-ai.description": "允许工作区成员使用 AFFiNE AI 功能。此设置不会影响计费。工作区成员通过个人帐户使用 AFFiNE AI。",
|
||||
@@ -1653,6 +1655,7 @@
|
||||
"com.affine.share-menu.option.link.no-access.description": "只有此工作区的成员可以打开此链接。",
|
||||
"com.affine.share-menu.option.link.readonly": "只读",
|
||||
"com.affine.share-menu.option.link.readonly.description": "任何人可以访问该链接",
|
||||
"com.affine.share-menu.workspace-sharing.disabled.tooltip": "该工作区已禁用分享,请联系管理员开启。",
|
||||
"com.affine.share-menu.option.permission.can-manage": "可管理",
|
||||
"com.affine.share-menu.option.permission.can-edit": "可编辑",
|
||||
"com.affine.share-menu.option.permission.can-read": "可阅读",
|
||||
|
||||
@@ -1566,6 +1566,8 @@
|
||||
"com.affine.settings.workspace.sharing.title": "分享",
|
||||
"com.affine.settings.workspace.sharing.url-preview.description": "允許 Slack 和其他社交應用程序展開 URL,即使文件僅由工作區成員訪問。",
|
||||
"com.affine.settings.workspace.sharing.url-preview.title": "始終啟用 URL 預覽",
|
||||
"com.affine.settings.workspace.sharing.workspace-sharing.description": "控制此工作區的頁面是否允許公開分享。關閉後,禁止新的分享且现有分享外部無法訪問。",
|
||||
"com.affine.settings.workspace.sharing.workspace-sharing.title": "允許工作區頁面分享",
|
||||
"com.affine.settings.workspace.affine-ai.title": "AFFiNE AI",
|
||||
"com.affine.settings.workspace.affine-ai.label": "啟用 AFFiNE AI 助理",
|
||||
"com.affine.settings.workspace.affine-ai.description": "允許工作區成員使用 AFFiNE AI 功能。此設置不影響計費。工作區成員透過他們的個人帳號使用 AFFiNE AI。",
|
||||
@@ -1630,6 +1632,7 @@
|
||||
"com.affine.share-menu.option.link.no-access.description": "只有此工作區的成員可以打開此連結。",
|
||||
"com.affine.share-menu.option.link.readonly": "只讀",
|
||||
"com.affine.share-menu.option.link.readonly.description": "任何人可以訪問該連結",
|
||||
"com.affine.share-menu.workspace-sharing.disabled.tooltip": "此工作區已停用分享,請聯絡管理員開啟。",
|
||||
"com.affine.share-menu.option.permission.can-manage": "可管理",
|
||||
"com.affine.share-menu.option.permission.can-edit": "可編輯",
|
||||
"com.affine.share-menu.option.permission.can-read": "可閱讀",
|
||||
|
||||
Reference in New Issue
Block a user