mirror of
https://github.com/hcengineering/platform.git
synced 2026-09-05 17:27:41 +02:00
Custom maintenance messages support (#9417)
Signed-off-by: Andrey Sobolev <haiodo@gmail.com>
This commit is contained in:
@@ -9,7 +9,8 @@
|
||||
"Unauthorized": "Neoprávněný přístup",
|
||||
"UnknownMethod": "Neznámá metoda: {method}",
|
||||
"InternalServerError": "Interní chyba serveru",
|
||||
"MaintenanceWarning": "Plánovaná údržba za {time, plural, =1 {méně než minutu} other {# minut}}",
|
||||
"MaintenanceWarning": "Plánovaná údržba za",
|
||||
"MaintenanceWarningTime": "{time, plural, =1 {méně než minutu} other {# minut}}",
|
||||
"AccountNotFound": "Účet nenalezen",
|
||||
"AccountNotConfirmed": "Účet není potvrzen",
|
||||
"WorkspaceNotFound": "Pracovní prostor nenalezen",
|
||||
|
||||
@@ -9,7 +9,8 @@
|
||||
"Unauthorized": "Nicht autorisiert",
|
||||
"UnknownMethod": "Unbekannte Methode: {method}",
|
||||
"InternalServerError": "Interner Serverfehler",
|
||||
"MaintenanceWarning": "Wartung geplant in {time, plural, =1 {weniger als einer Minute} other {# Minuten}}",
|
||||
"MaintenanceWarning": "Wartung geplant in",
|
||||
"MaintenanceWarningTime": "{time, plural, =1 {weniger als einer Minute} other {# Minuten}}",
|
||||
"AccountNotFound": "Konto nicht gefunden",
|
||||
"AccountNotConfirmed": "Konto nicht bestätigt",
|
||||
"WorkspaceNotFound": "Arbeitsbereich nicht gefunden",
|
||||
|
||||
@@ -9,7 +9,8 @@
|
||||
"Unauthorized": "Unauthorized",
|
||||
"UnknownMethod": "Unknown method: {method}",
|
||||
"InternalServerError": "Internal server error",
|
||||
"MaintenanceWarning": "Maintenance Scheduled in {time, plural, =1 {less than a minute} other {# minutes}}",
|
||||
"MaintenanceWarning": "Maintenance Scheduled in",
|
||||
"MaintenanceWarningTime": "{time, plural, =1 {less than a minute} other {# minutes}}",
|
||||
"AccountNotFound": "Account not found or the provided credentials are incorrect",
|
||||
"AccountNotConfirmed": "Account not confirmed",
|
||||
"WorkspaceNotFound": "Workspace not found",
|
||||
|
||||
@@ -9,7 +9,8 @@
|
||||
"Unauthorized": "No autorizado",
|
||||
"UnknownMethod": "Método desconocido: {method}",
|
||||
"InternalServerError": "Error interno del servidor",
|
||||
"MaintenanceWarning": "Mantenimiento programado dentro de {time, plural, =1 {menos de un minuto} other {# minutos}}",
|
||||
"MaintenanceWarning": "Mantenimiento programado dentro de",
|
||||
"MaintenanceWarningTime": "{time, plural, =1 {menos de un minuto} other {# minutos}}",
|
||||
"AccountNotFound": "Cuenta no encontrada",
|
||||
"AccountNotConfirmed": "Cuenta no confirmada",
|
||||
"WorkspaceNotFound": "Espacio de trabajo no encontrado",
|
||||
|
||||
@@ -9,7 +9,8 @@
|
||||
"Unauthorized": "Non autorisé",
|
||||
"UnknownMethod": "Méthode inconnue : {method}",
|
||||
"InternalServerError": "Erreur interne du serveur",
|
||||
"MaintenanceWarning": "Maintenance prévue dans {time, plural, =1 {moins d'une minute} other {# minutes}}",
|
||||
"MaintenanceWarning": "Maintenance prévue dans",
|
||||
"MaintenanceWarningTime": "{time, plural, =1 {moins d'une minute} other {# minutes}}",
|
||||
"AccountNotFound": "Compte non trouvé",
|
||||
"AccountNotConfirmed": "Compte non confirmé",
|
||||
"WorkspaceNotFound": "Espace de travail non trouvé",
|
||||
|
||||
@@ -9,7 +9,8 @@
|
||||
"Unauthorized": "Non autorizzato",
|
||||
"UnknownMethod": "Metodo sconosciuto: {method}",
|
||||
"InternalServerError": "Errore interno del server",
|
||||
"MaintenanceWarning": "Manutenzione programmata tra {time, plural, =1 {meno di un minuto} other {# minuti}}",
|
||||
"MaintenanceWarning": "Manutenzione programmata tra",
|
||||
"MaintenanceWarningTime": "{time, plural, =1 {meno di un minuto} other {# minuti}}",
|
||||
"AccountNotFound": "Account non trovato",
|
||||
"AccountNotConfirmed": "Account non confermato",
|
||||
"WorkspaceNotFound": "Spazio di lavoro non trovato",
|
||||
|
||||
@@ -9,7 +9,8 @@
|
||||
"Unauthorized": "認証されていません",
|
||||
"UnknownMethod": "不明なメソッド: {method}",
|
||||
"InternalServerError": "サーバー内部エラー",
|
||||
"MaintenanceWarning": "{time, plural, =1 {1分以内に} other {#分後に}}メンテナンスが予定されています",
|
||||
"MaintenanceWarning": "メンテナンスが予定されています",
|
||||
"MaintenanceWarningTime": "{time, plural, =1 {1分以内に} other {#分後に}}",
|
||||
"AccountNotFound": "アカウントが見つからないか、認証情報が間違っています",
|
||||
"AccountNotConfirmed": "アカウントが確認されていません",
|
||||
"WorkspaceNotFound": "ワークスペースが見つかりません",
|
||||
|
||||
@@ -9,7 +9,8 @@
|
||||
"Unauthorized": "Não autorizado",
|
||||
"UnknownMethod": "Método desconhecido: {method}",
|
||||
"InternalServerError": "Erro interno do servidor",
|
||||
"MaintenanceWarning": "Manutenção programada dentro de {time, plural, =1 {menos de um minuto} other {# minutos}}",
|
||||
"MaintenanceWarning": "Manutenção programada dentro de",
|
||||
"MaintenanceWarningTime": "{time, plural, =1 {menos de um minuto} other {# minutos}}",
|
||||
"AccountNotFound": "Conta não encontrada",
|
||||
"AccountNotConfirmed": "Conta não confirmada",
|
||||
"WorkspaceNotFound": "Espaço de trabalho não encontrado",
|
||||
|
||||
@@ -9,7 +9,8 @@
|
||||
"Unauthorized": "Неавторизован",
|
||||
"UnknownMethod": "Неизвестный метод: {method}",
|
||||
"InternalServerError": "Внутренняя ошибка сервера",
|
||||
"MaintenanceWarning": "Серверные работы запланированы через {time, plural, one {# минуту} few {# минуты} other {# минут}}",
|
||||
"MaintenanceWarning": "Серверные работы запланированы через",
|
||||
"MaintenanceWarningTime": "{time, plural, one {# минуту} few {# минуты} other {# минут}}",
|
||||
"AccountNotFound": "Аккаунт не найден",
|
||||
"AccountNotConfirmed": "Аккаунт не подтвержден",
|
||||
"WorkspaceNotFound": "Рабочее пространство не найдено",
|
||||
|
||||
@@ -9,7 +9,8 @@
|
||||
"Unauthorized": "未授权",
|
||||
"UnknownMethod": "未知方法: {method}",
|
||||
"InternalServerError": "内部服务器错误",
|
||||
"MaintenanceWarning": "计划在 {time, plural, =1 {不到一分钟} other {# 分钟}} 内进行维护",
|
||||
"MaintenanceWarning": "计划在 内进行维护 ",
|
||||
"MaintenanceWarningTime": "{time, plural, =1 {不到一分钟} other {# 分钟}}",
|
||||
"AccountNotFound": "账户未找到",
|
||||
"AccountNotConfirmed": "账户未确认",
|
||||
"WorkspaceNotFound": "工作区未找到",
|
||||
|
||||
@@ -144,7 +144,8 @@ export default plugin(platformId, {
|
||||
ExpiredLink: '' as StatusCode,
|
||||
UnknownMethod: '' as StatusCode<{ method: string }>,
|
||||
InternalServerError: '' as StatusCode,
|
||||
MaintenanceWarning: '' as StatusCode<{ time: number }>,
|
||||
MaintenanceWarning: '' as StatusCode<{ time: number, message?: string }>,
|
||||
MaintenanceWarningTime: '' as IntlString,
|
||||
AccountNotFound: '' as StatusCode<{ account?: string }>,
|
||||
AccountMismatch: '' as StatusCode<{ account?: string, requiredAccount?: string }>,
|
||||
AccountNotConfirmed: '' as StatusCode,
|
||||
|
||||
@@ -97,10 +97,12 @@
|
||||
let readonlyAccount = false
|
||||
let systemAccount = false
|
||||
let maintenanceTime = -1
|
||||
let maintenanceMessage: string | undefined
|
||||
|
||||
addEventListener(PlatformEvent, async (_event, _status: Status) => {
|
||||
if (_status.code === platform.status.MaintenanceWarning) {
|
||||
maintenanceTime = _status.params.time
|
||||
maintenanceMessage = _status.params.message
|
||||
} else {
|
||||
if (readonlyAccount) return
|
||||
if (_status.code === platform.status.ReadOnlyAccount) {
|
||||
@@ -242,7 +244,12 @@
|
||||
>
|
||||
{#if maintenanceTime > 0}
|
||||
<div class="flex-grow flex-center flex-row-center" class:maintenanceScheduled={maintenanceTime > 0}>
|
||||
<Label label={platform.status.MaintenanceWarning} params={{ time: maintenanceTime }} />
|
||||
{#if maintenanceMessage !== undefined && maintenanceMessage.trim() !== ''}
|
||||
{maintenanceMessage}
|
||||
{:else}
|
||||
<Label label={platform.status.MaintenanceWarning} />
|
||||
{/if}
|
||||
<Label label={platform.status.MaintenanceWarningTime} params={{ time: maintenanceTime }} />
|
||||
</div>
|
||||
{:else if status.severity !== Severity.OK}
|
||||
<StatusComponent {status} />
|
||||
|
||||
@@ -112,7 +112,8 @@ export default async () => {
|
||||
if (event.event === WorkspaceEvent.MaintenanceNotification) {
|
||||
void setPlatformStatus(
|
||||
new Status(Severity.WARNING, platform.status.MaintenanceWarning, {
|
||||
time: event.params.timeMinutes
|
||||
time: event.params.timeMinutes,
|
||||
message: event.params.message ?? ''
|
||||
})
|
||||
)
|
||||
}
|
||||
|
||||
@@ -139,27 +139,38 @@
|
||||
}
|
||||
|
||||
$: update($ticker)
|
||||
|
||||
let maintenanceMessage = 'A new version is planned to be installed in'
|
||||
</script>
|
||||
|
||||
{#if isAdminUser()}
|
||||
<div class="flex flex-col">
|
||||
<div class="flex-row-center p-1">
|
||||
<div class="p-3">1.</div>
|
||||
<Button
|
||||
icon={IconArrowRight}
|
||||
label={getEmbeddedLabel('Set maintenance warning')}
|
||||
on:click={() => {
|
||||
const endpoint = getMetadata(login.metadata.AccountsUrl) ?? ''
|
||||
if (endpoint !== '') {
|
||||
void fetch(
|
||||
concatLink(endpoint, `/api/v1/manage?token=${token}&operation=maintenance&timeout=${warningTimeout}`),
|
||||
{
|
||||
method: 'PUT'
|
||||
}
|
||||
)
|
||||
}
|
||||
}}
|
||||
/>
|
||||
<div class="flex p-1 flex-row-center">
|
||||
<div class="flex-row-center flex-grow">
|
||||
<EditBox bind:value={maintenanceMessage}></EditBox>
|
||||
</div>
|
||||
<Button
|
||||
icon={IconArrowRight}
|
||||
label={getEmbeddedLabel('Set maintenance warning')}
|
||||
on:click={() => {
|
||||
const endpoint = getMetadata(login.metadata.AccountsUrl) ?? ''
|
||||
if (endpoint !== '') {
|
||||
void fetch(
|
||||
concatLink(endpoint, `/api/v1/manage?token=${token}&operation=maintenance&timeout=${warningTimeout}`),
|
||||
{
|
||||
method: 'PUT',
|
||||
body: JSON.stringify({ message: maintenanceMessage }),
|
||||
headers: {
|
||||
'Content-Type': 'application/json;charset=utf-8'
|
||||
}
|
||||
}
|
||||
)
|
||||
}
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
<div class="flex-col p-1">
|
||||
<div class="flex-row-center p-1">
|
||||
<EditBox kind={'underline'} format={'number'} bind:value={warningTimeout} /> min
|
||||
|
||||
@@ -205,6 +205,7 @@ export function startHttpServer (
|
||||
try {
|
||||
const token = (req.query.token as string) ?? (req.headers.authorization ?? '').split(' ')[1]
|
||||
const payload = decodeToken(token)
|
||||
|
||||
if (payload.extra?.admin !== 'true' && payload.account !== systemAccountUuid) {
|
||||
console.warn('Non admin attempt to maintenance action', { payload })
|
||||
res.writeHead(404, {})
|
||||
@@ -216,11 +217,13 @@ export function startHttpServer (
|
||||
|
||||
switch (operation) {
|
||||
case 'maintenance': {
|
||||
const timeMinutes = parseInt((req.query.timeout as string) ?? '5')
|
||||
sessions.scheduleMaintenance(timeMinutes)
|
||||
void retrieveJson(req).then((message) => {
|
||||
const timeMinutes = parseInt((req.query.timeout as string) ?? '5')
|
||||
sessions.scheduleMaintenance(timeMinutes, message)
|
||||
|
||||
res.writeHead(200)
|
||||
res.end()
|
||||
res.writeHead(200)
|
||||
res.end()
|
||||
})
|
||||
return
|
||||
}
|
||||
case 'wipe-statistics': {
|
||||
|
||||
@@ -312,8 +312,13 @@ export function serveAccount (measureCtx: MeasureContext, brandings: BrandingMap
|
||||
const transactors = getAllTransactors(EndpointKind.Internal)
|
||||
for (const tr of transactors) {
|
||||
const serverEndpoint = tr.replaceAll('wss://', 'https://').replace('ws://', 'http://')
|
||||
const jsonBody = JSON.stringify(req.request.body as any)
|
||||
await fetch(serverEndpoint + `/api/v1/manage?token=${token}&operation=maintenance&timeout=${timeMinutes}`, {
|
||||
method: 'PUT'
|
||||
method: 'PUT',
|
||||
body: jsonBody,
|
||||
headers: {
|
||||
'Content-Type': 'application/json;charset=utf-8'
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
@@ -729,7 +729,7 @@ export interface SessionManager {
|
||||
|
||||
closeWorkspaces: (ctx: MeasureContext) => Promise<void>
|
||||
|
||||
scheduleMaintenance: (timeMinutes: number) => void
|
||||
scheduleMaintenance: (timeMinutes: number, message?: string) => void
|
||||
|
||||
profiling?: {
|
||||
start: () => void
|
||||
|
||||
@@ -109,6 +109,7 @@ export class TSessionManager implements SessionManager {
|
||||
|
||||
maintenanceTimer: any
|
||||
timeMinutes = 0
|
||||
maintenanceMessage?: string
|
||||
|
||||
modelVersion = process.env.MODEL_VERSION ?? ''
|
||||
serverVersion = process.env.VERSION ?? ''
|
||||
@@ -146,8 +147,9 @@ export class TSessionManager implements SessionManager {
|
||||
this.ticksContext = ctx.newChild('ticks', {})
|
||||
}
|
||||
|
||||
scheduleMaintenance (timeMinutes: number): void {
|
||||
scheduleMaintenance (timeMinutes: number, message?: string): void {
|
||||
this.timeMinutes = timeMinutes
|
||||
this.maintenanceMessage = message
|
||||
|
||||
this.sendMaintenanceWarning()
|
||||
|
||||
@@ -190,7 +192,8 @@ export class TSessionManager implements SessionManager {
|
||||
space: core.space.DerivedTx,
|
||||
createdBy: core.account.System,
|
||||
params: {
|
||||
timeMinutes: this.timeMinutes
|
||||
timeMinutes: this.timeMinutes,
|
||||
message: this.maintenanceMessage
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -306,7 +309,7 @@ export class TSessionManager implements SessionManager {
|
||||
wsId,
|
||||
total: s.session.requests.size,
|
||||
user: s.session.getUser(),
|
||||
...cutObjectArray(r.params)
|
||||
params: cutObjectArray(r.params)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user