refactor: migrate to common eslint+prettier configs (#4168)

* refactor: migrate to common eslint+prettier configs

* fix: prettier frontend

* feat: config changes

* fix: lint issues

* fix: lint

* fix: type imports

* fix: cyclical import issue

* fix: lockfile

* fix: missing dep

* fix: switch to tabs

* fix: continue switch to tabs

* fix: rustfmt parity

* fix: moderation lint issue

* fix: lint issues

* fix: ui intl

* fix: lint issues

* Revert "fix: rustfmt parity"

This reverts commit cb99d2376c321d813d4b7fc7e2a213bb30a54711.

* feat: revert last rs
This commit is contained in:
Cal H.
2025-08-14 21:48:38 +01:00
committed by GitHub
parent 82697278dc
commit 2aabcf36ee
702 changed files with 101360 additions and 102020 deletions

View File

@@ -1,345 +1,345 @@
<script setup lang="ts">
import dayjs from "dayjs";
import {
MoreVerticalIcon,
HistoryIcon,
DownloadIcon,
SpinnerIcon,
EditIcon,
LockIcon,
TrashIcon,
FolderArchiveIcon,
BotIcon,
XIcon,
LockOpenIcon,
RotateCounterClockwiseIcon,
} from "@modrinth/assets";
import { ButtonStyled, commonMessages, OverflowMenu, ProgressBar } from "@modrinth/ui";
import { defineMessages, useVIntl } from "@vintl/vintl";
import { ref, computed } from "vue";
import type { Backup } from "@modrinth/utils";
BotIcon,
DownloadIcon,
EditIcon,
FolderArchiveIcon,
HistoryIcon,
LockIcon,
LockOpenIcon,
MoreVerticalIcon,
RotateCounterClockwiseIcon,
SpinnerIcon,
TrashIcon,
XIcon,
} from '@modrinth/assets'
import { ButtonStyled, commonMessages, OverflowMenu, ProgressBar } from '@modrinth/ui'
import type { Backup } from '@modrinth/utils'
import { defineMessages, useVIntl } from '@vintl/vintl'
import dayjs from 'dayjs'
import { computed, ref } from 'vue'
const flags = useFeatureFlags();
const { formatMessage } = useVIntl();
const flags = useFeatureFlags()
const { formatMessage } = useVIntl()
const emit = defineEmits<{
(e: "prepare" | "download" | "rename" | "restore" | "lock" | "retry"): void;
(e: "delete", skipConfirmation?: boolean): void;
}>();
(e: 'prepare' | 'download' | 'rename' | 'restore' | 'lock' | 'retry'): void
(e: 'delete', skipConfirmation?: boolean): void
}>()
const props = withDefaults(
defineProps<{
backup: Backup;
preview?: boolean;
kyrosUrl?: string;
jwt?: string;
}>(),
{
preview: false,
kyrosUrl: undefined,
jwt: undefined,
},
);
defineProps<{
backup: Backup
preview?: boolean
kyrosUrl?: string
jwt?: string
}>(),
{
preview: false,
kyrosUrl: undefined,
jwt: undefined,
},
)
const backupQueued = computed(
() =>
props.backup.task?.create?.progress === 0 ||
(props.backup.ongoing && !props.backup.task?.create),
);
const automated = computed(() => props.backup.automated);
const failedToCreate = computed(() => props.backup.interrupted);
() =>
props.backup.task?.create?.progress === 0 ||
(props.backup.ongoing && !props.backup.task?.create),
)
const automated = computed(() => props.backup.automated)
const failedToCreate = computed(() => props.backup.interrupted)
const preparedDownloadStates = ["ready", "done"];
const inactiveStates = ["failed", "cancelled"];
const preparedDownloadStates = ['ready', 'done']
const inactiveStates = ['failed', 'cancelled']
const hasPreparedDownload = computed(() => {
const fileState = props.backup.task?.file?.state ?? "";
return preparedDownloadStates.includes(fileState);
});
const fileState = props.backup.task?.file?.state ?? ''
return preparedDownloadStates.includes(fileState)
})
const creating = computed(() => {
const task = props.backup.task?.create;
if (task && task.progress < 1 && !inactiveStates.includes(task.state)) {
return task;
}
if (props.backup.ongoing) {
return {
progress: 0,
state: "ongoing",
};
}
return undefined;
});
const task = props.backup.task?.create
if (task && task.progress < 1 && !inactiveStates.includes(task.state)) {
return task
}
if (props.backup.ongoing) {
return {
progress: 0,
state: 'ongoing',
}
}
return undefined
})
const restoring = computed(() => {
const task = props.backup.task?.restore;
if (task && task.progress < 1 && !inactiveStates.includes(task.state)) {
return task;
}
return undefined;
});
const task = props.backup.task?.restore
if (task && task.progress < 1 && !inactiveStates.includes(task.state)) {
return task
}
return undefined
})
const initiatedPrepare = ref(false);
const initiatedPrepare = ref(false)
const preparingFile = computed(() => {
if (hasPreparedDownload.value) {
return false;
}
if (hasPreparedDownload.value) {
return false
}
const task = props.backup.task?.file;
return (
(!task && initiatedPrepare.value) ||
(task && task.progress < 1 && !inactiveStates.includes(task.state))
);
});
const task = props.backup.task?.file
return (
(!task && initiatedPrepare.value) ||
(task && task.progress < 1 && !inactiveStates.includes(task.state))
)
})
const failedToRestore = computed(() => props.backup.task?.restore?.state === "failed");
const failedToPrepareFile = computed(() => props.backup.task?.file?.state === "failed");
const failedToRestore = computed(() => props.backup.task?.restore?.state === 'failed')
const failedToPrepareFile = computed(() => props.backup.task?.file?.state === 'failed')
const messages = defineMessages({
locked: {
id: "servers.backups.item.locked",
defaultMessage: "Locked",
},
lock: {
id: "servers.backups.item.lock",
defaultMessage: "Lock",
},
unlock: {
id: "servers.backups.item.unlock",
defaultMessage: "Unlock",
},
restore: {
id: "servers.backups.item.restore",
defaultMessage: "Restore",
},
rename: {
id: "servers.backups.item.rename",
defaultMessage: "Rename",
},
queuedForBackup: {
id: "servers.backups.item.queued-for-backup",
defaultMessage: "Queued for backup",
},
preparingDownload: {
id: "servers.backups.item.preparing-download",
defaultMessage: "Preparing download...",
},
prepareDownload: {
id: "servers.backups.item.prepare-download",
defaultMessage: "Prepare download",
},
prepareDownloadAgain: {
id: "servers.backups.item.prepare-download-again",
defaultMessage: "Try preparing again",
},
alreadyPreparing: {
id: "servers.backups.item.already-preparing",
defaultMessage: "Already preparing backup for download",
},
creatingBackup: {
id: "servers.backups.item.creating-backup",
defaultMessage: "Creating backup...",
},
restoringBackup: {
id: "servers.backups.item.restoring-backup",
defaultMessage: "Restoring from backup...",
},
failedToCreateBackup: {
id: "servers.backups.item.failed-to-create-backup",
defaultMessage: "Failed to create backup",
},
failedToRestoreBackup: {
id: "servers.backups.item.failed-to-restore-backup",
defaultMessage: "Failed to restore from backup",
},
failedToPrepareFile: {
id: "servers.backups.item.failed-to-prepare-backup",
defaultMessage: "Failed to prepare download",
},
automated: {
id: "servers.backups.item.automated",
defaultMessage: "Automated",
},
retry: {
id: "servers.backups.item.retry",
defaultMessage: "Retry",
},
});
locked: {
id: 'servers.backups.item.locked',
defaultMessage: 'Locked',
},
lock: {
id: 'servers.backups.item.lock',
defaultMessage: 'Lock',
},
unlock: {
id: 'servers.backups.item.unlock',
defaultMessage: 'Unlock',
},
restore: {
id: 'servers.backups.item.restore',
defaultMessage: 'Restore',
},
rename: {
id: 'servers.backups.item.rename',
defaultMessage: 'Rename',
},
queuedForBackup: {
id: 'servers.backups.item.queued-for-backup',
defaultMessage: 'Queued for backup',
},
preparingDownload: {
id: 'servers.backups.item.preparing-download',
defaultMessage: 'Preparing download...',
},
prepareDownload: {
id: 'servers.backups.item.prepare-download',
defaultMessage: 'Prepare download',
},
prepareDownloadAgain: {
id: 'servers.backups.item.prepare-download-again',
defaultMessage: 'Try preparing again',
},
alreadyPreparing: {
id: 'servers.backups.item.already-preparing',
defaultMessage: 'Already preparing backup for download',
},
creatingBackup: {
id: 'servers.backups.item.creating-backup',
defaultMessage: 'Creating backup...',
},
restoringBackup: {
id: 'servers.backups.item.restoring-backup',
defaultMessage: 'Restoring from backup...',
},
failedToCreateBackup: {
id: 'servers.backups.item.failed-to-create-backup',
defaultMessage: 'Failed to create backup',
},
failedToRestoreBackup: {
id: 'servers.backups.item.failed-to-restore-backup',
defaultMessage: 'Failed to restore from backup',
},
failedToPrepareFile: {
id: 'servers.backups.item.failed-to-prepare-backup',
defaultMessage: 'Failed to prepare download',
},
automated: {
id: 'servers.backups.item.automated',
defaultMessage: 'Automated',
},
retry: {
id: 'servers.backups.item.retry',
defaultMessage: 'Retry',
},
})
</script>
<template>
<div
:class="
preview
? 'grid-cols-[min-content_1fr_1fr] sm:grid-cols-[min-content_3fr_2fr_1fr] md:grid-cols-[auto_3fr_2fr_1fr]'
: 'grid-cols-[min-content_1fr_1fr] sm:grid-cols-[min-content_3fr_2fr_1fr] md:grid-cols-[auto_3fr_2fr_1fr_2fr]'
"
class="grid items-center gap-4 rounded-2xl bg-bg-raised px-4 py-3"
>
<div
class="flex h-12 w-12 items-center justify-center rounded-xl border-[1px] border-solid border-button-border bg-button-bg"
>
<SpinnerIcon
v-if="creating"
class="h-6 w-6 animate-spin"
:class="{ 'text-orange': backupQueued, 'text-green': !backupQueued }"
/>
<FolderArchiveIcon v-else class="h-6 w-6" />
</div>
<div class="col-span-2 flex flex-col gap-1 sm:col-span-1">
<span class="font-bold text-contrast">
{{ backup.name }}
</span>
<div class="flex flex-wrap items-center gap-2 text-sm">
<span v-if="backup.locked" class="flex items-center gap-1 text-sm text-secondary">
<LockIcon /> {{ formatMessage(messages.locked) }}
</span>
<span v-if="automated && backup.locked"></span>
<span v-if="automated" class="flex items-center gap-1 text-secondary">
<BotIcon /> {{ formatMessage(messages.automated) }}
</span>
<span v-if="(failedToCreate || failedToRestore) && (automated || backup.locked)"></span>
<span
v-if="failedToCreate || failedToRestore || failedToPrepareFile"
class="flex items-center gap-1 text-sm text-red"
>
<XIcon />
{{
formatMessage(
failedToCreate
? messages.failedToCreateBackup
: failedToRestore
? messages.failedToRestoreBackup
: messages.failedToPrepareFile,
)
}}
</span>
</div>
</div>
<div v-if="creating" class="col-span-2 flex flex-col gap-3">
<span v-if="backupQueued" class="text-orange">
{{ formatMessage(messages.queuedForBackup) }}
</span>
<span v-else class="text-green"> {{ formatMessage(messages.creatingBackup) }} </span>
<ProgressBar
:progress="creating.progress"
:color="backupQueued ? 'orange' : 'green'"
:waiting="creating.progress === 0"
class="max-w-full"
/>
</div>
<div v-else-if="restoring" class="col-span-2 flex flex-col gap-3 text-purple">
{{ formatMessage(messages.restoringBackup) }}
<ProgressBar
:progress="restoring.progress"
color="purple"
:waiting="restoring.progress === 0"
class="max-w-full"
/>
</div>
<template v-else>
<div class="col-span-2">
{{ dayjs(backup.created_at).format("MMMM D, YYYY [at] h:mm A") }}
</div>
<div v-if="false">{{ 245 }} MiB</div>
</template>
<div
v-if="!preview"
class="col-span-full flex justify-normal gap-2 md:col-span-1 md:justify-end"
>
<template v-if="failedToCreate">
<ButtonStyled>
<button @click="() => emit('retry')">
<RotateCounterClockwiseIcon />
{{ formatMessage(messages.retry) }}
</button>
</ButtonStyled>
<ButtonStyled>
<button @click="() => emit('delete', true)">
<TrashIcon />
Remove
</button>
</ButtonStyled>
</template>
<ButtonStyled v-else-if="creating">
<button @click="() => emit('delete')">
<XIcon />
{{ formatMessage(commonMessages.cancelButton) }}
</button>
</ButtonStyled>
<template v-else>
<ButtonStyled>
<a
v-if="hasPreparedDownload"
:class="{
disabled: !kyrosUrl || !jwt,
}"
:href="`https://${kyrosUrl}/modrinth/v0/backups/${backup.id}/download?auth=${jwt}`"
@click="() => emit('download')"
>
<DownloadIcon />
{{ formatMessage(commonMessages.downloadButton) }}
</a>
<button
v-else
:disabled="!!preparingFile"
@click="
() => {
initiatedPrepare = true;
emit('prepare');
}
"
>
<SpinnerIcon v-if="preparingFile" class="animate-spin" />
<DownloadIcon v-else />
{{
formatMessage(
preparingFile
? messages.preparingDownload
: failedToPrepareFile
? messages.prepareDownloadAgain
: messages.prepareDownload,
)
}}
</button>
</ButtonStyled>
<ButtonStyled circular type="transparent">
<OverflowMenu
:options="[
{ id: 'rename', action: () => emit('rename') },
{
id: 'restore',
action: () => emit('restore'),
disabled: !!restoring || !!preparingFile,
},
{ id: 'lock', action: () => emit('lock') },
{ divider: true },
{
id: 'delete',
color: 'red',
action: () => emit('delete'),
disabled: !!restoring || !!preparingFile,
},
]"
>
<MoreVerticalIcon />
<template #rename> <EditIcon /> {{ formatMessage(messages.rename) }} </template>
<template #restore> <HistoryIcon /> {{ formatMessage(messages.restore) }} </template>
<template v-if="backup.locked" #lock>
<LockOpenIcon /> {{ formatMessage(messages.unlock) }}
</template>
<template v-else #lock> <LockIcon /> {{ formatMessage(messages.lock) }} </template>
<template #delete>
<TrashIcon /> {{ formatMessage(commonMessages.deleteLabel) }}
</template>
</OverflowMenu>
</ButtonStyled>
</template>
</div>
<pre
v-if="!preview && flags.advancedDebugInfo"
class="col-span-full m-0 rounded-xl bg-button-bg text-xs"
>{{ backup }}</pre
>
</div>
<div
:class="
preview
? 'grid-cols-[min-content_1fr_1fr] sm:grid-cols-[min-content_3fr_2fr_1fr] md:grid-cols-[auto_3fr_2fr_1fr]'
: 'grid-cols-[min-content_1fr_1fr] sm:grid-cols-[min-content_3fr_2fr_1fr] md:grid-cols-[auto_3fr_2fr_1fr_2fr]'
"
class="grid items-center gap-4 rounded-2xl bg-bg-raised px-4 py-3"
>
<div
class="flex h-12 w-12 items-center justify-center rounded-xl border-[1px] border-solid border-button-border bg-button-bg"
>
<SpinnerIcon
v-if="creating"
class="h-6 w-6 animate-spin"
:class="{ 'text-orange': backupQueued, 'text-green': !backupQueued }"
/>
<FolderArchiveIcon v-else class="h-6 w-6" />
</div>
<div class="col-span-2 flex flex-col gap-1 sm:col-span-1">
<span class="font-bold text-contrast">
{{ backup.name }}
</span>
<div class="flex flex-wrap items-center gap-2 text-sm">
<span v-if="backup.locked" class="flex items-center gap-1 text-sm text-secondary">
<LockIcon /> {{ formatMessage(messages.locked) }}
</span>
<span v-if="automated && backup.locked"></span>
<span v-if="automated" class="flex items-center gap-1 text-secondary">
<BotIcon /> {{ formatMessage(messages.automated) }}
</span>
<span v-if="(failedToCreate || failedToRestore) && (automated || backup.locked)"></span>
<span
v-if="failedToCreate || failedToRestore || failedToPrepareFile"
class="flex items-center gap-1 text-sm text-red"
>
<XIcon />
{{
formatMessage(
failedToCreate
? messages.failedToCreateBackup
: failedToRestore
? messages.failedToRestoreBackup
: messages.failedToPrepareFile,
)
}}
</span>
</div>
</div>
<div v-if="creating" class="col-span-2 flex flex-col gap-3">
<span v-if="backupQueued" class="text-orange">
{{ formatMessage(messages.queuedForBackup) }}
</span>
<span v-else class="text-green"> {{ formatMessage(messages.creatingBackup) }} </span>
<ProgressBar
:progress="creating.progress"
:color="backupQueued ? 'orange' : 'green'"
:waiting="creating.progress === 0"
class="max-w-full"
/>
</div>
<div v-else-if="restoring" class="col-span-2 flex flex-col gap-3 text-purple">
{{ formatMessage(messages.restoringBackup) }}
<ProgressBar
:progress="restoring.progress"
color="purple"
:waiting="restoring.progress === 0"
class="max-w-full"
/>
</div>
<template v-else>
<div class="col-span-2">
{{ dayjs(backup.created_at).format('MMMM D, YYYY [at] h:mm A') }}
</div>
<div v-if="false">{{ 245 }} MiB</div>
</template>
<div
v-if="!preview"
class="col-span-full flex justify-normal gap-2 md:col-span-1 md:justify-end"
>
<template v-if="failedToCreate">
<ButtonStyled>
<button @click="() => emit('retry')">
<RotateCounterClockwiseIcon />
{{ formatMessage(messages.retry) }}
</button>
</ButtonStyled>
<ButtonStyled>
<button @click="() => emit('delete', true)">
<TrashIcon />
Remove
</button>
</ButtonStyled>
</template>
<ButtonStyled v-else-if="creating">
<button @click="() => emit('delete')">
<XIcon />
{{ formatMessage(commonMessages.cancelButton) }}
</button>
</ButtonStyled>
<template v-else>
<ButtonStyled>
<a
v-if="hasPreparedDownload"
:class="{
disabled: !kyrosUrl || !jwt,
}"
:href="`https://${kyrosUrl}/modrinth/v0/backups/${backup.id}/download?auth=${jwt}`"
@click="() => emit('download')"
>
<DownloadIcon />
{{ formatMessage(commonMessages.downloadButton) }}
</a>
<button
v-else
:disabled="!!preparingFile"
@click="
() => {
initiatedPrepare = true
emit('prepare')
}
"
>
<SpinnerIcon v-if="preparingFile" class="animate-spin" />
<DownloadIcon v-else />
{{
formatMessage(
preparingFile
? messages.preparingDownload
: failedToPrepareFile
? messages.prepareDownloadAgain
: messages.prepareDownload,
)
}}
</button>
</ButtonStyled>
<ButtonStyled circular type="transparent">
<OverflowMenu
:options="[
{ id: 'rename', action: () => emit('rename') },
{
id: 'restore',
action: () => emit('restore'),
disabled: !!restoring || !!preparingFile,
},
{ id: 'lock', action: () => emit('lock') },
{ divider: true },
{
id: 'delete',
color: 'red',
action: () => emit('delete'),
disabled: !!restoring || !!preparingFile,
},
]"
>
<MoreVerticalIcon />
<template #rename> <EditIcon /> {{ formatMessage(messages.rename) }} </template>
<template #restore> <HistoryIcon /> {{ formatMessage(messages.restore) }} </template>
<template v-if="backup.locked" #lock>
<LockOpenIcon /> {{ formatMessage(messages.unlock) }}
</template>
<template v-else #lock> <LockIcon /> {{ formatMessage(messages.lock) }} </template>
<template #delete>
<TrashIcon /> {{ formatMessage(commonMessages.deleteLabel) }}
</template>
</OverflowMenu>
</ButtonStyled>
</template>
</div>
<pre
v-if="!preview && flags.advancedDebugInfo"
class="col-span-full m-0 rounded-xl bg-button-bg text-xs"
>{{ backup }}</pre
>
</div>
</template>