Skip to content

Commit

Permalink
[MS] Replaced workspaces by recent workspaces in sidebar
Browse files Browse the repository at this point in the history
  • Loading branch information
Max-7 committed Jan 14, 2025
1 parent 5e5e1cc commit 82fa7e6
Show file tree
Hide file tree
Showing 12 changed files with 179 additions and 72 deletions.
2 changes: 1 addition & 1 deletion client/src/components/sidebar/SidebarRecentFileItem.vue
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@
<script setup lang="ts">
import { IonItem, IonText, IonIcon } from '@ionic/vue';
import { close } from 'ionicons/icons';
import { RecentFile } from '@/services/recentFiles';
import { RecentFile } from '@/services/recentDocuments';

defineProps<{
file: RecentFile;
Expand Down
2 changes: 1 addition & 1 deletion client/src/components/sidebar/SidebarWorkspaceItem.vue
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@

<script setup lang="ts">
import { IonItem, IonText, IonIcon } from '@ionic/vue';
import { WorkspaceInfo, WorkspaceHandle } from '@/parsec';
import { WorkspaceHandle, WorkspaceInfo } from '@/parsec';
import { ellipsisHorizontal } from 'ionicons/icons';
import { currentRouteIsWorkspaceRoute } from '@/router';
import { onMounted, onBeforeUnmount, ref } from 'vue';
Expand Down
1 change: 1 addition & 0 deletions client/src/locales/en-US.json
Original file line number Diff line number Diff line change
Expand Up @@ -698,6 +698,7 @@
},
"SideMenu": {
"workspaces": "Workspaces",
"recentWorkspaces": "Recent workspaces",
"favorites": "Favorites",
"noWorkspace": "No workspaces",
"users": "Users",
Expand Down
1 change: 1 addition & 0 deletions client/src/locales/fr-FR.json
Original file line number Diff line number Diff line change
Expand Up @@ -698,6 +698,7 @@
},
"SideMenu": {
"workspaces": "Espaces de travail",
"recentWorkspaces": "Espaces récents",
"favorites": "Favoris",
"noWorkspace": "Aucun espace de travail",
"users": "Utilisateurs",
Expand Down
8 changes: 6 additions & 2 deletions client/src/parsec/workspace.ts
Original file line number Diff line number Diff line change
Expand Up @@ -68,8 +68,12 @@ export async function initializeWorkspace(
return startedWorkspaceResult;
}

export async function listWorkspaces(): Promise<Result<Array<WorkspaceInfo>, ClientListWorkspacesError>> {
const handle = getParsecHandle();
export async function listWorkspaces(
handle: ConnectionHandle | null = null,
): Promise<Result<Array<WorkspaceInfo>, ClientListWorkspacesError>> {
if (!handle) {
handle = getParsecHandle();
}

if (handle !== null && !needsMocks()) {
const result = await libparsec.clientListWorkspaces(handle);
Expand Down
2 changes: 2 additions & 0 deletions client/src/router/navigation.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
import { ConnectionHandle, EntryName, WorkspaceHandle } from '@/parsec';
import { getConnectionHandle } from '@/router/params';
import { ClientAreaQuery, Query, RouteBackup, Routes, getCurrentRoute, getRouter } from '@/router/types';
import { recentDocumentManager } from '@/services/recentDocuments';
import { Base64 } from 'megashark-lib';
import { LocationQueryRaw, RouteParamsRaw } from 'vue-router';

Expand Down Expand Up @@ -95,6 +96,7 @@ export async function switchOrganization(handle: ConnectionHandle | null, backup
window.electronAPI.log('error', 'Trying to switch to an organization for which we have no backup information');
return;
}
recentDocumentManager.resetHistory();
const backup = routesBackup[backupIndex];
try {
await navigateTo(Routes.Loading, { skipHandle: true, replace: true, query: { loginInfo: Base64.fromObject(backup) } });
Expand Down
6 changes: 3 additions & 3 deletions client/src/services/fileOpener.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import { detectFileContentType, FileContentType } from '@/common/fileTypes';
import { entryStat, EntryStat, entryStatAt, FsPath, getSystemPath, isDesktop, WorkspaceHandle, WorkspaceHistoryEntryStat } from '@/parsec';
import { navigateTo, Routes } from '@/router';
import { Information, InformationLevel, InformationManager, PresentationMode } from '@/services/informationManager';
import { recentFileManager } from '@/services/recentFiles';
import { recentDocumentManager } from '@/services/recentDocuments';
import { DateTime } from 'luxon';
import { Base64, openSpinnerModal } from 'megashark-lib';

Expand All @@ -21,7 +21,7 @@ async function openWithSystem(
informationManager: InformationManager,
): Promise<void> {
if (entry.isFile()) {
recentFileManager.addFile({
recentDocumentManager.addFile({
entryId: entry.id,
path: entry.path,
workspaceHandle: workspaceHandle,
Expand Down Expand Up @@ -113,7 +113,7 @@ async function openPath(
return;
}

recentFileManager.addFile({
recentDocumentManager.addFile({
entryId: entry.id,
path: entry.path,
workspaceHandle: workspaceHandle,
Expand Down
135 changes: 135 additions & 0 deletions client/src/services/recentDocuments.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,135 @@
// Parsec Cloud (https://parsec.cloud) Copyright (c) BUSL-1.1 2016-present Scille SAS

import { DetectedFileType } from '@/common/fileTypes';
import {
ConnectionHandle,
EntryID,
EntryName,
FsPath,
getClientInfo,
listWorkspaces,
UserID,
WorkspaceHandle,
WorkspaceID,
WorkspaceInfo,
} from '@/parsec';
import { StorageManager } from '@/services/storageManager';
import { Ref, ref } from 'vue';

interface RecentFile {
entryId: EntryID;
workspaceHandle: WorkspaceHandle;
path: FsPath;
name: EntryName;
contentType?: DetectedFileType;
}

type RecentWorkspace = WorkspaceInfo;

const FILE_HISTORY_SIZE = 5;
const WORKSPACE_HISTORY_SIZE = 5;

interface RecentDocumentStorageData {
workspaces: Array<WorkspaceID>;
}

class RecentDocumentManager {
files: Ref<Array<RecentFile>> = ref([]);
workspaces: Ref<Array<RecentWorkspace>> = ref([]);

constructor() {
this.files.value = new Array<RecentFile>();
this.workspaces.value = new Array<RecentWorkspace>();
}

private _getStorageDataKey(userId: UserID): string {
return `recentDocuments_${userId}`;
}

async loadFromStorage(storage: StorageManager, handle: ConnectionHandle | null = null): Promise<void> {
const clientInfoResult = await getClientInfo(handle);
if (!clientInfoResult.ok) {
window.electronAPI.log('error', `Failed to load recent workspaces: ${JSON.stringify(clientInfoResult.error)}`);
return;
}
const dataKey = this._getStorageDataKey(clientInfoResult.value.userId);
const storedData = await storage.retrieveComponentData<RecentDocumentStorageData>(dataKey, { workspaces: [] });
if (!storedData || !storedData.workspaces) {
return;
}
const workspacesResult = await listWorkspaces(handle);
if (!workspacesResult.ok) {
window.electronAPI.log('error', `Failed to load recent workspaces: ${JSON.stringify(workspacesResult.error)}`);
return;
}
for (const workspace of workspacesResult.value) {
if (storedData.workspaces.includes(workspace.id)) {
this.addWorkspace(workspace);
}
}
console.log('Loaded', this.workspaces.value);
}

async saveToStorage(storage: StorageManager): Promise<void> {
const clientInfoResult = await getClientInfo();
if (!clientInfoResult.ok) {
window.electronAPI.log('error', `Failed to save recent workspaces: ${JSON.stringify(clientInfoResult.error)}`);
return;
}
const dataKey = this._getStorageDataKey(clientInfoResult.value.userId);
await storage.storeComponentData<RecentDocumentStorageData>(dataKey, {
workspaces: this.workspaces.value.map((workspace) => workspace.id),
});
}

addFile(file: RecentFile): void {
const exists = this.files.value.find((item) => item.entryId === file.entryId) !== undefined;
if (exists) {
return;
}
if (this.files.value.unshift(file) > FILE_HISTORY_SIZE) {
this.files.value.pop();
}
}

addWorkspace(workspace: RecentWorkspace): void {
const exists = this.workspaces.value.find((item) => item.id === workspace.id) !== undefined;
if (exists) {
return;
}
if (this.workspaces.value.unshift(workspace) > WORKSPACE_HISTORY_SIZE) {
this.workspaces.value.pop();
}
}

removeFile(file: RecentFile): void {
const index = this.files.value.findIndex((item) => item.entryId === file.entryId);
if (index !== -1) {
this.files.value.splice(index, 1);
}
}

removeWorkspace(workspace: RecentWorkspace): void {
const index = this.workspaces.value.findIndex((item) => item.id === workspace.id);
if (index !== -1) {
this.workspaces.value.splice(index, 1);
}
}

resetHistory(): void {
this.files.value = new Array<RecentFile>();
this.workspaces.value = new Array<RecentWorkspace>();
}

getFiles(): Array<RecentFile> {
return this.files.value;
}

getWorkspaces(): Array<RecentWorkspace> {
return this.workspaces.value;
}
}

const recentDocumentManager = new RecentDocumentManager();

export { recentDocumentManager, RecentFile, RecentWorkspace };
52 changes: 0 additions & 52 deletions client/src/services/recentFiles.ts

This file was deleted.

5 changes: 5 additions & 0 deletions client/src/views/layouts/ConnectedLayout.vue
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ import useUploadMenu from '@/services/fileUploadMenu';
import { MsModalResult, openSpinnerModal } from 'megashark-lib';
import { DateTime } from 'luxon';
import { StorageManagerKey, StorageManager } from '@/services/storageManager';
import { recentDocumentManager } from '@/services/recentDocuments';

const injectionProvider: InjectionProvider = inject(InjectionProviderKey)!;
const storageManager: StorageManager = inject(StorageManagerKey)!;
Expand Down Expand Up @@ -64,6 +65,9 @@ onMounted(async () => {
},
);

recentDocumentManager.resetHistory();
await recentDocumentManager.loadFromStorage(storageManager, handle);

initialized.value = true;

const connInfo = getConnectionInfo();
Expand Down Expand Up @@ -133,6 +137,7 @@ async function logout(): Promise<void> {
window.electronAPI.log('error', `Error when logging out: ${JSON.stringify(logoutResult.error)}`);
}
}
recentDocumentManager.resetHistory();

await modal.dismiss();
await navigateTo(Routes.Home, { replace: true, skipHandle: true });
Expand Down
23 changes: 10 additions & 13 deletions client/src/views/sidebar-menu/SidebarMenuPage.vue
Original file line number Diff line number Diff line change
Expand Up @@ -182,7 +182,8 @@

<!-- list of workspaces -->
<sidebar-menu-list
title="SideMenu.workspaces"
v-if="recentDocumentManager.getWorkspaces().length > 0"
title="SideMenu.recentWorkspaces"
:icon="business"
class="workspaces"
v-model:is-content-visible="workspacesMenuVisible"
Expand All @@ -195,7 +196,7 @@
{{ $msTranslate('SideMenu.noWorkspace') }}
</ion-text>
<sidebar-workspace-item
v-for="workspace in nonFavoriteWorkspaces"
v-for="workspace in recentDocumentManager.getWorkspaces()"
:workspace="workspace"
:key="workspace.id"
@workspace-clicked="goToWorkspace"
Expand All @@ -208,7 +209,7 @@

<div
class="list-sidebar-divider"
v-if="recentFileManager.getFiles().length > 0 && !currentRouteIsOrganizationManagementRoute()"
v-if="recentDocumentManager.getFiles().length > 0 && !currentRouteIsOrganizationManagementRoute()"
/>

<!-- last opened files -->
Expand All @@ -219,12 +220,12 @@
<sidebar-menu-list
title="SideMenu.recentDocuments"
:icon="documentIcon"
v-show="recentFileManager.getFiles().length > 0"
v-show="recentDocumentManager.getFiles().length > 0"
v-model:is-content-visible="recentFilesMenuVisible"
@update:is-content-visible="onRecentFilesMenuVisibilityChanged"
>
<sidebar-recent-file-item
v-for="file in recentFileManager.getFiles()"
v-for="file in recentDocumentManager.getFiles()"
:file="file"
:key="file.entryId"
@file-clicked="openRecentFile"
Expand Down Expand Up @@ -383,7 +384,7 @@ import {
} from 'ionicons/icons';
import { Ref, computed, inject, onMounted, onUnmounted, ref, watch } from 'vue';
import { Duration } from 'luxon';
import { recentFileManager, RecentFile } from '@/services/recentFiles';
import { recentDocumentManager, RecentFile } from '@/services/recentDocuments';
import { openPath } from '@/services/fileOpener';
import { SIDEBAR_MENU_DATA_KEY, SidebarDefaultData, SidebarSavedData } from '@/views/sidebar-menu/utils';
import { FileContentType } from '@/common/fileTypes';
Expand Down Expand Up @@ -516,7 +517,7 @@ onMounted(async () => {
// Adds fake files by default in dev mode
// to make sure we keep the feature in mind
if (needsMocks()) {
recentFileManager.addFile({
recentDocumentManager.addFile({
entryId: crypto.randomUUID().toString(),
workspaceHandle: 1337,
path: '/a/b/File_Fake image.png',
Expand All @@ -527,7 +528,7 @@ onMounted(async () => {
mimeType: 'image/png',
},
});
recentFileManager.addFile({
recentDocumentManager.addFile({
entryId: crypto.randomUUID().toString(),
workspaceHandle: 1337,
path: '/a/b/File_Fake PDF document.pdf',
Expand Down Expand Up @@ -569,10 +570,6 @@ const favoritesWorkspaces = computed(() => {
});
});

const nonFavoriteWorkspaces = computed(() => {
return workspaces.value.filter((workspace: WorkspaceInfo) => !favorites.value.includes(workspace.id));
});

function onMove(detail: GestureDetail): void {
if (detail.currentX < MIN_WIDTH) {
computedWidth.value = MIN_WIDTH;
Expand Down Expand Up @@ -610,7 +607,7 @@ async function openRecentFile(file: RecentFile): Promise<void> {
}

async function removeRecentFile(file: RecentFile): Promise<void> {
recentFileManager.removeFile(file);
recentDocumentManager.removeFile(file);
}

async function onWorkspacesMenuVisibilityChanged(visible: boolean): Promise<void> {
Expand Down
Loading

0 comments on commit 82fa7e6

Please sign in to comment.