Skip to content

Commit

Permalink
UBERF-9511: Allow to unarchive workspace by user request (#8084)
Browse files Browse the repository at this point in the history
Signed-off-by: Andrey Sobolev <[email protected]>
  • Loading branch information
haiodo authored Feb 24, 2025
1 parent c6e752c commit dcbeb1e
Show file tree
Hide file tree
Showing 16 changed files with 109 additions and 45 deletions.
3 changes: 2 additions & 1 deletion plugins/login-assets/lang/cs.json
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,7 @@
"PasswordMinDigits": "{count, plural, =1 {Heslo musí obsahovat alespoň # číslo} other {Heslo musí obsahovat alespoň # čísel}}",
"PasswordMinUpperChars": "{count, plural, =1 {Heslo musí obsahovat alespoň # velké písmeno} other {Heslo musí obsahovat alespoň # velkých písmen}}",
"PasswordMinLowerChars": "{count, plural, =1 {Heslo musí obsahovat alespoň # malé písmeno} other {Heslo musí obsahovat alespoň # malých písmen}}",
"WorkspaceIsArchived": "Pracovní prostor je archivován kvůli nečinnosti. Kontaktujte nás prosím pro obnovení..."
"WorkspaceIsArchived": "Pracovní prostor je archivován kvůli nečinnosti.",
"RestoreArchivedWorkspace": "Obnovit pracovní prostor."
}
}
3 changes: 2 additions & 1 deletion plugins/login-assets/lang/de.json
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,7 @@
"PasswordMinDigits": "{count, plural, =1 {Das Passwort muss mindestens # Zahl enthalten} other {Das Passwort muss mindestens # Zahlen enthalten}}",
"PasswordMinUpperChars": "{count, plural, =1 {Das Passwort muss mindestens # Großbuchstaben enthalten} other {Das Passwort muss mindestens # Großbuchstaben enthalten}}",
"PasswordMinLowerChars": "{count, plural, =1 {Das Passwort muss mindestens # Kleinbuchstaben enthalten} other {Das Passwort muss mindestens # Kleinbuchstaben enthalten}}",
"WorkspaceArchivedDesc": "Workspace wurde wegen Inaktivität archiviert. Bitte kontaktieren Sie uns zur Wiederherstellung..."
"WorkspaceArchivedDesc": "Workspace wurde wegen Inaktivität archiviert.",
"RestoreArchivedWorkspace": "Workspace wiederherstellen."
}
}
3 changes: 2 additions & 1 deletion plugins/login-assets/lang/en.json
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,7 @@
"PasswordMinDigits": "{count, plural, =1 {Password must contain at least # number} other {Password must contain at least # numbers}}",
"PasswordMinUpperChars": "{count, plural, =1 {Password must contain at least # uppercase letter} other {Password must contain at least # uppercase letters}}",
"PasswordMinLowerChars": "{count, plural, =1 {Password must contain at least # lowercase letter} other {Password must contain at least # lowercase letters}}",
"WorkspaceArchivedDesc": "Workspace is archived because of being unused, Please contact us to restore..."
"WorkspaceArchivedDesc": "Workspace is archived because of being unused.",
"RestoreArchivedWorkspace": "Unarchive"
}
}
3 changes: 2 additions & 1 deletion plugins/login-assets/lang/es.json
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,7 @@
"PasswordMinDigits": "{count, plural, =1 {La contraseña debe contener al menos # número} other {La contraseña debe contener al menos # números}}",
"PasswordMinUpperChars": "{count, plural, =1 {La contraseña debe contener al menos # letra mayúscula} other {La contraseña debe contener al menos # letras mayúsculas}}",
"PasswordMinLowerChars": "{count, plural, =1 {La contraseña debe contener al menos # letra minúscula} other {La contraseña debe contener al menos # letras minúsculas}}",
"WorkspaceArchivedDesc": "El espacio de trabajo está archivado por no estar en uso, por favor contáctenos para restaurarlo..."
"WorkspaceArchivedDesc": "El espacio de trabajo está archivado por no estar en uso.",
"RestoreArchivedWorkspace": "Restaurar"
}
}
3 changes: 2 additions & 1 deletion plugins/login-assets/lang/fr.json
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,7 @@
"PasswordMinDigits": "{count, plural, =1 {Le mot de passe doit contenir au moins # chiffre} other {Le mot de passe doit contenir au moins # chiffres}}",
"PasswordMinUpperChars": "{count, plural, =1 {Le mot de passe doit contenir au moins # lettre majuscule} other {Le mot de passe doit contenir au moins # lettres majuscules}}",
"PasswordMinLowerChars": "{count, plural, =1 {Le mot de passe doit contenir au moins # lettre minuscule} other {Le mot de passe doit contenir au moins # lettres minuscules}}",
"WorkspaceArchivedDesc": "L'espace de travail est archivé en raison de son inactivité, veuillez nous contacter pour le restaurer..."
"WorkspaceArchivedDesc": "L'espace de travail est archivé en raison de son inactivité.",
"RestoreArchivedWorkspace": "Restaurer"
}
}
3 changes: 2 additions & 1 deletion plugins/login-assets/lang/it.json
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,7 @@
"PasswordMinDigits": "{count, plural, =1 {La password deve contenere almeno # numero} other {La password deve contenere almeno # numeri}}",
"PasswordMinUpperChars": "{count, plural, =1 {La password deve contenere almeno # lettera maiuscola} other {La password deve contenere almeno # lettere maiuscole}}",
"PasswordMinLowerChars": "{count, plural, =1 {La password deve contenere almeno # lettera minuscola} other {La password deve contenere almeno # lettere minuscole}}",
"WorkspaceArchivedDesc": "Il workspace è stato archiviato perché inutilizzato. Si prega di contattarci per ripristinarlo..."
"WorkspaceArchivedDesc": "Il workspace è stato archiviato perché inutilizzato.",
"RestoreArchivedWorkspace": "Un archiviato workspace"
}
}
3 changes: 2 additions & 1 deletion plugins/login-assets/lang/pt.json
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,7 @@
"PasswordMinDigits": "{count, plural, =1 {A senha deve conter pelo menos # número} other {A senha deve conter pelo menos # números}}",
"PasswordMinUpperChars": "{count, plural, =1 {A senha deve conter pelo menos # letra maiúscula} other {A senha deve conter pelo menos # letras maiúsculas}}",
"PasswordMinLowerChars": "{count, plural, =1 {A senha deve conter pelo menos # letra minúscula} other {A senha deve conter pelo menos # letras minúsculas}}",
"WorkspaceArchivedDesc": "O espaço de trabalho está arquivado por estar inativo, por favor, entre em contato conosco para restaurá-lo..."
"WorkspaceArchivedDesc": "O espaço de trabalho está arquivado por estar inativo.",
"RestoreArchivedWorkspace": "Restaurar"
}
}
3 changes: 2 additions & 1 deletion plugins/login-assets/lang/ru.json
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,7 @@
"PasswordMinDigits": "{count, plural, =1 {Пароль должен содержать минимум # цифру} other {Пароль должен содержать минимум # цифр}}",
"PasswordMinUpperChars": "{count, plural, =1 {Пароль должен содержать минимум # заглавную букву} other {Пароль должен содержать минимум # заглавных букв}}",
"PasswordMinLowerChars": "{count, plural, =1 {Пароль должен содержать минимум # строчную букву} other {Пароль должен содержать минимум # строчных букв}}",
"WorkspaceArchivedDesc": "Рабочее пространство архивировано из-за неиспользования, пожалуйста, свяжитесь с нами для восстановления..."
"WorkspaceArchivedDesc": "Рабочее пространство архивировано из-за неиспользования.",
"RestoreArchivedWorkspace": "Восстановить"
}
}
3 changes: 2 additions & 1 deletion plugins/login-assets/lang/zh.json
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,7 @@
"PasswordMinDigits": "{count, plural, =1 {密码至少需要 # 个数字} other {密码至少需要 # 个数字}}",
"PasswordMinUpperChars": "{count, plural, =1 {密码至少需要 # 个大写字母} other {密码至少需要 # 个大写字母}}",
"PasswordMinLowerChars": "{count, plural, =1 {密码至少需要 # 个小写字母} other {密码至少需要 # 个小写字母}}",
"WorkspaceArchivedDesc": "工作区因未使用而归档,请与我们联系以恢复..."
"WorkspaceArchivedDesc": "工作区已被归档,因为未使用。",
"RestoreArchivedWorkspace": "解包"
}
}
24 changes: 18 additions & 6 deletions plugins/login-resources/src/components/SelectWorkspace.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@
// limitations under the License.
-->
<script lang="ts">
import { isArchivingMode } from '@hcengineering/core'
import { isActiveMode, isArchivingMode, isRestoringMode, isUpgradingMode } from '@hcengineering/core'
import { LoginInfo, Workspace } from '@hcengineering/login'
import { OK, Severity, Status } from '@hcengineering/platform'
import presentation, { NavLink, isAdminUser, reduceCalls } from '@hcengineering/presentation'
Expand All @@ -32,7 +32,7 @@
} from '@hcengineering/ui'
import { onMount } from 'svelte'
import login from '../plugin'
import { getAccount, getHref, getWorkspaces, goTo, navigateToWorkspace, selectWorkspace } from '../utils'
import { getAccount, getHref, getWorkspaces, goTo, navigateToWorkspace, selectWorkspace, unArchive } from '../utils'
import StatusControl from './StatusControl.svelte'
export let navigateUrl: string | undefined = undefined
Expand Down Expand Up @@ -69,13 +69,25 @@
status = new Status(Severity.INFO, login.status.ConnectingToServer, {})
const [loginStatus, result] = await selectWorkspace(workspace)
if (isArchivingMode(result?.mode)) {
if (isArchivingMode(result?.mode) && result?.workspaceId !== undefined) {
const workspaceId = result?.workspaceId
showPopup(MessageBox, {
label: login.string.SelectWorkspace,
message: login.string.WorkspaceArchivedDesc,
canSubmit: false,
canSubmit: true,
params: {},
action: async () => {}
okLabel: login.string.RestoreArchivedWorkspace,
action: async () => {
if (await unArchive(workspaceId, result.token)) {
workspaces = await getWorkspaces()
let info = workspaces.filter((it) => it.workspaceId === workspaceId).shift()
while (isRestoringMode(info?.mode) || isUpgradingMode(info?.mode)) {
await new Promise<void>((resolve) => setTimeout(resolve, 5000))
workspaces = await getWorkspaces()
info = workspaces.filter((it) => it.workspaceId === workspaceId).shift()
}
}
}
})
status = loginStatus
return
Expand Down Expand Up @@ -152,7 +164,7 @@
{#if isArchivingMode(workspace.mode)}
- <Label label={presentation.string.Archived} />
{/if}
{#if workspace.mode !== 'active' && workspace.mode !== 'archived'}
{#if !isActiveMode(workspace.mode) && !isArchivingMode(workspace.mode)}
({workspace.progress}%)
{/if}
</span>
Expand Down
29 changes: 8 additions & 21 deletions plugins/login-resources/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,15 +19,18 @@ import InviteLink from './components/InviteLink.svelte'
import LoginApp from './components/LoginApp.svelte'
import {
changePassword,
createMissingEmployee,
fetchWorkspace,
getInviteLink,
getWorkspaces,
leaveWorkspace,
selectWorkspace,
sendInvite,
resendInvite,
fetchWorkspace,
createMissingEmployee,
getInviteLink
selectWorkspace,
sendInvite
} from './utils'

import { type Pages, pages } from '@hcengineering/login'
export { type Pages, pages }
/*!
* Anticrm Platform™ Login Plugin
* © 2020, 2021 Anticrm Platform Contributors.
Expand All @@ -53,21 +56,6 @@ export default async () => ({
}
})

export const pages = [
'login',
'signup',
'createWorkspace',
'password',
'recovery',
'selectWorkspace',
'admin',
'join',
'confirm',
'confirmationSend',
'auth',
'login-password'
] as const

export enum OtpLoginSteps {
Email = 'email',
Otp = 'otp'
Expand All @@ -77,7 +65,6 @@ export enum LoginMethods {
Password = 'password',
Otp = 'otp'
}
export type Pages = (typeof pages)[number]

export interface BottomAction {
i18n: IntlString
Expand Down
32 changes: 32 additions & 0 deletions plugins/login-resources/src/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -549,6 +549,38 @@ export async function fetchWorkspace (workspace: string): Promise<[Status, Works
return [unknownError(err), undefined]
}
}

export async function unArchive (workspaceId: string, token: string): Promise<boolean> {
const accountsUrl = getMetadata(login.metadata.AccountsUrl)

if (accountsUrl === undefined) {
throw new Error('accounts url not specified')
}

if (token === undefined) {
return false
}

const request = {
method: 'performWorkspaceOperation',
params: [workspaceId, 'unarchive']
}

try {
const response = await fetch(accountsUrl, {
method: 'POST',
headers: {
Authorization: 'Bearer ' + token,
'Content-Type': 'application/json'
},
body: JSON.stringify(request)
})
return (await response.json()).result
} catch (err: any) {
Analytics.handleError(err)
return false
}
}
export async function createMissingEmployee (workspace: string): Promise<[Status]> {
const accountsUrl = getMetadata(login.metadata.AccountsUrl)

Expand Down
20 changes: 19 additions & 1 deletion plugins/login/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,23 @@ export interface OtpInfo {
retryOn: Timestamp
}

export const pages = [
'login',
'signup',
'createWorkspace',
'password',
'recovery',
'selectWorkspace',
'admin',
'join',
'confirm',
'confirmationSend',
'auth',
'login-password'
] as const

export type Pages = (typeof pages)[number]

export default plugin(loginId, {
metadata: {
AccountsUrl: '' as Asset,
Expand Down Expand Up @@ -99,7 +116,8 @@ export default plugin(loginId, {
PasswordMinUpperChars: '' as IntlString<{ count: number }>,
PasswordMinLowerChars: '' as IntlString<{ count: number }>,
WorkspaceArchived: '' as IntlString,
WorkspaceArchivedDesc: '' as IntlString
WorkspaceArchivedDesc: '' as IntlString,
RestoreArchivedWorkspace: '' as IntlString
},
function: {
SendInvite: '' as Resource<(email: string, personId?: Ref<Doc>, role?: AccountRole) => Promise<void>>,
Expand Down
12 changes: 7 additions & 5 deletions plugins/workbench-resources/src/connect.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ import core, {
type MeasureMetricsContext,
type Version
} from '@hcengineering/core'
import login, { loginId } from '@hcengineering/login'
import login, { loginId, type Pages } from '@hcengineering/login'
import { broadcastEvent, getMetadata, getResource, setMetadata, translateCB } from '@hcengineering/platform'
import presentation, {
closeClient,
Expand Down Expand Up @@ -208,13 +208,15 @@ export async function connect (title: string): Promise<Client | undefined> {
},
onArchived: () => {
translateCB(plugin.string.WorkspaceIsArchived, {}, get(themeStore).language, (r) => {
versionError.set(r)
setTimeout(() => {
location.reload()
}, 5000)
const selectWorkspace: Pages = 'selectWorkspace'
navigate({
path: [loginId, selectWorkspace],
query: {}
})
})
},
onMigration: () => {
// TODO: Rework maitenance mode as well
translateCB(plugin.string.WorkspaceIsMigrating, {}, get(themeStore).language, (r) => {
versionError.set(r)
setTimeout(() => {
Expand Down
4 changes: 3 additions & 1 deletion server/account/src/operations.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1305,7 +1305,9 @@ export async function performWorkspaceOperation (
}

if (account.admin !== true) {
return false
if (event !== 'unarchive' || workspaceId !== decodedToken.workspace.name) {
return false
}
}
const workspaceInfos = await getWorkspacesById(db, workspaceId)
if (workspaceInfos.length === 0) {
Expand Down
6 changes: 4 additions & 2 deletions ws-tests/sanity/tests/workspace/archive.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -82,8 +82,8 @@ test.describe('Workspace Archive tests', () => {
await page2.locator(`[id="${workspaceInfo.workspaceId}"]`).getByText('archived').waitFor()
})
await test.step('Check workspace is archived', async () => {
await page.reload()
await page.getByText('Workspace is archived').waitFor()
await page.reload() // Will redirect to select workspace page
await page.getByText('archived').waitFor()
})
await test.step('Restore workspace', async () => {
await page2.locator(`[id="${workspaceInfo.workspaceId}"]`).getByRole('button', { name: 'Unarchive' }).click()
Expand All @@ -94,6 +94,8 @@ test.describe('Workspace Archive tests', () => {
await test.step('Check workspace is active again', async () => {
await page.reload()

await selectWorkspacePage.selectWorkspace(workspaceInfo.workspaceName)

const issuesDetailsPage = new IssuesDetailsPage(page)
await issuesDetailsPage.checkIssue(newIssue)
})
Expand Down

0 comments on commit dcbeb1e

Please sign in to comment.