mirror of
https://github.com/hcengineering/platform.git
synced 2026-09-12 04:37:44 +02:00
UBERF-9511: Allow to unarchive workspace by user request (#8084)
Signed-off-by: Andrey Sobolev <haiodo@gmail.com>
This commit is contained in:
@@ -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."
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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."
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -63,6 +63,7 @@
|
||||
"PasswordMinDigits": "{count, plural, =1 {Пароль должен содержать минимум # цифру} other {Пароль должен содержать минимум # цифр}}",
|
||||
"PasswordMinUpperChars": "{count, plural, =1 {Пароль должен содержать минимум # заглавную букву} other {Пароль должен содержать минимум # заглавных букв}}",
|
||||
"PasswordMinLowerChars": "{count, plural, =1 {Пароль должен содержать минимум # строчную букву} other {Пароль должен содержать минимум # строчных букв}}",
|
||||
"WorkspaceArchivedDesc": "Рабочее пространство архивировано из-за неиспользования, пожалуйста, свяжитесь с нами для восстановления..."
|
||||
"WorkspaceArchivedDesc": "Рабочее пространство архивировано из-за неиспользования.",
|
||||
"RestoreArchivedWorkspace": "Восстановить"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -63,6 +63,7 @@
|
||||
"PasswordMinDigits": "{count, plural, =1 {密码至少需要 # 个数字} other {密码至少需要 # 个数字}}",
|
||||
"PasswordMinUpperChars": "{count, plural, =1 {密码至少需要 # 个大写字母} other {密码至少需要 # 个大写字母}}",
|
||||
"PasswordMinLowerChars": "{count, plural, =1 {密码至少需要 # 个小写字母} other {密码至少需要 # 个小写字母}}",
|
||||
"WorkspaceArchivedDesc": "工作区因未使用而归档,请与我们联系以恢复..."
|
||||
"WorkspaceArchivedDesc": "工作区已被归档,因为未使用。",
|
||||
"RestoreArchivedWorkspace": "解包"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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'
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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>
|
||||
|
||||
@@ -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.
|
||||
@@ -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'
|
||||
@@ -77,7 +65,6 @@ export enum LoginMethods {
|
||||
Password = 'password',
|
||||
Otp = 'otp'
|
||||
}
|
||||
export type Pages = (typeof pages)[number]
|
||||
|
||||
export interface BottomAction {
|
||||
i18n: IntlString
|
||||
|
||||
@@ -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)
|
||||
|
||||
|
||||
@@ -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,
|
||||
@@ -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>>,
|
||||
|
||||
@@ -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,
|
||||
@@ -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(() => {
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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()
|
||||
@@ -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)
|
||||
})
|
||||
|
||||
Reference in New Issue
Block a user