fix: workspace storage settings issues (#3055)

(cherry picked from commit 00ce086e79)
This commit is contained in:
Peng Xiao
2023-07-06 20:48:20 +08:00
committed by Alex Yang
parent 6d552ce85e
commit 424580971e
13 changed files with 105 additions and 40 deletions

View File

@@ -10,6 +10,9 @@ yarn -T run build:infra
# generate prisma client type # generate prisma client type
yarn workspace @affine/server prisma generate yarn workspace @affine/server prisma generate
# generate i18n
yarn i18n-codegen gen
# lint staged files # lint staged files
yarn exec lint-staged yarn exec lint-staged

View File

@@ -17,11 +17,13 @@ test('check workspace has a DB file', async ({ appInfo, workspace }) => {
expect(await fs.exists(dbPath)).toBe(true); expect(await fs.exists(dbPath)).toBe(true);
}); });
test.skip('move workspace db file', async ({ page, appInfo, workspace }) => { test('move workspace db file', async ({ page, appInfo, workspace }) => {
const w = await workspace.current(); const w = await workspace.current();
const settingButton = page.getByTestId('slider-bar-workspace-setting-button'); await page.getByTestId('slider-bar-workspace-setting-button').click();
// goto settings await expect(page.getByTestId('setting-modal')).toBeVisible();
await settingButton.click();
// goto workspace setting
await page.getByTestId('workspace-list-item').click();
const tmpPath = path.join(appInfo.sessionData, w.id + '-tmp-dir'); const tmpPath = path.join(appInfo.sessionData, w.id + '-tmp-dir');
@@ -42,21 +44,24 @@ test.skip('move workspace db file', async ({ page, appInfo, workspace }) => {
expect(files.some(f => f.endsWith('.affine'))).toBe(true); expect(files.some(f => f.endsWith('.affine'))).toBe(true);
}); });
test.skip('export then add', async ({ page, appInfo, workspace }) => { test('export then add', async ({ page, appInfo, workspace }) => {
const w = await workspace.current(); const w = await workspace.current();
const settingButton = page.getByTestId('slider-bar-workspace-setting-button');
// goto settings await page.getByTestId('slider-bar-workspace-setting-button').click();
await settingButton.click(); await expect(page.getByTestId('setting-modal')).toBeVisible();
const originalId = w.id; const originalId = w.id;
const newWorkspaceName = 'new-test-name'; const newWorkspaceName = 'new-test-name';
// goto workspace setting
await page.getByTestId('workspace-list-item').click();
// change workspace name // change workspace name
await page.getByTestId('workspace-name-input').fill(newWorkspaceName); await page.getByTestId('workspace-name-input').fill(newWorkspaceName);
await page.getByTestId('save-workspace-name').click(); await page.getByTestId('save-workspace-name').click();
await page.waitForSelector('text="Update workspace name success"'); await page.waitForSelector('text="Update workspace name success"');
await page.click('[data-tab-key="export"]'); await page.waitForTimeout(500);
const tmpPath = path.join(appInfo.sessionData, w.id + '-tmp.db'); const tmpPath = path.join(appInfo.sessionData, w.id + '-tmp.db');
@@ -73,10 +78,11 @@ test.skip('export then add', async ({ page, appInfo, workspace }) => {
expect(await fs.exists(tmpPath)).toBe(true); expect(await fs.exists(tmpPath)).toBe(true);
await page.getByTestId('modal-close-button').click();
// add workspace // add workspace
// we are reusing the same db file so that we don't need to maintain one // we are reusing the same db file so that we don't need to maintain one
// in the codebase // in the codebase
await page.getByTestId('current-workspace').click(); await page.getByTestId('current-workspace').click();
await page.getByTestId('add-or-new-workspace').click(); await page.getByTestId('add-or-new-workspace').click();

View File

@@ -52,9 +52,11 @@ export class WorkspaceSQLiteDB extends BaseSQLiteAdapter {
}; };
setupListener(docId?: string) { setupListener(docId?: string) {
logger.debug('WorkspaceSQLiteDB: setupListener', this.workspaceId, docId);
const doc = this.getDoc(docId); const doc = this.getDoc(docId);
if (doc) { if (doc) {
const onUpdate = async (update: Uint8Array, origin: YOrigin) => { const onUpdate = async (update: Uint8Array, origin: YOrigin) => {
logger.debug('onUpdate', this.workspaceId, docId, update.length);
const insertRows = [{ data: update, docId }]; const insertRows = [{ data: update, docId }];
if (origin === 'renderer') { if (origin === 'renderer') {
await this.addUpdateToSQLite(insertRows); await this.addUpdateToSQLite(insertRows);
@@ -68,7 +70,11 @@ export class WorkspaceSQLiteDB extends BaseSQLiteAdapter {
logger.debug('external update', this.workspaceId); logger.debug('external update', this.workspaceId);
} }
}; };
doc.subdocs.forEach(subdoc => {
this.setupListener(subdoc.guid);
});
const onSubdocs = ({ added }: { added: Set<Y.Doc> }) => { const onSubdocs = ({ added }: { added: Set<Y.Doc> }) => {
logger.info('onSubdocs', this.workspaceId, docId, added);
added.forEach(subdoc => { added.forEach(subdoc => {
this.setupListener(subdoc.guid); this.setupListener(subdoc.guid);
}); });

View File

@@ -1,18 +1,20 @@
import { Button, toast } from '@affine/component'; import { Button, FlexWrapper, toast, Tooltip } from '@affine/component';
import { SettingRow } from '@affine/component/setting-components'; import { SettingRow } from '@affine/component/setting-components';
import { useAFFiNEI18N } from '@affine/i18n/hooks'; import { useAFFiNEI18N } from '@affine/i18n/hooks';
import { useMemo } from 'react';
import { type FC, useCallback, useEffect, useState } from 'react'; import { type FC, useCallback, useEffect, useState } from 'react';
import type { AffineOfficialWorkspace } from '../../../shared'; import type { AffineOfficialWorkspace } from '../../../shared';
import * as style from './style.css';
const useShowOpenDBFile = (workspaceId: string) => { const useDBFileSecondaryPath = (workspaceId: string) => {
const [show, setShow] = useState(false); const [path, setPath] = useState<string | undefined>(undefined);
useEffect(() => { useEffect(() => {
if (window.apis && window.events && environment.isDesktop) { if (window.apis && window.events && environment.isDesktop) {
window.apis?.workspace window.apis?.workspace
.getMeta(workspaceId) .getMeta(workspaceId)
.then(meta => { .then(meta => {
setShow(!!meta.secondaryDBPath); setPath(meta.secondaryDBPath);
}) })
.catch(err => { .catch(err => {
console.error(err); console.error(err);
@@ -20,12 +22,12 @@ const useShowOpenDBFile = (workspaceId: string) => {
return window.events.workspace.onMetaChange((newMeta: any) => { return window.events.workspace.onMetaChange((newMeta: any) => {
if (newMeta.workspaceId === workspaceId) { if (newMeta.workspaceId === workspaceId) {
const meta = newMeta.meta; const meta = newMeta.meta;
setShow(!!meta.secondaryDBPath); setPath(meta.secondaryDBPath);
} }
}); });
} }
}, [workspaceId]); }, [workspaceId]);
return show; return path;
}; };
export const StoragePanel: FC<{ export const StoragePanel: FC<{
@@ -33,7 +35,7 @@ export const StoragePanel: FC<{
}> = ({ workspace }) => { }> = ({ workspace }) => {
const workspaceId = workspace.id; const workspaceId = workspace.id;
const t = useAFFiNEI18N(); const t = useAFFiNEI18N();
const showOpenFolder = useShowOpenDBFile(workspaceId); const secondaryPath = useDBFileSecondaryPath(workspaceId);
const [moveToInProgress, setMoveToInProgress] = useState<boolean>(false); const [moveToInProgress, setMoveToInProgress] = useState<boolean>(false);
const onRevealDBFile = useCallback(() => { const onRevealDBFile = useCallback(() => {
@@ -65,23 +67,57 @@ export const StoragePanel: FC<{
}); });
}, [moveToInProgress, t, workspaceId]); }, [moveToInProgress, t, workspaceId]);
if (!showOpenFolder) { const rowContent = useMemo(
return null; () =>
} secondaryPath ? (
<FlexWrapper justifyContent="space-between">
<Tooltip
zIndex={1000}
content={t['com.affine.settings.storage.db-location.change-hint']()}
placement="top-start"
>
<Button
data-testid="move-folder"
className={style.urlButton}
size="middle"
onClick={handleMoveTo}
>
{secondaryPath}
</Button>
</Tooltip>
<Button
size="small"
data-testid="reveal-folder"
data-disabled={moveToInProgress}
onClick={onRevealDBFile}
>
{t['Open folder']()}
</Button>
</FlexWrapper>
) : (
<Button
size="small"
data-testid="move-folder"
data-disabled={moveToInProgress}
onClick={handleMoveTo}
>
{t['Move folder']()}
</Button>
),
[handleMoveTo, moveToInProgress, onRevealDBFile, secondaryPath, t]
);
return ( return (
<SettingRow <SettingRow
name={t['Storage']()} name={t['Storage']()}
desc={t['Storage Folder Hint']()} desc={t[
spreadCol={false} secondaryPath
? 'com.affine.settings.storage.description-alt'
: 'com.affine.settings.storage.description'
]()}
spreadCol={!secondaryPath}
> >
<Button {rowContent}
data-testid="move-folder"
data-disabled={moveToInProgress}
onClick={handleMoveTo}
>
{t['Move folder']()}
</Button>
<Button onClick={onRevealDBFile}>{t['Open folder']()}</Button>
</SettingRow> </SettingRow>
); );
}; };

View File

@@ -43,12 +43,15 @@ globalStyle(`${avatarWrapper} .camera-icon-wrapper`, {
export const urlButton = style({ export const urlButton = style({
width: 'calc(100% - 64px - 15px)', width: 'calc(100% - 64px - 15px)',
justifyContent: 'left',
textAlign: 'left',
}); });
globalStyle(`${urlButton} span`, { globalStyle(`${urlButton} span`, {
width: '100%', width: '100%',
overflow: 'hidden', overflow: 'hidden',
textOverflow: 'ellipsis', textOverflow: 'ellipsis',
whiteSpace: 'nowrap', whiteSpace: 'nowrap',
fontWeight: '500',
}); });
export const fakeWrapper = style({ export const fakeWrapper = style({

View File

@@ -125,6 +125,7 @@ const WorkspaceListItem = ({
className={clsx(sidebarSelectItem, { active: isActive })} className={clsx(sidebarSelectItem, { active: isActive })}
title={workspaceName} title={workspaceName}
onClick={onClick} onClick={onClick}
data-testid="workspace-list-item"
> >
<WorkspaceAvatar size={14} workspace={workspace} className="icon" /> <WorkspaceAvatar size={14} workspace={workspace} className="icon" />
<span className="setting-name">{workspaceName}</span> <span className="setting-name">{workspaceName}</span>

View File

@@ -184,7 +184,11 @@ export const RootAppSidebar = ({
</RouteMenuLinkItem> </RouteMenuLinkItem>
)} )}
{runtimeConfig.enableNewSettingModal ? ( {runtimeConfig.enableNewSettingModal ? (
<MenuItem icon={<SettingsIcon />} onClick={onOpenSettingModal}> <MenuItem
data-testid="slider-bar-workspace-setting-button"
icon={<SettingsIcon />}
onClick={onOpenSettingModal}
>
<span data-testid="settings-modal-trigger"> <span data-testid="settings-modal-trigger">
{t['Settings']()} {t['Settings']()}
</span> </span>

View File

@@ -27,11 +27,11 @@ export const ModalCloseButton = ({
...props ...props
}: ModalCloseButtonProps) => { }: ModalCloseButtonProps) => {
return absolute ? ( return absolute ? (
<StyledIconButton {...props}> <StyledIconButton data-testid="modal-close-button" {...props}>
<CloseIcon /> <CloseIcon />
</StyledIconButton> </StyledIconButton>
) : ( ) : (
<IconButton {...props}> <IconButton data-testid="modal-close-button" {...props}>
<CloseIcon /> <CloseIcon />
</IconButton> </IconButton>
); );

View File

@@ -280,7 +280,8 @@
"UNKNOWN_ERROR": "Unbekannter Fehler", "UNKNOWN_ERROR": "Unbekannter Fehler",
"Open folder hint": "Prüfe, wo sich der Speicherordner befindet.", "Open folder hint": "Prüfe, wo sich der Speicherordner befindet.",
"Storage Folder": "Speicherordner", "Storage Folder": "Speicherordner",
"Storage Folder Hint": "Speicherort überprüfen oder ändern.", "com.affine.settings.storage.description": "Speicherort überprüfen oder ändern.",
"com.affine.settings.storage.description-alt": "Speicherort überprüfen oder ändern.",
"Sync across devices with AFFiNE Cloud": "Geräteübergreifende Synchronisierung mit AFFiNE Cloud", "Sync across devices with AFFiNE Cloud": "Geräteübergreifende Synchronisierung mit AFFiNE Cloud",
"Name Your Workspace": "Workspace benennen", "Name Your Workspace": "Workspace benennen",
"Update Available": "Update verfügbar", "Update Available": "Update verfügbar",

View File

@@ -23,6 +23,9 @@
"com.affine.settings.about.update.download.message": "Automatically download updates (to this device).", "com.affine.settings.about.update.download.message": "Automatically download updates (to this device).",
"com.affine.settings.about.update.check.message": "Automatically check for new updates periodically.", "com.affine.settings.about.update.check.message": "Automatically check for new updates periodically.",
"com.affine.settings.about.message": "Information about AFFiNE", "com.affine.settings.about.message": "Information about AFFiNE",
"com.affine.settings.storage.description": "Check or change storage location",
"com.affine.settings.storage.description-alt": "Check or change storage location. Click path to edit location.",
"com.affine.settings.storage.db-location.change-hint": "Click to move storage location.",
"com.affine.pageMode": "Page Mode", "com.affine.pageMode": "Page Mode",
"com.affine.edgelessMode": "Edgeless Mode", "com.affine.edgelessMode": "Edgeless Mode",
"com.affine.onboarding.title1": "Hyper merged whiteboard and docs", "com.affine.onboarding.title1": "Hyper merged whiteboard and docs",
@@ -281,7 +284,6 @@
"Loading Page": "Loading Page", "Loading Page": "Loading Page",
"Favorite pages for easy access": "Favourite pages for easy access", "Favorite pages for easy access": "Favourite pages for easy access",
"emptySharedPages": "Shared pages will appear here.", "emptySharedPages": "Shared pages will appear here.",
"Storage Folder Hint": "Check or change storage location. Click path to edit location.",
"You cannot delete the last workspace": "You cannot delete the last workspace", "You cannot delete the last workspace": "You cannot delete the last workspace",
"Synced with AFFiNE Cloud": "Synced with AFFiNE Cloud", "Synced with AFFiNE Cloud": "Synced with AFFiNE Cloud",
"Recent": "Recent", "Recent": "Recent",
@@ -305,8 +307,8 @@
"DB_FILE_ALREADY_LOADED": "Database file already loaded", "DB_FILE_ALREADY_LOADED": "Database file already loaded",
"UNKNOWN_ERROR": "Unknown error", "UNKNOWN_ERROR": "Unknown error",
"Default Location": "Default Location", "Default Location": "Default Location",
"Open folder": "Open folder", "Open folder": "Open",
"Move folder": "Move folder", "Move folder": "Move",
"Set database location": "Set database location", "Set database location": "Set database location",
"Move folder hint": "Select a new storage location.", "Move folder hint": "Select a new storage location.",
"Storage Folder": "Storage Folder", "Storage Folder": "Storage Folder",

View File

@@ -298,7 +298,8 @@
"UNKNOWN_ERROR": "Erreur inconnue", "UNKNOWN_ERROR": "Erreur inconnue",
"Restart Install Client Update": "Redémarrez pour installer la mise à jour", "Restart Install Client Update": "Redémarrez pour installer la mise à jour",
"Save": "Enregistrer", "Save": "Enregistrer",
"Storage Folder Hint": "Vérifier ou changer l'emplacement du lieu de stockage", "com.affine.settings.storage.description": "Vérifier ou changer l'emplacement du lieu de stockage",
"com.affine.settings.storage.description-alt": "Vérifier ou changer l'emplacement du lieu de stockage",
"Use on current device only": "Utiliser seulement sur l'appareil actuel", "Use on current device only": "Utiliser seulement sur l'appareil actuel",
"Default db location hint": "Par défaut, elle sera enregistrée sous {{location}}", "Default db location hint": "Par défaut, elle sera enregistrée sous {{location}}",
"FILE_ALREADY_EXISTS": "Fichier déjà existant", "FILE_ALREADY_EXISTS": "Fichier déjà existant",

View File

@@ -212,7 +212,8 @@
"Sync across devices with AFFiNE Cloud": "AFFiNEクラウドでデバイス間を同期する", "Sync across devices with AFFiNE Cloud": "AFFiNEクラウドでデバイス間を同期する",
"Stop publishing": "公開をやめる", "Stop publishing": "公開をやめる",
"Storage Folder": "ストレージフォルダー", "Storage Folder": "ストレージフォルダー",
"Storage Folder Hint": "保存場所を確認または変更する", "com.affine.settings.storage.description": "保存場所を確認または変更する",
"com.affine.settings.storage.description-alt": "保存場所を確認または変更する",
"Upload": "アップロード", "Upload": "アップロード",
"Update Available": "アップデート可能", "Update Available": "アップデート可能",
"Update workspace name success": "ワークスペース名の更新に成功", "Update workspace name success": "ワークスペース名の更新に成功",

View File

@@ -377,7 +377,8 @@
"Shared Pages Description": "公开分享页面需要 AFFiNE Cloud 服务。", "Shared Pages Description": "公开分享页面需要 AFFiNE Cloud 服务。",
"Shared Pages In Public Workspace Description": "整个工作区已在网络上发布,可以通过<1>工作区设置</1>进行编辑。", "Shared Pages In Public Workspace Description": "整个工作区已在网络上发布,可以通过<1>工作区设置</1>进行编辑。",
"Storage Folder": "存储文件夹", "Storage Folder": "存储文件夹",
"Storage Folder Hint": "检查或更改存储位置。", "com.affine.settings.storage.description": "检查或更改存储位置。",
"com.affine.settings.storage.description-alt": "检查或更改存储位置。点击路径调整存储位置。",
"Successfully deleted": "成功删除。", "Successfully deleted": "成功删除。",
"Sync across devices with AFFiNE Cloud": "使用 AFFiNE Cloud 在多个设备间进行同步", "Sync across devices with AFFiNE Cloud": "使用 AFFiNE Cloud 在多个设备间进行同步",
"Synced with AFFiNE Cloud": "AFFiNE Cloud 同步完成", "Synced with AFFiNE Cloud": "AFFiNE Cloud 同步完成",