Skip to content

Commit

Permalink
[MS] Handle user status frozen
Browse files Browse the repository at this point in the history
  • Loading branch information
Max-7 committed Nov 13, 2024
1 parent cac1e17 commit 449ad5f
Show file tree
Hide file tree
Showing 9 changed files with 118 additions and 22 deletions.
9 changes: 6 additions & 3 deletions client/src/components/users/UserCard.vue
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@
selected: user.isSelected,
'no-padding-end': !user.isSelected,
revoked: user.isRevoked(),
frozen: user.isFrozen(),
'user-hovered': !user.isSelected && (menuOpened || isHovered),
}"
@click="$emit('click', $event, user)"
Expand All @@ -30,10 +29,14 @@
<!-- eslint-enable vue/no-mutating-props -->
</div>
<div
v-if="user.isRevoked()"
v-if="!user.isActive()"
class="user-revoked"
>
<user-status-tag :revoked="user.isRevoked()" />
<user-status-tag
:revoked="user.isRevoked()"
:frozen="user.isFrozen()"
:show-tooltip="true"
/>
</div>
<div
class="user-card-option"
Expand Down
15 changes: 15 additions & 0 deletions client/src/components/users/UserFilterPopover.vue
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,21 @@
@change="users.unselectHiddenUsers()"
/>
</ion-item>
<ion-item
class="list-group-item ion-no-padding"
id="filter-check-frozen"
>
<user-status-tag
:revoked="false"
:frozen="true"
class="status-tag"
@click="users.filters.statusFrozen = !users.filters.statusFrozen"
/>
<ms-checkbox
v-model="users.filters.statusFrozen"
@change="users.unselectHiddenUsers()"
/>
</ion-item>
</ion-item-group>
<ion-item-group class="list-group">
<ion-text
Expand Down
7 changes: 5 additions & 2 deletions client/src/components/users/UserListItem.vue
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@
:detail="false"
:class="{
selected: user.isSelected && !user.isRevoked(),
frozen: user.isFrozen(),
revoked: user.isRevoked(),
'no-padding-end': !user.isSelected,
'user-hovered': !user.isSelected && (menuOpened || isHovered),
Expand Down Expand Up @@ -71,7 +70,11 @@
class="user-status"
:class="user.isRevoked() ? 'user-revoked' : ''"
>
<user-status-tag :revoked="user.isRevoked()" />
<user-status-tag
:revoked="user.isRevoked()"
:frozen="user.isFrozen()"
:show-tooltip="true"
/>
</div>

