mirror of
https://github.com/HangarMC/Hangar.git
synced 2025-03-13 15:39:18 +08:00
fix(frontend): tackle some vue-tsc errors
only 159 to go!
This commit is contained in:
parent
88e0a41469
commit
2acafbc382
@ -5,16 +5,10 @@ import { hasSlotContent } from "~/lib/composables/useSlot";
|
||||
import Table from "~/lib/components/design/Table.vue";
|
||||
import PaginationButtons from "~/lib/components/design/PaginationButtons.vue";
|
||||
import PaginationComponent from "~/lib/components/design/Pagination.vue";
|
||||
import { Header } from "~/types/components/SortableTable";
|
||||
|
||||
type T = Record<string, any>; // remove when https://github.com/vuejs/rfcs/discussions/436 lands or when using volar
|
||||
|
||||
export interface Header {
|
||||
name: string;
|
||||
title: string;
|
||||
sortable?: boolean;
|
||||
width?: string;
|
||||
}
|
||||
|
||||
const props = defineProps<{
|
||||
headers: Header[];
|
||||
items: T[];
|
||||
|
@ -37,7 +37,7 @@ async function submit(close: () => void) {
|
||||
useNotificationStore().success(i18n.t("project.flag.flagSend"));
|
||||
await router.go(0);
|
||||
} catch (e) {
|
||||
handleRequestError(e as AxiosError);
|
||||
handleRequestError(e);
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
@ -30,7 +30,7 @@ async function confirm(close: () => void) {
|
||||
router.go(0);
|
||||
useNotificationStore().success(i18n.t(`author.lock.success${props.user.locked ? "Unlock" : "Lock"}`, [props.user.name]));
|
||||
} catch (e) {
|
||||
handleRequestError(e as AxiosError);
|
||||
handleRequestError(e);
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
@ -8,9 +8,10 @@ import Button from "~/lib/components/design/Button.vue";
|
||||
import Modal from "~/lib/components/modals/Modal.vue";
|
||||
import { useBackendData } from "~/store/backendData";
|
||||
import InputText from "~/lib/components/ui/InputText.vue";
|
||||
import InputSelect, { Option } from "~/lib/components/ui/InputSelect.vue";
|
||||
import InputSelect from "~/lib/components/ui/InputSelect.vue";
|
||||
import { useInternalApi } from "~/composables/useApi";
|
||||
import { handleRequestError } from "~/composables/useErrorHandling";
|
||||
import { Option } from "~/lib/types/components/ui/InputSelect";
|
||||
|
||||
const props = defineProps<{
|
||||
projectId: number;
|
||||
@ -41,10 +42,10 @@ watch(name, async () => {
|
||||
parentId: parent.value,
|
||||
})
|
||||
.catch((err: AxiosError) => {
|
||||
if (!err.response?.data.isHangarApiException) {
|
||||
if (!err.response?.data?.isHangarApiException) {
|
||||
return handleRequestError(err);
|
||||
}
|
||||
nameErrorMessages.value.push(i18n.t(err.response.data.message));
|
||||
nameErrorMessages.value.push(i18n.t(err.response.data?.message));
|
||||
})
|
||||
.finally(() => {
|
||||
validateLoading.value = false;
|
||||
|
@ -9,8 +9,9 @@ import InputText from "~/lib/components/ui/InputText.vue";
|
||||
import { required } from "~/lib/composables/useValidationHelpers";
|
||||
import InputAutocomplete from "~/lib/components/ui/InputAutocomplete.vue";
|
||||
import { useApi } from "~/composables/useApi";
|
||||
import Tabs, { Tab } from "~/lib/components/design/Tabs.vue";
|
||||
import { watch, ref, useRoute } from "#imports";
|
||||
import Tabs from "~/lib/components/design/Tabs.vue";
|
||||
import { ref, useRoute } from "#imports";
|
||||
import { Tab } from "~/lib/types/components/design/Tabs";
|
||||
|
||||
const route = useRoute();
|
||||
const i18n = useI18n();
|
||||
|
@ -23,7 +23,7 @@ class Auth {
|
||||
const result = await useAxios()
|
||||
.get(`/logout?returnUrl=${useConfig().publicHost}?loggedOut`)
|
||||
.catch((e) => handleRequestError(e));
|
||||
if ("status" in result && result?.status === 200 && result?.data) {
|
||||
if (result?.status === 200 && result?.data) {
|
||||
location.replace(result?.data);
|
||||
} else {
|
||||
await useNotificationStore().error("Error while logging out?!");
|
||||
|
@ -1,12 +1,12 @@
|
||||
import axios, { AxiosError } from "axios";
|
||||
import { HangarApiException, HangarValidationException, MultiHangarApiException } from "hangar-api";
|
||||
import { Composer } from "vue-i18n";
|
||||
import { ref } from "vue";
|
||||
import { useNotificationStore } from "~/lib/store/notification";
|
||||
import { I18n } from "~/lib/i18n";
|
||||
import { createError } from "#imports";
|
||||
|
||||
export function handleRequestError(err: AxiosError | unknown, i18n: Composer = I18n.value, msg: string | undefined = undefined) {
|
||||
export function handleRequestError(err: AxiosError | unknown, msg: string | undefined = undefined) {
|
||||
const i18n: Composer = I18n.value;
|
||||
if (import.meta.env.SSR) {
|
||||
_handleRequestError(err, i18n);
|
||||
}
|
||||
@ -40,43 +40,37 @@ export function handleRequestError(err: AxiosError | unknown, i18n: Composer = I
|
||||
}
|
||||
|
||||
function _handleRequestError(err: AxiosError | unknown, i18n: Composer) {
|
||||
function writeResponse(object: unknown) {
|
||||
console.log("writeResponse", object);
|
||||
// throw new Error("TODO: Implement me"); // TODO
|
||||
createError({ statusCode: object.status, statusMessage: object.statusText });
|
||||
}
|
||||
|
||||
const transformed = transformAxiosError(err);
|
||||
if (!axios.isAxiosError(err)) {
|
||||
// everything should be an AxiosError
|
||||
writeResponse({
|
||||
status: 500,
|
||||
createError({
|
||||
statusCode: 500,
|
||||
});
|
||||
console.log("handle not axios error", transformed);
|
||||
} else if (err.response && typeof err.response.data === "object" && err.response.data) {
|
||||
if ("isHangarApiException" in err.response.data) {
|
||||
const data =
|
||||
"isMultiException" in err.response.data ? (err.response.data as MultiHangarApiException).exceptions[0] : (err.response.data as HangarApiException);
|
||||
writeResponse({
|
||||
status: data.httpError.statusCode,
|
||||
statusText: i18n.te(data.message) ? i18n.t(data.message) : data.message,
|
||||
createError({
|
||||
statusCode: data.httpError.statusCode,
|
||||
statusMessage: i18n.te(data.message) ? i18n.t(data.message) : data.message,
|
||||
});
|
||||
} else if ("isHangarValidationException" in err.response.data) {
|
||||
const data = err.response.data as HangarValidationException;
|
||||
writeResponse({
|
||||
status: data.httpError.statusCode,
|
||||
statusText: data.fieldErrors.map((f) => f.errorMsg).join(", "),
|
||||
createError({
|
||||
statusCode: data.httpError.statusCode,
|
||||
statusMessage: data.fieldErrors.map((f) => f.errorMsg).join(", "),
|
||||
});
|
||||
} else {
|
||||
writeResponse({
|
||||
status: err.response.status,
|
||||
statusText: err.response.statusText,
|
||||
createError({
|
||||
statusCode: err.response.status,
|
||||
statusMessage: err.response.statusText,
|
||||
});
|
||||
}
|
||||
} else {
|
||||
writeResponse({
|
||||
status: 500,
|
||||
statusText: "Internal Error: " + transformed.code,
|
||||
createError({
|
||||
statusCode: 500,
|
||||
statusMessage: "Internal Error: " + transformed.code,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
@ -2,7 +2,7 @@ import { helpers } from "@vuelidate/validators";
|
||||
import { useInternalApi } from "~/composables/useApi";
|
||||
import { withOverrideMessage } from "~/lib/composables/useValidationHelpers";
|
||||
|
||||
export const validProjectName = withOverrideMessage((ownerId: () => string) =>
|
||||
export const validProjectName = withOverrideMessage((ownerId: () => number) =>
|
||||
helpers.withParams(
|
||||
{ ownerId, type: "validProjectName" },
|
||||
helpers.withAsync(async (value: string) => {
|
||||
|
@ -24,7 +24,7 @@ export async function useProjectPage(route: RouteLocationNormalizedLoaded, route
|
||||
if (!page) return;
|
||||
await useInternalApi(`pages/save/${project.id}/${page.value?.id}`, "post", {
|
||||
content,
|
||||
}).catch((e) => handleRequestError(e, i18n, "page.new.error.save"));
|
||||
}).catch((e) => handleRequestError(e, "page.new.error.save"));
|
||||
if (page.value) {
|
||||
page.value.contents = content;
|
||||
}
|
||||
@ -33,7 +33,7 @@ export async function useProjectPage(route: RouteLocationNormalizedLoaded, route
|
||||
|
||||
async function deletePage() {
|
||||
if (!page) return;
|
||||
await useInternalApi(`pages/delete/${project.id}/${page.value?.id}`, "post").catch((e) => handleRequestError(e, i18n, "page.new.error.save"));
|
||||
await useInternalApi(`pages/delete/${project.id}/${page.value?.id}`, "post").catch((e) => handleRequestError(e, "page.new.error.save"));
|
||||
await router.replace(`/${route.params.user}/${route.params.project}`);
|
||||
}
|
||||
|
||||
|
@ -1 +1 @@
|
||||
Subproject commit a6c3c7eb08fd543684116ac314ac841be375def1
|
||||
Subproject commit 7fe3405bc026b8110503fa87d2f8ac7a64ee2660
|
@ -5,7 +5,6 @@ import { HangarProject, ProjectChannel } from "hangar-internal";
|
||||
import { useHead } from "@vueuse/head";
|
||||
import { useRoute } from "vue-router";
|
||||
import Card from "~/lib/components/design/Card.vue";
|
||||
import { Header } from "~/components/SortableTable.vue";
|
||||
import { ChannelFlag } from "~/types/enums";
|
||||
import { useProjectChannels } from "~/composables/useApiHelper";
|
||||
import { handleRequestError } from "~/composables/useErrorHandling";
|
||||
|
@ -6,12 +6,13 @@ import { useHead } from "@vueuse/head";
|
||||
import { useRoute } from "vue-router";
|
||||
import Card from "~/lib/components/design/Card.vue";
|
||||
import Link from "~/lib/components/design/Link.vue";
|
||||
import SortableTable, { Header } from "~/components/SortableTable.vue";
|
||||
import SortableTable from "~/components/SortableTable.vue";
|
||||
import Alert from "~/lib/components/design/Alert.vue";
|
||||
import { useProjectFlags } from "~/composables/useApiHelper";
|
||||
import { useSeo } from "~/composables/useSeo";
|
||||
import { projectIconUrl } from "~/composables/useUrlHelper";
|
||||
import { definePageMeta } from "#imports";
|
||||
import { Header } from "~/types/components/SortableTable";
|
||||
|
||||
definePageMeta({
|
||||
projectPermsRequired: ["MOD_NOTES_AND_FLAGS"],
|
||||
@ -25,13 +26,13 @@ const i18n = useI18n();
|
||||
const route = useRoute();
|
||||
const flags = await useProjectFlags(props.project.id);
|
||||
|
||||
const headers = [
|
||||
const headers: Header[] = [
|
||||
{ title: "Submitter", name: "user" },
|
||||
{ title: "Reason", name: "reason" },
|
||||
{ title: "Comment", name: "comment" },
|
||||
{ title: "When", name: "createdAt" },
|
||||
{ title: "Resolved", name: "resolved" },
|
||||
] as Header[];
|
||||
];
|
||||
|
||||
useHead(useSeo("Flags | " + props.project.name, props.project.description, route, projectIconUrl(props.project.namespace.owner, props.project.namespace.slug)));
|
||||
</script>
|
||||
|
@ -7,7 +7,7 @@ import { useHead } from "@vueuse/head";
|
||||
import { useRoute } from "vue-router";
|
||||
import Card from "~/lib/components/design/Card.vue";
|
||||
import Link from "~/lib/components/design/Link.vue";
|
||||
import SortableTable, { Header } from "~/components/SortableTable.vue";
|
||||
import SortableTable from "~/components/SortableTable.vue";
|
||||
import Alert from "~/lib/components/design/Alert.vue";
|
||||
import { useProjectNotes } from "~/composables/useApiHelper";
|
||||
import { handleRequestError } from "~/composables/useErrorHandling";
|
||||
@ -17,6 +17,7 @@ import Button from "~/lib/components/design/Button.vue";
|
||||
import { useSeo } from "~/composables/useSeo";
|
||||
import { projectIconUrl } from "~/composables/useUrlHelper";
|
||||
import { definePageMeta } from "#imports";
|
||||
import { Header } from "~/types/components/SortableTable";
|
||||
|
||||
definePageMeta({
|
||||
projectPermsRequired: ["MOD_NOTES_AND_FLAGS"],
|
||||
@ -32,11 +33,11 @@ const notes = await useProjectNotes(props.project.id);
|
||||
const text = ref("");
|
||||
const loading = ref(false);
|
||||
|
||||
const headers = [
|
||||
const headers: Header[] = [
|
||||
{ title: "Date", name: "createdAt", width: "10%" },
|
||||
{ title: "User", name: "userName", width: "10%" },
|
||||
{ title: "Message", name: "message", width: "80%" },
|
||||
] as Header[];
|
||||
];
|
||||
|
||||
useHead(useSeo("Notes | " + props.project.name, props.project.description, route, projectIconUrl(props.project.namespace.owner, props.project.namespace.slug)));
|
||||
|
||||
|
@ -34,6 +34,7 @@ import "vue-advanced-cropper/dist/style.css";
|
||||
import InputAutocomplete from "~/lib/components/ui/InputAutocomplete.vue";
|
||||
import { definePageMeta } from "#imports";
|
||||
import Alert from "~/lib/components/design/Alert.vue";
|
||||
import { Tab } from "~/lib/types/components/design/Tabs";
|
||||
|
||||
definePageMeta({
|
||||
projectPermsRequired: ["EDIT_SUBJECT_SETTINGS"],
|
||||
@ -49,7 +50,7 @@ const props = defineProps<{
|
||||
}>();
|
||||
|
||||
const selectedTab = ref(route.hash.substring(1) || "general");
|
||||
const tabs = [
|
||||
const tabs: Tab[] = [
|
||||
{ value: "general", header: i18n.t("project.settings.tabs.general") },
|
||||
{ value: "links", header: i18n.t("project.settings.tabs.links") },
|
||||
{ value: "management", header: i18n.t("project.settings.tabs.management") },
|
||||
@ -94,7 +95,7 @@ function changeImage({ canvas }: CropperResult) {
|
||||
});
|
||||
}
|
||||
|
||||
const newName = ref<string | null>("");
|
||||
const newName = ref<string | null | undefined>("");
|
||||
const newNameField = ref<InstanceType<typeof InputText> | null>(null);
|
||||
const loading = reactive({
|
||||
save: false,
|
||||
@ -112,7 +113,7 @@ watch(selectedTab, (val) => history.replaceState({}, "", route.path + "#" + val)
|
||||
|
||||
const search = ref<string>("");
|
||||
const result = ref<string[]>([]);
|
||||
async function doSearch(val: string) {
|
||||
async function doSearch(val: unknown) {
|
||||
result.value = [];
|
||||
const users = await useApi<PaginatedResult<User>>("users", "get", {
|
||||
query: val,
|
||||
@ -272,8 +273,8 @@ useHead(
|
||||
<InputText
|
||||
v-model="form.description"
|
||||
counter
|
||||
:maxlength="useBackendData.validations?.project?.desc?.max"
|
||||
:rules="[required(), maxLength()(useBackendData.validations?.project?.desc?.max)]"
|
||||
:maxlength="useBackendData.validations?.project?.desc?.max || 120"
|
||||
:rules="[required(), maxLength()(useBackendData.validations?.project?.desc?.max || 120)]"
|
||||
/>
|
||||
</ProjectSettingsSection>
|
||||
<!-- todo: forums integration -->
|
||||
@ -284,9 +285,9 @@ useHead(
|
||||
<InputTag
|
||||
v-model="form.settings.keywords"
|
||||
counter
|
||||
:maxlength="useBackendData.validations?.project.keywords.max"
|
||||
:maxlength="useBackendData.validations?.project?.keywords?.max || 5"
|
||||
:label="i18n.t('project.new.step3.keywords')"
|
||||
:rules="[maxLength()(useBackendData.validations?.project.keywords.max)]"
|
||||
:rules="[maxLength()(useBackendData.validations?.project?.keywords?.max || 5)]"
|
||||
/>
|
||||
</ProjectSettingsSection>
|
||||
<ProjectSettingsSection>
|
||||
|
@ -100,7 +100,7 @@ async function savePage(content: string) {
|
||||
}
|
||||
editingPage.value = false;
|
||||
} catch (err) {
|
||||
handleRequestError(err as AxiosError, i18n, "page.new.error.save");
|
||||
handleRequestError(err, "page.new.error.save");
|
||||
}
|
||||
}
|
||||
|
||||
@ -155,7 +155,7 @@ async function restoreVersion() {
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div v-if="projectVersion" class="flex <sm:flex-col flex-wrap md:flex-nowrap gap-4">
|
||||
<div v-if="projectVersion && platform" class="flex <sm:flex-col flex-wrap md:flex-nowrap gap-4">
|
||||
<section class="basis-full md:basis-9/12 flex-grow overflow-auto">
|
||||
<div class="flex flex-wrap gap-2 justify-between">
|
||||
<div>
|
||||
@ -340,7 +340,7 @@ async function restoreVersion() {
|
||||
</div>
|
||||
</Card>
|
||||
|
||||
<Card v-if="projectVersion.pluginDependencies[platform?.name.toUpperCase()] || hasPerms(NamedPermission.EDIT_VERSION)">
|
||||
<Card v-if="(platform?.name && projectVersion?.pluginDependencies[platform?.name.toUpperCase()]) || hasPerms(NamedPermission.EDIT_VERSION)">
|
||||
<template #header>
|
||||
<div class="inline-flex w-full">
|
||||
<h3 class="flex-grow">{{ i18n.t("version.page.dependencies") }}</h3>
|
||||
|
@ -378,7 +378,7 @@ useHead(
|
||||
<div v-if="isCurrentReviewOpen && currentUserReview === review" class="space-x-1">
|
||||
<TextAreaModal :title="t('reviews.stopReview')" :label="t('general.message')" :submit="stopReview">
|
||||
<template #activator="slotProps">
|
||||
<Button size="small" color="error" v-bind="slotProps.attrs" v-on="slotProps.on">
|
||||
<Button size="small" color="error" v-on="slotProps.on">
|
||||
<IconMdiStop />
|
||||
{{ t("reviews.stopReview") }}
|
||||
</Button>
|
||||
|
@ -9,7 +9,7 @@ import { remove } from "lodash-es";
|
||||
import { type ValidationRule } from "@vuelidate/core";
|
||||
import { useSeo } from "~/composables/useSeo";
|
||||
import { projectIconUrl } from "~/composables/useUrlHelper";
|
||||
import Steps, { Step } from "~/lib/components/design/Steps.vue";
|
||||
import Steps from "~/lib/components/design/Steps.vue";
|
||||
import InputFile from "~/lib/components/ui/InputFile.vue";
|
||||
import InputText from "~/lib/components/ui/InputText.vue";
|
||||
import InputSelect from "~/lib/components/ui/InputSelect.vue";
|
||||
@ -25,10 +25,12 @@ import ChannelModal from "~/components/modals/ChannelModal.vue";
|
||||
import { useBackendData } from "~/store/backendData";
|
||||
import DependencyTable from "~/components/projects/DependencyTable.vue";
|
||||
import InputTag from "~/lib/components/ui/InputTag.vue";
|
||||
import Tabs, { Tab } from "~/lib/components/design/Tabs.vue";
|
||||
import Tabs from "~/lib/components/design/Tabs.vue";
|
||||
import PlatformLogo from "~/components/logos/platforms/PlatformLogo.vue";
|
||||
import { useProjectChannels } from "~/composables/useApiHelper";
|
||||
import { definePageMeta } from "#imports";
|
||||
import { Step } from "~/lib/types/components/design/Steps";
|
||||
import { Tab } from "~/lib/types/components/design/Tabs";
|
||||
|
||||
definePageMeta({
|
||||
projectPermsRequired: ["CREATE_VERSION"],
|
||||
@ -302,8 +304,8 @@ useHead(
|
||||
</div>
|
||||
<div class="basis-full md:(basis-4/12 -ml-2)">
|
||||
<ChannelModal :project-id="project.id" @create="addChannel">
|
||||
<template #activator="{ on, attrs }">
|
||||
<Button class="basis-4/12" v-bind="attrs" size="medium" v-on="on">
|
||||
<template #activator="{ on }">
|
||||
<Button class="basis-4/12" size="medium" v-on="on">
|
||||
<IconMdiPlus />
|
||||
{{ t("version.new.form.addChannel") }}
|
||||
</Button>
|
||||
@ -345,7 +347,7 @@ useHead(
|
||||
<p class="mb-4">{{ i18n.t("version.new.form.versionDescription") }}</p>
|
||||
<div class="flex flex-wrap mt-2 md:-space-x-2 <md:space-y-2">
|
||||
<!-- TODO validate version string against existing versions - now super easy! -->
|
||||
<div class="basis-full md:basis-4/12 items-center">
|
||||
<div v-if="pendingVersion" class="basis-full md:basis-4/12 items-center">
|
||||
<InputText
|
||||
v-model="pendingVersion.versionString"
|
||||
:label="t('version.new.form.versionString')"
|
||||
@ -357,7 +359,7 @@ useHead(
|
||||
</div>
|
||||
|
||||
<p class="mt-8 text-xl">{{ t("version.new.form.addedArtifacts") }}</p>
|
||||
<div v-for="(pendingFile, idx) in pendingVersion.files" :key="idx" class="mb-2">
|
||||
<div v-for="(pendingFile, idx) in pendingVersion?.files" :key="idx" class="mb-2">
|
||||
<div class="flex flex-wrap items-center mt-4">
|
||||
<div v-if="pendingFile.fileInfo" class="basis-full <md:mt-4 md:basis-4/12">
|
||||
<InputText :model-value="pendingFile.fileInfo.name" :label="t('version.new.form.fileName')" disabled />
|
||||
@ -383,7 +385,12 @@ useHead(
|
||||
<div v-for="platform in selectedPlatformsData" :key="platform.enumName" class="basis-full">
|
||||
<span class="text-lg inline-flex items-center"><PlatformLogo :platform="platform.enumName" :size="25" class="mr-1" /> {{ platform.name }}</span>
|
||||
<div class="mt-2">
|
||||
<InputTag v-model="pendingVersion.platformDependencies[platform.enumName]" :options="platform.possibleVersions" :rules="platformVersionRules" />
|
||||
<InputTag
|
||||
v-if="pendingVersion"
|
||||
v-model="pendingVersion.platformDependencies[platform.enumName]"
|
||||
:options="platform.possibleVersions"
|
||||
:rules="platformVersionRules"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@ -392,7 +399,13 @@ useHead(
|
||||
<div class="flex flex-wrap space-y-7">
|
||||
<div v-for="platform in selectedPlatformsData" :key="platform.enumName" class="basis-full">
|
||||
<span class="text-lg inline-flex items-center"><PlatformLogo :platform="platform.enumName" :size="25" class="mr-1" /> {{ platform.name }}</span>
|
||||
<DependencyTable ref="dependencyTables" :key="`${platform.name}-deps-table`" :platform="platform.enumName" :version="pendingVersion" />
|
||||
<DependencyTable
|
||||
v-if="pendingVersion"
|
||||
ref="dependencyTables"
|
||||
:key="`${platform.name}-deps-table`"
|
||||
:platform="platform.enumName"
|
||||
:version="pendingVersion"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
@ -3,7 +3,7 @@ import { useI18n } from "vue-i18n";
|
||||
import { Review, ReviewQueueEntry } from "hangar-internal";
|
||||
import { useHead } from "@vueuse/head";
|
||||
import { useRoute } from "vue-router";
|
||||
import SortableTable, { Header } from "~/components/SortableTable.vue";
|
||||
import SortableTable from "~/components/SortableTable.vue";
|
||||
import { ReviewAction } from "~/types/enums";
|
||||
import { useVersionApprovals } from "~/composables/useApiHelper";
|
||||
import Card from "~/lib/components/design/Card.vue";
|
||||
@ -12,6 +12,7 @@ import Tag from "~/components/Tag.vue";
|
||||
import { useSeo } from "~/composables/useSeo";
|
||||
import Button from "~/lib/components/design/Button.vue";
|
||||
import { definePageMeta } from "#imports";
|
||||
import { Header } from "~/types/components/SortableTable";
|
||||
|
||||
definePageMeta({
|
||||
globalPermsRequired: ["REVIEWER"],
|
||||
|
@ -6,8 +6,9 @@ import { useHead } from "@vueuse/head";
|
||||
import PageTitle from "~/lib/components/design/PageTitle.vue";
|
||||
import { useSeo } from "~/composables/useSeo";
|
||||
import Flags from "~/components/Flags.vue";
|
||||
import Tabs, { Tab } from "~/lib/components/design/Tabs.vue";
|
||||
import Tabs from "~/lib/components/design/Tabs.vue";
|
||||
import { definePageMeta } from "#imports";
|
||||
import { Tab } from "~/lib/types/components/design/Tabs";
|
||||
|
||||
definePageMeta({
|
||||
globalPermsRequired: ["MOD_NOTES_AND_FLAGS"],
|
||||
|
@ -9,7 +9,7 @@ import { debounce } from "lodash-es";
|
||||
import PageTitle from "~/lib/components/design/PageTitle.vue";
|
||||
import { useActionLogs } from "~/composables/useApiHelper";
|
||||
import Card from "~/lib/components/design/Card.vue";
|
||||
import SortableTable, { Header } from "~/components/SortableTable.vue";
|
||||
import SortableTable from "~/components/SortableTable.vue";
|
||||
import Link from "~/lib/components/design/Link.vue";
|
||||
import MarkdownModal from "~/components/modals/MarkdownModal.vue";
|
||||
import DiffModal from "~/components/modals/DiffModal.vue";
|
||||
@ -19,6 +19,7 @@ import { definePageMeta, useInternalApi, watch } from "#imports";
|
||||
import InputText from "~/lib/components/ui/InputText.vue";
|
||||
import InputSelect from "~/lib/components/ui/InputSelect.vue";
|
||||
import { useBackendData } from "~/store/backendData";
|
||||
import { Header } from "~/types/components/SortableTable";
|
||||
|
||||
definePageMeta({
|
||||
globalPermsRequired: ["VIEW_LOGS"],
|
||||
@ -29,7 +30,7 @@ const route = useRoute();
|
||||
const loggedActions = await useActionLogs();
|
||||
|
||||
// TODO add support for sorting
|
||||
const headers = [
|
||||
const headers: Header[] = [
|
||||
{ title: i18n.t("userActionLog.user"), name: "user", sortable: false },
|
||||
{ title: i18n.t("userActionLog.address"), name: "address", sortable: false },
|
||||
{ title: i18n.t("userActionLog.time"), name: "time", sortable: false },
|
||||
@ -37,7 +38,7 @@ const headers = [
|
||||
{ title: i18n.t("userActionLog.context"), name: "context", sortable: false },
|
||||
{ title: i18n.t("userActionLog.oldState"), name: "oldState", sortable: false },
|
||||
{ title: i18n.t("userActionLog.newState"), name: "newState", sortable: false },
|
||||
] as Header[];
|
||||
];
|
||||
|
||||
const page = ref(0);
|
||||
const sort = ref<string[]>([]);
|
||||
|
@ -1,6 +1,6 @@
|
||||
<script lang="ts" setup>
|
||||
import { useI18n } from "vue-i18n";
|
||||
import { PaginatedResult, Project, User } from "hangar-api";
|
||||
import { User } from "hangar-api";
|
||||
import { useRoute, useRouter } from "vue-router";
|
||||
import { OrganizationRoleTable } from "hangar-internal";
|
||||
import { computed, ref } from "vue";
|
||||
@ -11,7 +11,7 @@ import Link from "~/lib/components/design/Link.vue";
|
||||
import Card from "~/lib/components/design/Card.vue";
|
||||
import { useApi, useInternalApi } from "~/composables/useApi";
|
||||
import { handleRequestError } from "~/composables/useErrorHandling";
|
||||
import SortableTable, { Header } from "~/components/SortableTable.vue";
|
||||
import SortableTable from "~/components/SortableTable.vue";
|
||||
import InputCheckbox from "~/lib/components/ui/InputCheckbox.vue";
|
||||
import { useSeo } from "~/composables/useSeo";
|
||||
import { authUrl, forumUserUrl } from "~/composables/useUrlHelper";
|
||||
@ -21,6 +21,7 @@ import InputSelect from "~/lib/components/ui/InputSelect.vue";
|
||||
import { useBackendData } from "~/store/backendData";
|
||||
import Button from "~/lib/components/design/Button.vue";
|
||||
import { definePageMeta } from "#imports";
|
||||
import { Header } from "~/types/components/SortableTable";
|
||||
|
||||
definePageMeta({
|
||||
globalPermsRequired: ["EDIT_ALL_USER_SETTINGS"],
|
||||
@ -36,19 +37,19 @@ const orgs = await useInternalApi<{ [key: string]: OrganizationRoleTable }>(`org
|
||||
);
|
||||
const user = await useUser(route.params.user as string);
|
||||
|
||||
const projectsConfig = [
|
||||
const projectsConfig: Header[] = [
|
||||
{ title: i18n.t("userAdmin.project"), name: "name" },
|
||||
{ title: i18n.t("userAdmin.owner"), name: "owner" },
|
||||
{ title: i18n.t("userAdmin.role"), name: "role" },
|
||||
{ title: i18n.t("userAdmin.accepted"), name: "accepted" },
|
||||
] as Header[];
|
||||
];
|
||||
|
||||
const orgConfig = [
|
||||
const orgConfig: Header[] = [
|
||||
{ title: i18n.t("userAdmin.organization"), name: "name" },
|
||||
{ title: i18n.t("userAdmin.owner"), name: "owner" },
|
||||
{ title: i18n.t("userAdmin.role"), name: "role" },
|
||||
{ title: i18n.t("userAdmin.accepted"), name: "accepted" },
|
||||
] as Header[];
|
||||
];
|
||||
|
||||
const orgList = computed(() => {
|
||||
return orgs
|
||||
|
@ -8,12 +8,13 @@ import PageTitle from "~/lib/components/design/PageTitle.vue";
|
||||
import Link from "~/lib/components/design/Link.vue";
|
||||
import Tag from "~/components/Tag.vue";
|
||||
import { useApi } from "~/composables/useApi";
|
||||
import { Header } from "~/components/SortableTable.vue";
|
||||
import { useSeo } from "~/composables/useSeo";
|
||||
import { definePageMeta, watch } from "#imports";
|
||||
import { useUsers } from "~/composables/useApiHelper";
|
||||
import InputCheckbox from "~/lib/components/ui/InputCheckbox.vue";
|
||||
import InputText from "~/lib/components/ui/InputText.vue";
|
||||
import { Header } from "~/types/components/SortableTable";
|
||||
import SortableTable from "~/components/SortableTable.vue";
|
||||
|
||||
definePageMeta({
|
||||
globalPermsRequired: ["EDIT_ALL_USER_SETTINGS"],
|
||||
@ -23,7 +24,7 @@ const i18n = useI18n();
|
||||
const route = useRoute();
|
||||
const router = useRouter();
|
||||
|
||||
const headers = [
|
||||
const headers: Header[] = [
|
||||
{ name: "pic", title: "", sortable: false },
|
||||
{ name: "name", title: i18n.t("pages.headers.username"), sortable: true },
|
||||
{ name: "roles", title: i18n.t("pages.headers.roles"), sortable: true },
|
||||
@ -31,7 +32,7 @@ const headers = [
|
||||
{ name: "projectCount", title: i18n.t("pages.headers.projects"), sortable: true },
|
||||
{ name: "locked", title: i18n.t("pages.headers.locked"), sortable: true },
|
||||
{ name: "org", title: i18n.t("pages.headers.organization"), sortable: true },
|
||||
] as Header[];
|
||||
];
|
||||
|
||||
const users = await useUsers();
|
||||
const page = ref(0);
|
||||
|
@ -5,22 +5,22 @@ import { useHead } from "@vueuse/head";
|
||||
import { PaginatedResult, User } from "hangar-api";
|
||||
import { computed, ref } from "vue";
|
||||
import { useAuthors } from "~/composables/useApiHelper";
|
||||
import { handleRequestError } from "~/composables/useErrorHandling";
|
||||
import SortableTable, { Header } from "~/components/SortableTable.vue";
|
||||
import SortableTable from "~/components/SortableTable.vue";
|
||||
import PageTitle from "~/lib/components/design/PageTitle.vue";
|
||||
import UserAvatar from "~/components/UserAvatar.vue";
|
||||
import { useSeo } from "~/composables/useSeo";
|
||||
import Link from "~/lib/components/design/Link.vue";
|
||||
import { useApi } from "~/composables/useApi";
|
||||
import { Header } from "~/types/components/SortableTable";
|
||||
const i18n = useI18n();
|
||||
const route = useRoute();
|
||||
|
||||
const headers = [
|
||||
const headers: Header[] = [
|
||||
{ name: "pic", title: "", sortable: false },
|
||||
{ name: "name", title: i18n.t("pages.headers.username"), sortable: true },
|
||||
{ name: "joinDate", title: i18n.t("pages.headers.joined"), sortable: true },
|
||||
{ name: "projectCount", title: i18n.t("pages.headers.projects"), sortable: true },
|
||||
] as Header[];
|
||||
];
|
||||
|
||||
const page = ref(0);
|
||||
const sort = ref<string[]>(["-projectCount"]);
|
||||
|
@ -37,7 +37,7 @@ const toArray = (input: unknown) => (Array.isArray(input) ? input : input ? [inp
|
||||
const filters = ref({
|
||||
versions: toArray(route.query.version),
|
||||
categories: toArray(route.query.category),
|
||||
platform: route.query.platform || null,
|
||||
platform: (route.query.platform || null) as string | null,
|
||||
licenses: toArray(route.query.license),
|
||||
});
|
||||
|
||||
|
@ -10,12 +10,12 @@ import { handleRequestError } from "~/composables/useErrorHandling";
|
||||
import { useInternalApi } from "~/composables/useApi";
|
||||
import { useBackendData, useCategoryOptions, useLicenseOptions } from "~/store/backendData";
|
||||
import { useSeo } from "~/composables/useSeo";
|
||||
import Steps, { Step } from "~/lib/components/design/Steps.vue";
|
||||
import Steps from "~/lib/components/design/Steps.vue";
|
||||
import { useSettingsStore } from "~/store/useSettingsStore";
|
||||
import InputSelect from "~/lib/components/ui/InputSelect.vue";
|
||||
import InputText from "~/lib/components/ui/InputText.vue";
|
||||
import InputTag from "~/lib/components/ui/InputTag.vue";
|
||||
import Tabs, { Tab } from "~/lib/components/design/Tabs.vue";
|
||||
import Tabs from "~/lib/components/design/Tabs.vue";
|
||||
import Button from "~/lib/components/design/Button.vue";
|
||||
import Markdown from "~/components/Markdown.vue";
|
||||
import InputTextarea from "~/lib/components/ui/InputTextarea.vue";
|
||||
@ -25,6 +25,8 @@ import Spinner from "~/lib/components/design/Spinner.vue";
|
||||
import Link from "~/lib/components/design/Link.vue";
|
||||
import { usePossibleOwners } from "~/composables/useApiHelper";
|
||||
import { definePageMeta } from "#imports";
|
||||
import { Step } from "~/lib/types/components/design/Steps";
|
||||
import { Tab } from "~/lib/types/components/design/Tabs";
|
||||
|
||||
interface NewProjectForm extends ProjectSettingsForm {
|
||||
ownerId: ProjectOwner["userId"];
|
||||
@ -80,7 +82,7 @@ const steps: Step[] = [
|
||||
{
|
||||
value: "tos",
|
||||
header: i18n.t("project.new.step1.title"),
|
||||
showBack: () => false,
|
||||
showBack: false,
|
||||
},
|
||||
{
|
||||
value: "basic",
|
||||
@ -98,7 +100,7 @@ const steps: Step[] = [
|
||||
return true;
|
||||
},
|
||||
},
|
||||
{ value: "finishing", header: i18n.t("project.new.step5.title"), showNext: () => false, showBack: () => false },
|
||||
{ value: "finishing", header: i18n.t("project.new.step5.title"), showNext: false, showBack: false },
|
||||
];
|
||||
|
||||
const selectBBCodeTab = ref("convert");
|
||||
@ -249,8 +251,8 @@ function createProject() {
|
||||
<InputTag
|
||||
v-model="form.settings.keywords"
|
||||
:label="i18n.t('project.new.step3.keywords')"
|
||||
:rules="[maxLength()(useBackendData.validations.project.keywords.max)]"
|
||||
:maxlength="useBackendData.validations.project.keywords.max"
|
||||
:rules="[maxLength()(useBackendData?.validations?.project?.keywords?.max || 5)]"
|
||||
:maxlength="useBackendData?.validations?.project?.keywords?.max || 5"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -18,8 +18,9 @@ import IconMdiInformationOutline from "~icons/mdi/information-outline";
|
||||
import IconMdiMessageOutline from "~icons/mdi/message-outline";
|
||||
import IconMdiCheck from "~icons/mdi/check";
|
||||
import Pagination from "~/lib/components/design/Pagination.vue";
|
||||
import Tabs, { Tab } from "~/lib/components/design/Tabs.vue";
|
||||
import Tabs from "~/lib/components/design/Tabs.vue";
|
||||
import { definePageMeta } from "#imports";
|
||||
import { Tab } from "~/lib/types/components/design/Tabs";
|
||||
|
||||
definePageMeta({
|
||||
loginRequired: true,
|
||||
|
@ -5,24 +5,24 @@ import { useHead } from "@vueuse/head";
|
||||
import { computed, ref } from "vue";
|
||||
import { PaginatedResult, User } from "hangar-api";
|
||||
import { useStaff } from "~/composables/useApiHelper";
|
||||
import { handleRequestError } from "~/composables/useErrorHandling";
|
||||
import SortableTable, { Header } from "~/components/SortableTable.vue";
|
||||
import SortableTable from "~/components/SortableTable.vue";
|
||||
import PageTitle from "~/lib/components/design/PageTitle.vue";
|
||||
import { useSeo } from "~/composables/useSeo";
|
||||
import UserAvatar from "~/components/UserAvatar.vue";
|
||||
import Link from "~/lib/components/design/Link.vue";
|
||||
import Tag from "~/components/Tag.vue";
|
||||
import { useApi } from "~/composables/useApi";
|
||||
import { Header } from "~/types/components/SortableTable";
|
||||
|
||||
const i18n = useI18n();
|
||||
const route = useRoute();
|
||||
|
||||
const headers = [
|
||||
const headers: Header[] = [
|
||||
{ name: "pic", title: "", sortable: false },
|
||||
{ name: "name", title: i18n.t("pages.headers.username"), sortable: true },
|
||||
{ name: "roles", title: i18n.t("pages.headers.roles"), sortable: true },
|
||||
{ name: "joinDate", title: i18n.t("pages.headers.joined"), sortable: true },
|
||||
] as Header[];
|
||||
];
|
||||
|
||||
const page = ref(0);
|
||||
const sort = ref<string[]>(["roles"]);
|
||||
|
@ -4,7 +4,7 @@ import { IPlatform, IProjectCategory, IPrompt } from "hangar-internal";
|
||||
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
||||
// @ts-ignore
|
||||
import backendData from "~/generated/backendData.json";
|
||||
import { Option } from "~/lib/components/ui/InputAutocomplete.vue";
|
||||
import { Option } from "~/lib/types/components/ui/InputAutocomplete";
|
||||
|
||||
const typedBackendData = backendData as unknown as BackendData;
|
||||
|
||||
|
@ -17,7 +17,7 @@ export const usePrismStore = defineStore("prism", () => {
|
||||
|
||||
async function loadLanguages() {
|
||||
const langs = new Set<string>();
|
||||
for (const codeBlock of document.querySelectorAll('code[class*="language-"]')) {
|
||||
for (const codeBlock of document.querySelectorAll('code[class*="language-"]') as any as Element[]) {
|
||||
langs.add(codeBlock.className.replace("language-", ""));
|
||||
}
|
||||
prismLog("Load languages", langs);
|
||||
|
6
frontend/src/types/api/projects.d.ts
vendored
6
frontend/src/types/api/projects.d.ts
vendored
@ -23,9 +23,9 @@ declare module "hangar-api" {
|
||||
}
|
||||
|
||||
interface License {
|
||||
name: string | null;
|
||||
url: string | null;
|
||||
type: string | null;
|
||||
name?: string | null;
|
||||
url?: string | null;
|
||||
type?: string | null;
|
||||
}
|
||||
|
||||
interface ProjectSettings {
|
||||
|
6
frontend/src/types/components/SortableTable.d.ts
vendored
Normal file
6
frontend/src/types/components/SortableTable.d.ts
vendored
Normal file
@ -0,0 +1,6 @@
|
||||
export interface Header {
|
||||
name: string;
|
||||
title: string;
|
||||
sortable?: boolean;
|
||||
width?: string;
|
||||
}
|
@ -4,8 +4,8 @@
|
||||
"compilerOptions": {
|
||||
"baseUrl": ".",
|
||||
"module": "ESNext",
|
||||
"target": "es2017",
|
||||
"lib": ["DOM", "ESNext"],
|
||||
"target": "ES2020",
|
||||
"lib": ["DOM", "ES2020"],
|
||||
"strict": true,
|
||||
"esModuleInterop": true,
|
||||
"incremental": true,
|
||||
|
Loading…
x
Reference in New Issue
Block a user