Skip to content

Commit cdaed6d

Browse files
fabienSvtrMax-7
andcommitted
[MS] Update workspace context menu to hide/unhide "Mount" and "Unmount" based on workspace hidden state (#11686)
Co-authored-by: fabienSvstr <fabien.sevestre@scille.fr> Co-authored-by: Maxime Grandcolas <maxime.grandcolas@scille.fr>
1 parent eb3c181 commit cdaed6d

File tree

14 files changed

+379
-21
lines changed

14 files changed

+379
-21
lines changed

client/src/components/workspaces/WorkspaceCard.vue

Lines changed: 46 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,10 @@
33
<template>
44
<div
55
class="workspace-card-item ion-no-padding"
6-
:class="{ 'workspace-hovered': isHovered || menuOpened }"
6+
:class="{
7+
'workspace-hovered': isHovered || menuOpened,
8+
'workspace-card-item--hidden': isHidden,
9+
}"
710
@click="$emit('click', workspace, $event)"
811
@mouseenter="isHovered = true"
912
@mouseleave="isHovered = false"
@@ -44,6 +47,17 @@
4447
>
4548
{{ $msTranslate(formatFileSize(workspace.size)) }}
4649
</ion-text>
50+
51+
<div
52+
class="workspace-hidden subtitles-sm"
53+
v-if="isHidden"
54+
>
55+
<ion-icon
56+
class="cloud-overlay"
57+
:icon="eyeOff"
58+
/>
59+
<ion-text>{{ $msTranslate('WorkspacesPage.Workspace.hidden') }}</ion-text>
60+
</div>
4761
</div>
4862
</div>
4963
<div class="workspace-card-bottom">
@@ -81,7 +95,7 @@ import { formatFileSize } from '@/common/file';
8195
import { WorkspaceRoleTag } from '@/components/workspaces';
8296
import { UserProfile, WorkspaceInfo } from '@/parsec';
8397
import { IonIcon, IonText } from '@ionic/vue';
84-
import { cloudDone, cloudOffline, ellipsisHorizontal, shareSocial, star } from 'ionicons/icons';
98+
import { cloudDone, cloudOffline, ellipsisHorizontal, eyeOff, shareSocial, star } from 'ionicons/icons';
8599
import { formatTimeSince } from 'megashark-lib';
86100
import { ref } from 'vue';
87101
@@ -92,6 +106,7 @@ const props = defineProps<{
92106
workspace: WorkspaceInfo;
93107
clientProfile: UserProfile;
94108
isFavorite: boolean;
109+
isHidden: boolean;
95110
}>();
96111
97112
const emits = defineEmits<{
@@ -180,6 +195,7 @@ async function onOptionsClick(event: Event): Promise<void> {
180195
flex-direction: column;
181196
gap: 0.75rem;
182197
overflow: hidden;
198+
position: relative;
183199
184200
&__title {
185201
color: var(--parsec-color-light-primary-900);
@@ -188,6 +204,8 @@ async function onOptionsClick(event: Event): Promise<void> {
188204
overflow: hidden;
189205
text-overflow: ellipsis;
190206
white-space: nowrap;
207+
align-items: center;
208+
gap: 0.5rem;
191209
margin-right: 1.125rem;
192210
193211
ion-text {
@@ -221,6 +239,21 @@ async function onOptionsClick(event: Event): Promise<void> {
221239
}
222240
}
223241
242+
.workspace-hidden {
243+
background: var(--parsec-color-light-secondary-white);
244+
color: var(--parsec-color-light-secondary-contrast);
245+
text-align: left;
246+
display: flex;
247+
align-items: center;
248+
gap: 0.375rem;
249+
padding: 3px 0.5rem;
250+
border-radius: var(--parsec-radius-8);
251+
252+
ion-icon {
253+
font-size: 0.875rem;
254+
}
255+
}
256+
224257
&-info {
225258
display: flex;
226259
align-items: center;
@@ -279,4 +312,15 @@ async function onOptionsClick(event: Event): Promise<void> {
279312
}
280313
}
281314
}
315+
316+
.workspace-card-item--hidden {
317+
.workspace-card-content {
318+
opacity: 0.9;
319+
filter: brightness(0.85);
320+
321+
&:hover {
322+
background: var(--parsec-color-light-secondary-premiere) !important;
323+
}
324+
}
325+
}
282326
</style>

client/src/components/workspaces/WorkspaceListItem.vue

Lines changed: 55 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,10 @@
55
button
66
class="workspace-list-item no-padding-end"
77
:detail="false"
8-
:class="{ 'workspace-hovered': isHovered || menuOpened }"
8+
:class="{
9+
'workspace-hovered': isHovered || menuOpened,
10+
'workspace-list-item--hidden': isHidden,
11+
}"
912
@click="$emit('click', workspace, $event)"
1013
@mouseenter="isHovered = true"
1114
@mouseleave="isHovered = false"
@@ -36,6 +39,16 @@
3639
{{ workspace.currentName }}
3740
</ion-text>
3841
</div>
42+
<div
43+
class="workspace-hidden"
44+
v-if="isHidden"
45+
>
46+
<ion-icon
47+
class="workspace-hidden__icon"
48+
:icon="eyeOff"
49+
/>
50+
<ion-text class="subtitles-sm workspace-hidden__text">{{ $msTranslate('WorkspacesPage.Workspace.hidden') }}</ion-text>
51+
</div>
3952

4053
<!-- role user -->
4154
<div class="workspace-role">
@@ -123,7 +136,7 @@ import AvatarGroup from '@/components/workspaces/AvatarGroup.vue';
123136
import WorkspaceRoleTag from '@/components/workspaces/WorkspaceRoleTag.vue';
124137
import { UserProfile, WorkspaceInfo } from '@/parsec';
125138
import { IonButton, IonIcon, IonItem, IonLabel, IonText } from '@ionic/vue';
126-
import { cloudDone, cloudOffline, ellipsisHorizontal, shareSocial, star } from 'ionicons/icons';
139+
import { cloudDone, cloudOffline, ellipsisHorizontal, eyeOff, shareSocial, star } from 'ionicons/icons';
127140
import { formatTimeSince, useWindowSize, WindowSizeBreakpoints } from 'megashark-lib';
128141
import { ref } from 'vue';
129142
@@ -135,6 +148,7 @@ const props = defineProps<{
135148
workspace: WorkspaceInfo;
136149
clientProfile: UserProfile;
137150
isFavorite: boolean;
151+
isHidden: boolean;
138152
}>();
139153
140154
const emits = defineEmits<{
@@ -174,7 +188,7 @@ async function onOptionsClick(event: Event): Promise<void> {
174188
175189
&-content {
176190
display: flex;
177-
background: var(--parsec-color-light-secondary-background);
191+
background: var(--parsec-color-light-secondary-premiere);
178192
border-radius: var(--parsec-radius-8);
179193
align-items: center;
180194
width: 100%;
@@ -266,6 +280,29 @@ async function onOptionsClick(event: Event): Promise<void> {
266280
}
267281
}
268282
283+
.workspace-hidden {
284+
background: var(--parsec-color-light-secondary-white);
285+
color: var(--parsec-color-light-secondary-contrast);
286+
text-align: left;
287+
display: flex;
288+
align-items: center;
289+
gap: 0.375rem;
290+
padding: 3px 0.5rem;
291+
border-radius: var(--parsec-radius-8);
292+
flex-shrink: 0;
293+
294+
&__icon {
295+
font-size: 0.875rem;
296+
flex-shrink: 0;
297+
}
298+
299+
&__text {
300+
@include ms.responsive-breakpoint('xs') {
301+
display: none;
302+
}
303+
}
304+
}
305+
269306
.workspace-role {
270307
min-width: 8rem;
271308
max-width: 6vw;
@@ -364,4 +401,19 @@ async function onOptionsClick(event: Event): Promise<void> {
364401
}
365402
}
366403
}
404+
405+
.workspace-list-item--hidden {
406+
border: 1px solid var(--parsec-color-light-secondary-medium);
407+
408+
.workspace-list-item-content {
409+
opacity: 0.9;
410+
filter: brightness(0.85);
411+
}
412+
413+
&:hover {
414+
.workspace-list-item-content {
415+
background: var(--parsec-color-light-secondary-premiere);
416+
}
417+
}
418+
}
367419
</style>

client/src/components/workspaces/utils.ts

Lines changed: 85 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,8 +10,11 @@ import {
1010
WorkspaceRole,
1111
getClientProfile,
1212
getSystemPath,
13+
isDesktop,
14+
mountWorkspace,
1315
getPathLink as parsecGetPathLink,
1416
renameWorkspace as parsecRenameWorkspace,
17+
unmountWorkspace,
1518
} from '@/parsec';
1619
import { Routes, navigateTo } from '@/router';
1720
import { EventDistributor } from '@/services/eventDistributor';
@@ -138,6 +141,7 @@ export async function openWorkspaceContextMenu(
138141
clientProfile: clientProfile,
139142
clientRole: workspace.currentSelfRole,
140143
isFavorite: workspaceAttributes.isFavorite(workspace.id),
144+
isHidden: workspaceAttributes.isHidden(workspace.id),
141145
},
142146
});
143147

@@ -156,6 +160,7 @@ export async function openWorkspaceContextMenu(
156160
clientProfile: clientProfile,
157161
clientRole: workspace.currentSelfRole,
158162
isFavorite: workspaceAttributes.isFavorite(workspace.id),
163+
isHidden: workspaceAttributes.isHidden(workspace.id),
159164
},
160165
});
161166