<!-- options -->
Expand Down
40 changes: 36 additions & 4 deletions client/src/components/users/UserStatusTag.vue
Original file line number Diff line number Diff line change
@@ -1,22 +1,49 @@
<!-- Parsec Cloud (https://parsec.cloud) Copyright (c) BUSL-1.1 2016-present Scille SAS -->

<template>
<ion-label class="label-status status">
<ion-label
class="label-status status"
@click="showTooltip ? openInformationTooltip($event, getStatusDescription()) : null"
>
<ion-chip
class="button-small tag-status"
:class="{ revoked: revoked, active: !revoked }"
:class="{ revoked: revoked, active: !revoked && !frozen, frozen: frozen }"
>
{{ revoked ? $msTranslate('UsersPage.status.revoked') : $msTranslate('UsersPage.status.active') }}
{{ $msTranslate(statusText) }}
</ion-chip>
</ion-label>
</template>

<script setup lang="ts">
import { IonChip, IonLabel } from '@ionic/vue';
import { Translatable, openInformationTooltip } from 'megashark-lib';
import { computed } from 'vue';

defineProps<{
const props = defineProps<{
revoked: boolean;
frozen?: boolean;
showTooltip?: boolean;
}>();

const statusText = computed((): Translatable => {
if (props.revoked) {
return 'UsersPage.status.revoked';
}
if (props.frozen) {
return 'UsersPage.status.frozen';
}
return 'UsersPage.status.active';
});

function getStatusDescription(): Translatable {
if (props.revoked) {
return 'UsersPage.statusDescriptions.revoked';
}
if (props.frozen) {
return 'UsersPage.statusDescriptions.frozen';
}
return 'UsersPage.statusDescriptions.active';
}
</script>

<style scoped lang="scss">
Expand Down Expand Up @@ -45,4 +72,9 @@ defineProps<{
background-color: var(--parsec-color-light-info-100);
color: var(--parsec-color-light-info-500);
}

.frozen {
background-color: lightseagreen;
color: blue;
}
</style>
38 changes: 28 additions & 10 deletions client/src/components/users/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ function compareUserProfiles(profile1: UserProfile, profile2: UserProfile): numb
export interface UserFilterLabels {
statusActive?: boolean;
statusRevoked?: boolean;
statusFrozen?: boolean;
profileAdmin?: boolean;
profileStandard?: boolean;
profileOutsider?: boolean;
Expand All @@ -51,6 +52,7 @@ export class UserCollection {
this.filters = {
statusActive: true,
statusRevoked: true,
statusFrozen: true,
profileAdmin: true,
profileStandard: true,
profileOutsider: true,
Expand Down Expand Up @@ -99,7 +101,11 @@ export class UserCollection {
) {
return false;
}
if ((!this.filters.statusRevoked && user.isRevoked()) || (!this.filters.statusActive && !user.isRevoked())) {
if (
(!this.filters.statusRevoked && user.isRevoked()) ||
(!this.filters.statusActive && user.isActive()) ||
(!this.filters.statusFrozen && user.isFrozen())
) {
return false;
}
return true;
Expand All @@ -117,6 +123,15 @@ export class UserCollection {
return this.getSelectedUsers().length;
}

private statusDiff(user1: UserModel, user2: UserModel): number {
return (
Number(user2.isActive()) * 4 +
Number(user2.isRevoked()) * 2 +
Number(user2.isFrozen()) -
(Number(user1.isActive()) * 4 + Number(user1.isRevoked()) * 2 + Number(user1.isFrozen()))
);
}

sort(property: SortProperty, ascending: boolean): void {
this.users.sort((user1, user2) => {
// Arbitrary value to keep the current user always at the top of the list
Expand Down Expand Up @@ -144,18 +159,21 @@ export class UserCollection {
}
case SortProperty.Profile:
if (profile1 === profile2) {
return user2.isRevoked() && !user1.isRevoked() ? -1 : 0;
// return user2.isRevoked() && !user1.isRevoked() ? -1 : 0;
return this.statusDiff(user1, user2);
}
return diff;
case SortProperty.Status:
if (user2.isRevoked() === user1.isRevoked()) {
return ascending ? diff : -diff;
}
if (ascending) {
return user2.isRevoked() && !user1.isRevoked() ? -1 : 0;
} else {
return user1.isRevoked() && !user2.isRevoked() ? -1 : 0;
}
return ascending ? this.statusDiff(user1, user2) : this.statusDiff(user2, user1);

// if (user2.isRevoked() === user1.isRevoked()) {
// return ascending ? diff : -diff;
// }
// if (ascending) {
// return user2.isRevoked() && !user1.isRevoked() ? -1 : 0;
// } else {
// return user1.isRevoked() && !user2.isRevoked() ? -1 : 0;
// }
default:
return 0;
}
Expand Down
8 changes: 7 additions & 1 deletion client/src/locales/en-US.json
Original file line number Diff line number Diff line change
Expand Up @@ -955,7 +955,13 @@
},
"status": {
"active": "Active",
"revoked": "Revoked"
"revoked": "Revoked",
"frozen": "Suspended"
},
"statusDescriptions": {
"active": "User is active.",
"revoked": "User has been revoked and can no longer access this organization.",
"frozen": "User is suspended and cannot access this organization."
},
"success": {
"email": "Email address:",
Expand Down
8 changes: 7 additions & 1 deletion client/src/locales/fr-FR.json
Original file line number Diff line number Diff line change
Expand Up @@ -955,7 +955,13 @@
},
"status": {
"active": "Actif",
"revoked": "Révoqué"
"revoked": "Révoqué",
"frozen": "Suspendu"
},
"statusDescriptions": {
"active": "L'utilisateur est actif.",
"revoked": "L'utilisateur a été révoqué et ne peux plus accéder à cette organisation.",
"frozen": "L'utilisateur a été suspendu et ne peut pas accéder à cette organisation."
},
"success": {
"email": "Adresse email :",
Expand Down
1 change: 1 addition & 0 deletions client/src/parsec/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -198,6 +198,7 @@ type SystemPath = Path;
interface UserInfo extends ParsecUserInfo {
isRevoked: () => boolean;
isFrozen: () => boolean;
isActive: () => boolean;
}

interface OwnDeviceInfo extends DeviceInfo {
Expand Down
14 changes: 13 additions & 1 deletion client/src/parsec/user.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,8 @@ export async function listUsers(skipRevoked = true, pattern = ''): Promise<Resul
if (handle !== null && !needsMocks()) {
const result = await libparsec.clientListUsers(handle, skipRevoked);
if (result.ok) {
const frozenResult = await libparsec.clientListFrozenUsers(handle);
const frozen: Array<UserID> = frozenResult.ok ? frozenResult.value : [];
if (pattern.length > 0) {
// Won't be using dates or `isRevoked` so the cast is fine
result.value = filterUserList(result.value as Array<UserInfo>, pattern);
Expand All @@ -30,7 +32,9 @@ export async function listUsers(skipRevoked = true, pattern = ''): Promise<Resul
item.revokedOn = DateTime.fromSeconds(item.revokedOn as any as number);
}
(item as UserInfo).isRevoked = (): boolean => item.revokedOn !== null;
(item as UserInfo).isFrozen = (): boolean => false;
(item as UserInfo).isFrozen = (): boolean =>
!(item as UserInfo).isRevoked() && frozen.find((userId) => userId === item.id) !== undefined;
(item as UserInfo).isActive = (): boolean => !(item as UserInfo).isRevoked() && !(item as UserInfo).isFrozen();
return item;
});
}
Expand All @@ -50,6 +54,7 @@ export async function listUsers(skipRevoked = true, pattern = ''): Promise<Resul
revokedBy: null,
isRevoked: (): boolean => false,
isFrozen: (): boolean => false,
isActive: (): boolean => true,
},
{
id: 'id1',
Expand All @@ -62,6 +67,7 @@ export async function listUsers(skipRevoked = true, pattern = ''): Promise<Resul
revokedBy: null,
isRevoked: (): boolean => false,
isFrozen: (): boolean => false,
isActive: (): boolean => true,
},
{
id: 'id2',
Expand All @@ -74,6 +80,7 @@ export async function listUsers(skipRevoked = true, pattern = ''): Promise<Resul
revokedBy: null,
isRevoked: (): boolean => false,
isFrozen: (): boolean => false,
isActive: (): boolean => true,
},
{
id: 'id3',
Expand All @@ -86,6 +93,7 @@ export async function listUsers(skipRevoked = true, pattern = ''): Promise<Resul
revokedBy: null,
isRevoked: (): boolean => false,
isFrozen: (): boolean => true,
isActive: (): boolean => false,
},
{
id: 'id4',
Expand All @@ -98,6 +106,7 @@ export async function listUsers(skipRevoked = true, pattern = ''): Promise<Resul
revokedBy: null,
isRevoked: (): boolean => false,
isFrozen: (): boolean => false,
isActive: (): boolean => true,
},
];
if (!skipRevoked) {
Expand All @@ -113,6 +122,7 @@ export async function listUsers(skipRevoked = true, pattern = ''): Promise<Resul
revokedBy: 'device',
isRevoked: (): boolean => true,
isFrozen: (): boolean => false,
isActive: (): boolean => false,
},
{
id: 'id6',
Expand All @@ -125,6 +135,7 @@ export async function listUsers(skipRevoked = true, pattern = ''): Promise<Resul
revokedBy: 'device',
isRevoked: (): boolean => true,
isFrozen: (): boolean => false,
isActive: (): boolean => false,
},
{
id: 'id7',
Expand All @@ -137,6 +148,7 @@ export async function listUsers(skipRevoked = true, pattern = ''): Promise<Resul
revokedBy: 'device',
isRevoked: (): boolean => true,
isFrozen: (): boolean => false,
isActive: (): boolean => false,
},
);
}
Expand Down

0 comments on commit 449ad5f

Please sign in to comment.