Skip to content

Commit 8a2125e

Browse files
authored
feat: backups alignment with Figma (#5559)
* feat: backup admonitions * feat: align modals + fix backupitem * fix: body needs opac 80 * fix: lint
1 parent 31b5410 commit 8a2125e

File tree

16 files changed

+715
-157
lines changed

16 files changed

+715
-157
lines changed

apps/frontend/src/pages/[type]/[id]/settings/server.vue

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@
3232
:options="languageOptions"
3333
searchable
3434
include-select-all-option
35-
:maxTagRows="2"
35+
:max-tag-rows="2"
3636
placeholder="Select languages"
3737
:disabled="!hasPermission"
3838
/>

apps/frontend/src/pages/hosting/manage/[id].vue

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -311,6 +311,7 @@
311311
</template>
312312
</InstallingBanner>
313313
</Transition>
314+
<BackupProgressAdmonitions class="mb-4" />
314315
<NuxtPage
315316
:route="route"
316317
:is-connected="isConnected"
@@ -357,6 +358,7 @@ import {
357358
} from '@modrinth/assets'
358359
import type { BusyReason } from '@modrinth/ui'
359360
import {
361+
BackupProgressAdmonitions,
360362
ButtonStyled,
361363
defineMessage,
362364
ErrorInformationCard,

packages/ui/src/components/base/Admonition.vue

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,7 @@ import ButtonStyled from './ButtonStyled.vue'
5252
5353
withDefaults(
5454
defineProps<{
55-
type?: 'info' | 'warning' | 'critical'
55+
type?: 'info' | 'warning' | 'critical' | 'success'
5656
header?: string
5757
body?: string
5858
showActionsUnderneath?: boolean
@@ -75,17 +75,20 @@ const typeClasses = {
7575
info: 'border-brand-blue bg-bg-blue',
7676
warning: 'border-brand-orange bg-bg-orange',
7777
critical: 'border-brand-red bg-bg-red',
78+
success: 'border-brand-green bg-bg-green',
7879
}
7980
8081
const iconClasses = {
8182
info: 'text-brand-blue',
8283
warning: 'text-brand-orange',
8384
critical: 'text-brand-red',
85+
success: 'text-brand-green',
8486
}
8587
86-
const buttonColors: Record<string, 'blue' | 'orange' | 'red'> = {
88+
const buttonColors: Record<string, 'blue' | 'orange' | 'red' | 'green'> = {
8789
info: 'blue',
8890
warning: 'orange',
8991
critical: 'red',
92+
success: 'green',
9093
}
9194
</script>

packages/ui/src/components/servers/backups/BackupDeleteModal.vue

Lines changed: 2 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,13 @@
11
<template>
22
<NewModal ref="modal" header="Delete backup" fade="danger">
3-
<div class="flex flex-col gap-6">
3+
<div class="flex flex-col gap-6 max-w-[400px]">
44
<Admonition type="critical" header="Delete warning">
55
This backup will be permanently deleted. This action cannot be undone.
66
</Admonition>
77

88
<div v-if="currentBackup" class="flex flex-col gap-2">
99
<span class="font-semibold text-contrast">Backup</span>
10-
<BackupItem
11-
:backup="currentBackup"
12-
preview
13-
class="!bg-surface-2 border-solid border-[1px] border-surface-5"
14-
/>
10+
<BackupItem :backup="currentBackup" preview class="!bg-surface-2 !shadow-none" />
1511
</div>
1612
</div>
1713

packages/ui/src/components/servers/backups/BackupItem.vue

Lines changed: 45 additions & 120 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,6 @@ import { defineMessages, useVIntl } from '../../../composables/i18n'
1717
import { commonMessages } from '../../../utils'
1818
import ButtonStyled from '../../base/ButtonStyled.vue'
1919
import OverflowMenu, { type Option as OverflowOption } from '../../base/OverflowMenu.vue'
20-
import ProgressBar from '../../base/ProgressBar.vue'
2120
2221
const { formatMessage } = useVIntl()
2322
const formatDateTime = useFormatDateTime({
@@ -48,12 +47,6 @@ const props = withDefaults(
4847
},
4948
)
5049
51-
const backupQueued = computed(
52-
() =>
53-
props.backup.status === 'pending' ||
54-
props.backup.task?.create?.progress === 0 ||
55-
(props.backup.status === 'in_progress' && !props.backup.task?.create),
56-
)
5750
const failedToCreate = computed(
5851
() => props.backup.status === 'error' || props.backup.status === 'timed_out',
5952
)
@@ -63,30 +56,30 @@ const inactiveStates = ['failed', 'cancelled', 'done']
6356
const creating = computed(() => {
6457
const task = props.backup.task?.create
6558
if (task && task.progress < 1 && !inactiveStates.includes(task.state)) {
66-
return task
59+
return true
6760
}
6861
6962
if (
7063
(props.backup.status === 'in_progress' || props.backup.status === 'pending') &&
7164
!props.backup.task?.restore
7265
) {
73-
return { progress: 0, state: 'ongoing' as const }
66+
return true
7467
}
75-
return undefined
68+
return false
7669
})
7770
7871
const restoring = computed(() => {
7972
const task = props.backup.task?.restore
8073
if (task && task.progress < 1 && !inactiveStates.includes(task.state)) {
81-
return task
74+
return true
8275
}
83-
return undefined
76+
return false
8477
})
8578
86-
const restoreQueued = computed(() => restoring.value?.progress === 0)
87-
8879
const failedToRestore = computed(() => props.backup.task?.restore?.state === 'failed')
8980
81+
const activeOperation = computed(() => creating.value || restoring.value)
82+
9083
const backupIcon = computed(() => {
9184
if (props.backup.automated) {
9285
return ClockIcon
@@ -97,8 +90,7 @@ const backupIcon = computed(() => {
9790
const overflowMenuOptions = computed<OverflowOption[]>(() => {
9891
const options: OverflowOption[] = []
9992
100-
// Download only available when not creating
101-
if (!creating.value) {
93+
if (!activeOperation.value) {
10294
options.push({
10395
id: 'download',
10496
action: () => emit('download'),
@@ -109,8 +101,7 @@ const overflowMenuOptions = computed<OverflowOption[]>(() => {
109101
110102
options.push({ id: 'rename', action: () => emit('rename') })
111103
112-
// Delete only available when not creating (has separate Cancel button)
113-
if (!creating.value) {
104+
if (!activeOperation.value) {
114105
options.push({ divider: true })
115106
options.push({
116107
id: 'delete',
@@ -138,22 +129,6 @@ const messages = defineMessages({
138129
id: 'servers.backups.item.rename',
139130
defaultMessage: 'Rename',
140131
},
141-
queuedForBackup: {
142-
id: 'servers.backups.item.queued-for-backup',
143-
defaultMessage: 'Backup queued',
144-
},
145-
queuedForRestore: {
146-
id: 'servers.backups.item.queued-for-restore',
147-
defaultMessage: 'Restore queued',
148-
},
149-
creatingBackup: {
150-
id: 'servers.backups.item.creating-backup',
151-
defaultMessage: 'Creating backup...',
152-
},
153-
restoringBackup: {
154-
id: 'servers.backups.item.restoring-backup',
155-
defaultMessage: 'Restoring from backup...',
156-
},
157132
failedToCreateBackup: {
158133
id: 'servers.backups.item.failed-to-create-backup',
159134
defaultMessage: 'Failed to create backup',
@@ -179,7 +154,7 @@ const messages = defineMessages({
179154
<template>
180155
<div
181156
class="grid items-center gap-4 rounded-2xl bg-bg-raised p-4 shadow-md"
182-
:class="preview ? 'grid-cols-2' : 'grid-cols-[auto_1fr_auto] md:grid-cols-[1fr_400px_1fr]'"
157+
:class="preview ? 'grid-cols-1' : 'grid-cols-[auto_1fr_auto] md:grid-cols-[1fr_400px_1fr]'"
183158
>
184159
<div class="flex flex-row gap-4 items-center">
185160
<div
@@ -199,7 +174,10 @@ const messages = defineMessages({
199174
</span>
200175
</div>
201176
<div class="flex items-center gap-1.5 text-sm text-secondary">
202-
<template v-if="failedToCreate || failedToRestore">
177+
<template v-if="preview">
178+
<span>{{ formatDateTime(backup.created_at) }}</span>
179+
</template>
180+
<template v-else-if="failedToCreate || failedToRestore">
203181
<XIcon class="size-4 text-red" />
204182
<span class="text-red">
205183
{{
@@ -228,95 +206,42 @@ const messages = defineMessages({
228206
</div>
229207

230208
<div
209+
v-if="!preview"
231210
class="col-span-full row-start-2 flex flex-col gap-2 md:col-span-1 md:row-start-auto md:items-center"
232211
>
233-
<template v-if="creating || restoring">
234-
<ProgressBar
235-
:progress="(creating || restoring)!.progress"
236-
:color="creating ? 'brand' : 'purple'"
237-
:waiting="(creating || restoring)!.progress === 0"
238-
:label="
239-
formatMessage(
240-
creating
241-
? backupQueued
242-
? messages.queuedForBackup
243-
: messages.creatingBackup
244-
: restoreQueued
245-
? messages.queuedForRestore
246-
: messages.restoringBackup,
247-
)
248-
"
249-
:label-class="creating ? 'text-contrast' : 'text-purple'"
250-
show-progress
251-
full-width
252-
/>
253-
</template>
254-
<template v-else>
255-
<span class="w-full font-medium text-contrast md:text-center">
256-
{{ formatDateTime(backup.created_at) }}
257-
</span>
258-
<!-- TODO: Uncomment when API supports size field -->
259-
<!-- <span class="text-secondary">{{ formatBytes(backup.size) }}</span> -->
260-
</template>
212+
<span class="w-full font-medium text-contrast md:text-center">
213+
{{ formatDateTime(backup.created_at) }}
214+
</span>
215+
<!-- TODO: Uncomment when API supports size field -->
216+
<!-- <span class="text-secondary">{{ formatBytes(backup.size) }}</span> -->
261217
</div>
262218

263219
<div v-if="!preview" class="flex shrink-0 items-center gap-2 md:justify-self-end">
264-
<template v-if="failedToCreate">
265-
<ButtonStyled>
266-
<button @click="() => emit('retry')">
267-
<RotateCounterClockwiseIcon class="size-5" />
268-
{{ formatMessage(commonMessages.retryButton) }}
269-
</button>
270-
</ButtonStyled>
271-
<ButtonStyled>
272-
<button @click="() => emit('delete', true)">
273-
<TrashIcon class="size-5" />
274-
{{ formatMessage(commonMessages.deleteLabel) }}
275-
</button>
276-
</ButtonStyled>
277-
</template>
278-
<template v-else-if="creating">
279-
<ButtonStyled type="outlined">
280-
<button class="!border-[1px] !border-surface-5" @click="() => emit('delete')">
281-
{{ formatMessage(commonMessages.cancelButton) }}
282-
</button>
283-
</ButtonStyled>
284-
<ButtonStyled circular type="transparent">
285-
<OverflowMenu :options="overflowMenuOptions">
286-
<MoreVerticalIcon class="size-5" />
287-
<template #rename>
288-
<EditIcon class="size-5" /> {{ formatMessage(messages.rename) }}
289-
</template>
290-
</OverflowMenu>
291-
</ButtonStyled>
292-
</template>
293-
<template v-else>
294-
<ButtonStyled color="brand" type="outlined">
295-
<button
296-
v-tooltip="props.restoreDisabled"
297-
class="!border-[1px]"
298-
:disabled="!!props.restoreDisabled"
299-
@click="() => emit('restore')"
300-
>
301-
<RotateCounterClockwiseIcon class="size-5" />
302-
{{ formatMessage(messages.restore) }}
303-
</button>
304-
</ButtonStyled>
305-
<ButtonStyled circular type="transparent">
306-
<OverflowMenu :options="overflowMenuOptions">
307-
<MoreVerticalIcon class="size-5" />
308-
<template #download>
309-
<DownloadIcon class="size-5" /> {{ formatMessage(commonMessages.downloadButton) }}
310-
</template>
311-
<template #rename>
312-
<EditIcon class="size-5" /> {{ formatMessage(messages.rename) }}
313-
</template>
314-
<template #delete>
315-
<TrashIcon class="size-5" /> {{ formatMessage(commonMessages.deleteLabel) }}
316-
</template>
317-
</OverflowMenu>
318-
</ButtonStyled>
319-
</template>
220+
<ButtonStyled v-if="!activeOperation" color="brand" type="outlined">
221+
<button
222+
v-tooltip="props.restoreDisabled"
223+
class="!border-[1px]"
224+
:disabled="!!props.restoreDisabled"
225+
@click="() => emit('restore')"
226+
>
227+
<RotateCounterClockwiseIcon class="size-5" />
228+
{{ formatMessage(messages.restore) }}
229+
</button>
230+
</ButtonStyled>
231+
<ButtonStyled circular type="transparent">
232+
<OverflowMenu :options="overflowMenuOptions">
233+
<MoreVerticalIcon class="size-5" />
234+
<template #download>
235+
<DownloadIcon class="size-5" /> {{ formatMessage(commonMessages.downloadButton) }}
236+
</template>
237+
<template #rename>
238+
<EditIcon class="size-5" /> {{ formatMessage(messages.rename) }}
239+
</template>
240+
<template #delete>
241+
<TrashIcon class="size-5" /> {{ formatMessage(commonMessages.deleteLabel) }}
242+
</template>
243+
</OverflowMenu>
244+
</ButtonStyled>
320245
</div>
321246

322247
<pre v-if="!preview && showDebugInfo" class="w-full rounded-xl bg-surface-4 p-2 text-xs">{{

0 commit comments

Comments
 (0)