@@ -184,12 +189,92 @@ export async function openWorkspaceContextMenu(
184189
case WorkspaceAction.ShowHistory:
185190
await navigateTo(Routes.History, { query: { documentPath: '/', workspaceHandle: workspace.handle } });
186191
break;
192+
case WorkspaceAction.Mount:
193+
await showWorkspace(workspace, workspaceAttributes, informationManager);
194+
break;
195+
case WorkspaceAction.UnMount:
196+
await hideWorkspace(workspace, workspaceAttributes, informationManager);
197+
break;
187198
default:
188199
console.warn('No WorkspaceAction match found');
189200
}
190201
}
191202
}
192203

204+
export async function showWorkspace(
205+
workspace: WorkspaceInfo,
206+
workspaceAttributes: WorkspaceAttributes,
207+
informationManager: InformationManager,
208+
): Promise<void> {
209+
let ok = true;
210+
if (isDesktop()) {
211+
const result = await mountWorkspace(workspace.handle);
212+
ok = result.ok;
213+
}
214+
215+
if (ok) {
216+
workspaceAttributes.removeHidden(workspace.id);
217+
informationManager.present(
218+
new Information({
219+
message: {
220+
key: isDesktop() ? 'WorkspacesPage.showHideWorkspace.successDesktopShown' : 'WorkspacesPage.showHideWorkspace.successWebShown',
221+
data: { workspace: workspace.currentName },
222+
},
223+
level: InformationLevel.Success,
224+
}),
225+
PresentationMode.Toast,
226+
);
227+
} else {
228+
informationManager.present(
229+
new Information({
230+
message: {
231+
key: 'WorkspacesPage.showHideWorkspace.failedShown',
232+
data: { workspace: workspace.currentName },
233+
},
234+
level: InformationLevel.Error,
235+
}),
236+
PresentationMode.Toast,
237+
);
238+
}
239+
}
240+
241+
export async function hideWorkspace(
242+
workspace: WorkspaceInfo,
243+
workspaceAttributes: WorkspaceAttributes,
244+
informationManager: InformationManager,
245+
): Promise<void> {
246+
let ok = true;
247+
if (isDesktop()) {
248+
const result = await unmountWorkspace(workspace);
249+
ok = result.ok;
250+
}
251+
252+
if (ok) {
253+
workspaceAttributes.addHidden(workspace.id);
254+
informationManager.present(
255+
new Information({
256+
message: {
257+
key: isDesktop() ? 'WorkspacesPage.showHideWorkspace.successDesktopHidden' : 'WorkspacesPage.showHideWorkspace.successWebHidden',
258+
data: { workspace: workspace.currentName },
259+
},
260+
level: InformationLevel.Success,
261+
}),
262+
PresentationMode.Toast,
263+
);
264+
} else {
265+
informationManager.present(
266+
new Information({
267+
message: {
268+
key: 'WorkspacesPage.showHideWorkspace.failedHidden',
269+
data: { workspace: workspace.currentName },
270+
},
271+
level: InformationLevel.Error,
272+
}),
273+
PresentationMode.Toast,
274+
);
275+
}
276+
}
277+
193278
async function openWorkspace(workspace: WorkspaceInfo, informationManager: InformationManager): Promise<void> {
194279
const result = await getSystemPath(workspace.handle, '/');
195280

client/src/locales/en-US.json

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -649,6 +649,8 @@
649649
"actionHistory": "History",
650650
"actionShare": "Sharing and roles",
651651
"actionDetails": "Details",
652+
"actionHide": "Hide this workspace",
653+
"actionShow": "Show this workspace",
652654
"actionCopyLink": "Copy link",
653655
"actionAddFavorite": "Pin",
654656
"actionRemoveFavorite": "Unpin"
@@ -699,6 +701,15 @@
699701
"filter": {
700702
"title": "Filter",
701703
"roles": "Role"
704+
},
705+
"showHideWorkspace": {
706+
"failedStarted": "Failed to get started workspace information. Please try again.",
707+
"successDesktopHidden": "The workspace is now hidden and will no longer appear in your explorer.",
708+
"successWebHidden": "The workspace is now hidden in Parsec.",
709+
"failedHidden": "Failed to hide the workspace. Please try again.",
710+
"successDesktopShown": "The workspace is now visible in Parsec and your explorer.",
711+
"successWebShown": "The workspace is now visible in Parsec.",
712+
"failedShown": "Failed to show the workspace. Please try again."
702713
}
703714
},
704715
"FoldersPage": {

client/src/locales/fr-FR.json

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -649,6 +649,8 @@
649649
"actionShare": "Partage et rôles",
650650
"actionDetails": "Détails",
651651
"actionCopyLink": "Copier le lien",
652+
"actionHide": "Masquer cet espace",
653+
"actionShow": "Afficher cet espace",
652654
"actionAddFavorite": "Épingler",
653655
"actionRemoveFavorite": "Désépingler"
654656
},
@@ -698,6 +700,15 @@
698700
"filter": {
699701
"title": "Filtrer",
700702
"roles": "Rôle"
703+
},
704+
"showHideWorkspace": {
705+
"failedStarted": "Impossible d'obtenir les informations relatives à l'espace de travail. Veuillez réessayer.",
706+
"successDesktopHidden": "L'espace de travail est maintenant masqué et n'apparaîtra plus dans votre explorateur.",
707+
"successWebHidden": "L'espace de travail est maintenant masqué dans Parsec.",
708+
"failedHidden": "Impossible de masquer l'espace de travail. Veuillez réessayer.",
709+
"successDesktopShown": "L'espace de travail est maintenant visible dans Parsec et votre explorateur.",
710+
"successWebShown": "L'espace de travail est maintenant visible dans Parsec.",
711+
"failedShown": "Impossible d'afficher l'espace de travail. Veuillez réessayer."
701712
}
702713
},
703714
"FoldersPage": {

0 commit comments

Comments
 (0)