diff --git a/.idea/encodings.xml b/.idea/encodings.xml index 97626ba4..99437e25 100644 --- a/.idea/encodings.xml +++ b/.idea/encodings.xml @@ -1,6 +1,7 @@ + \ No newline at end of file diff --git a/frontend/src/components/Flags.vue b/frontend/src/components/Flags.vue index 9ad6576f..e94afbf0 100644 --- a/frontend/src/components/Flags.vue +++ b/frontend/src/components/Flags.vue @@ -20,7 +20,7 @@ const props = defineProps<{ const i18n = useI18n(); const route = useRoute(); -const flags = await (props.resolved ? useResolvedFlags() : useUnresolvedFlags()).catch((e) => handleRequestError(e)); +const flags = await (props.resolved ? useResolvedFlags() : useUnresolvedFlags()); const loading = ref<{ [key: number]: boolean }>({}); function resolve(flag: Flag) { @@ -45,6 +45,7 @@ function resolve(flag: Flag) { // TODO: bake into hangarflag? const notifications = ref([]); const currentId = ref(-1); + async function getNotifications(flag: Flag) { if (currentId.value === flag.id) { return; @@ -83,7 +84,10 @@ async function getNotifications(flag: Flag) { diff --git a/frontend/src/components/layout/Header.vue b/frontend/src/components/layout/Header.vue index 33d58188..b1ff9953 100644 --- a/frontend/src/components/layout/Header.vue +++ b/frontend/src/components/layout/Header.vue @@ -122,25 +122,23 @@ function updateNotifications() { unreadNotifications.value = v.value; } }); - useRecentNotifications(30) - .then((v) => { - if (v && v.value) { - // Only show notifications that are recent or unread (from the last 30 notifications) - let filteredAmount = 0; - notifications.value = v.value.filter((notification: HangarNotification) => { - if (filteredAmount < 8 && (!notification.read || isRecent(notification.createdAt))) { - if (!notification.read) { - loadedUnreadNotifications.value++; - } - - filteredAmount++; - return true; + useRecentNotifications(30).then((v) => { + if (v && v.value) { + // Only show notifications that are recent or unread (from the last 30 notifications) + let filteredAmount = 0; + notifications.value = v.value.filter((notification: HangarNotification) => { + if (filteredAmount < 8 && (!notification.read || isRecent(notification.createdAt))) { + if (!notification.read) { + loadedUnreadNotifications.value++; } - return false; - }); - } - }) - .catch((e) => handleRequestError(e)); + + filteredAmount++; + return true; + } + return false; + }); + } + }); } function isRecent(date: string): boolean { diff --git a/frontend/src/composables/useApiHelper.ts b/frontend/src/composables/useApiHelper.ts index 2de58f09..13712e6e 100644 --- a/frontend/src/composables/useApiHelper.ts +++ b/frontend/src/composables/useApiHelper.ts @@ -16,160 +16,179 @@ import { RoleTable, } from "hangar-internal"; import { AsyncData } from "nuxt/app"; +import { ref, Ref } from "vue"; import { useApi, useInternalApi } from "~/composables/useApi"; import { useAsyncData } from "#imports"; +import { handleRequestError } from "~/composables/useErrorHandling"; -export async function useProjects(params: Record = { limit: 25, offset: 0 }) { +export async function useProjects(params: Record = { limit: 25, offset: 0 }): Promise | null>> { return extract(await useAsyncData("useProjects", () => useApi>("projects", "get", params))); } -export async function useUser(user: string) { +export async function useUser(user: string): Promise> { return extract(await useAsyncData("useUser:" + user, () => useApi("users/" + user))); } -export async function useOrganization(user: string) { +export async function useOrganization(user: string): Promise> { return extract(await useAsyncData("useOrganization:" + user, () => useInternalApi(`organizations/org/${user}`))); } -export async function useProject(user: string, project: string) { +export async function useProject(user: string, project: string): Promise> { return extract(await useAsyncData("useProject:" + user + ":" + project, () => useInternalApi("projects/project/" + user + "/" + project))); } -export async function useStargazers(user: string, project: string) { +export async function useStargazers(user: string, project: string): Promise | null>> { return extract(await useAsyncData("useStargazers:" + user + ":" + project, () => useApi>(`projects/${user}/${project}/stargazers`))); } -export async function useWatchers(user: string, project: string) { +export async function useWatchers(user: string, project: string): Promise | null>> { return extract(await useAsyncData("useWatchers:" + user + ":" + project, () => useApi>(`projects/${user}/${project}/watchers`))); } -export async function useStaff(params?: { offset?: number; limit?: number; sort?: string[] }) { +export async function useStaff(params?: { offset?: number; limit?: number; sort?: string[] }): Promise | null>> { return extract(await useAsyncData("useStaff", () => useApi>("staff", "GET", params))); } -export async function useAuthors(params?: { offset?: number; limit?: number; sort?: string[] }) { +export async function useAuthors(params?: { offset?: number; limit?: number; sort?: string[] }): Promise | null>> { return extract(await useAsyncData("useAuthors", () => useApi>("authors", "GET", params))); } -export async function useUsers() { +export async function useUsers(): Promise | null>> { return extract(await useAsyncData("useUsers", () => useApi>("users"))); } -export async function useInvites() { +export async function useInvites(): Promise> { return extract(await useAsyncData("useInvites", () => useInternalApi("invites"))); } -export async function useNotifications() { +export async function useNotifications(): Promise | null>> { return extract(await useAsyncData("useNotifications", () => useInternalApi>("notifications"))); } -export async function useUnreadNotifications() { +export async function useUnreadNotifications(): Promise | null>> { return extract(await useAsyncData("useUnreadNotifications", () => useInternalApi>("unreadnotifications"))); } -export async function useReadNotifications() { +export async function useReadNotifications(): Promise | null>> { return extract(await useAsyncData("useReadNotifications", () => useInternalApi>("readnotifications"))); } -export async function useRecentNotifications(amount: number) { +export async function useRecentNotifications(amount: number): Promise> { return extract(await useAsyncData("useRecentNotifications:" + amount, () => useInternalApi("recentnotifications?amount=" + amount))); } -export async function useUnreadNotificationsCount() { +export async function useUnreadNotificationsCount(): Promise> { return extract(await useAsyncData("useUnreadNotificationsCount", () => useInternalApi("unreadcount"))); } -export async function useResolvedFlags() { +export async function useResolvedFlags(): Promise | null>> { return extract(await useAsyncData("useResolvedFlags", () => useInternalApi>("flags/resolved"))); } -export async function useUnresolvedFlags() { +export async function useUnresolvedFlags(): Promise | null>> { return extract(await useAsyncData("useUnresolvedFlags", () => useInternalApi>("flags/unresolved"))); } -export async function useProjectFlags(projectId: number) { +export async function useProjectFlags(projectId: number): Promise> { return extract(await useAsyncData("useProjectFlags:" + projectId, () => useInternalApi("flags/" + projectId))); } -export async function useProjectNotes(projectId: number) { +export async function useProjectNotes(projectId: number): Promise> { return extract(await useAsyncData("useProjectNotes:" + projectId, () => useInternalApi("projects/notes/" + projectId))); } -export async function useProjectChannels(user: string, project: string) { +export async function useProjectChannels(user: string, project: string): Promise> { return extract(await useAsyncData("useProjectChannels:" + user + ":" + project, () => useInternalApi(`channels/${user}/${project}`))); } -export async function useProjectVersions(user: string, project: string) { +export async function useProjectVersions(user: string, project: string): Promise | null>> { return extract( await useAsyncData("useProjectVersions:" + user + ":" + project, () => useApi>(`projects/${user}/${project}/versions`)) ); } -export async function useProjectVersionsInternal(user: string, project: string, version: string) { - return await useAsyncData("useProjectVersionsInternal:" + user + ":" + project + ":" + version, () => - useInternalApi(`versions/version/${user}/${project}/versions/${version}`) +export async function useProjectVersionsInternal(user: string, project: string, version: string): Promise> { + return extract( + await useAsyncData("useProjectVersionsInternal:" + user + ":" + project + ":" + version, () => + useInternalApi(`versions/version/${user}/${project}/versions/${version}`) + ) ); } -export async function usePage(user: string, project: string, path?: string) { - return await useAsyncData("usePage:" + user + ":" + project + ":" + path, () => - useInternalApi(`pages/page/${user}/${project}` + (path ? "/" + path : "")) +export async function usePage(user: string, project: string, path?: string): Promise> { + return extract( + await useAsyncData("usePage:" + user + ":" + project + ":" + path, () => + useInternalApi(`pages/page/${user}/${project}` + (path ? "/" + path : "")) + ) ); } -export async function useHealthReport() { +export async function useHealthReport(): Promise> { return extract(await useAsyncData("useHealthReport", () => useInternalApi("admin/health"))); } -export async function useActionLogs() { +export async function useActionLogs(): Promise | null>> { return extract(await useAsyncData("useActionLogs", () => useInternalApi>("admin/log/"))); } -export async function useVersionApprovals() { - return await useAsyncData("useVersionApprovals", () => - useInternalApi<{ underReview: ReviewQueueEntry[]; notStarted: ReviewQueueEntry[] }>("admin/approval/versions") +export async function useVersionApprovals(): Promise> { + return extract( + await useAsyncData("useVersionApprovals", () => + useInternalApi<{ underReview: ReviewQueueEntry[]; notStarted: ReviewQueueEntry[] }>("admin/approval/versions") + ) ); } -export async function usePossibleOwners() { +export async function usePossibleOwners(): Promise> { return extract(await useAsyncData("usePossibleOwners", () => useInternalApi("projects/possibleOwners"))); } -export async function useOrgVisibility(user: string) { +export async function useOrgVisibility(user: string): Promise> { return extract( await useAsyncData("useOrgVisibility:" + user, () => useInternalApi<{ [key: string]: boolean }>(`organizations/${user}/userOrganizationsVisibility`)) ); } -export async function useVersionInfo() { +export async function useVersionInfo(): Promise> { return extract(await useAsyncData("useVersionInfo", () => useInternalApi(`data/version-info`))); } -export async function useUserData(user: string) { - return await useAsyncData("useUserData:" + user, async () => { - // noinspection ES6MissingAwait - const data = await Promise.all([ - useApi>(`users/${user}/starred`), - useApi>(`users/${user}/watching`), - useApi>(`projects`, "get", { - owner: user, - }), - useInternalApi<{ [key: string]: RoleTable }>(`organizations/${user}/userOrganizations`), - useApi(`users/${user}/pinned`), - ]); - return { - starred: data[0] as PaginatedResult, - watching: data[1] as PaginatedResult, - projects: data[2] as PaginatedResult, - organizations: data[3] as { [key: string]: RoleTable }, - pinned: data[4] as ProjectCompact[], - }; - }); +export async function useUserData(user: string): Promise< + Ref<{ + starred: PaginatedResult; + watching: PaginatedResult; + projects: PaginatedResult; + organizations: { [key: string]: RoleTable }; + pinned: ProjectCompact[]; + } | null> +> { + return extract( + await useAsyncData("useUserData:" + user, async () => { + // noinspection ES6MissingAwait + const data = await Promise.all([ + useApi>(`users/${user}/starred`), + useApi>(`users/${user}/watching`), + useApi>(`projects`, "get", { + owner: user, + }), + useInternalApi<{ [key: string]: RoleTable }>(`organizations/${user}/userOrganizations`), + useApi(`users/${user}/pinned`), + ]); + return { + starred: data[0] as PaginatedResult, + watching: data[1] as PaginatedResult, + projects: data[2] as PaginatedResult, + organizations: data[3] as { [key: string]: RoleTable }, + pinned: data[4] as ProjectCompact[], + }; + }) + ); } -function extract(asyncData: AsyncData) { +function extract(asyncData: AsyncData): Ref { if (asyncData.error?.value) { - throw asyncData.error.value; + handleRequestError(asyncData.error.value); + return ref(null); } else { return asyncData.data; } diff --git a/frontend/src/composables/useErrorHandling.ts b/frontend/src/composables/useErrorHandling.ts index e03c3ef9..66ef4826 100644 --- a/frontend/src/composables/useErrorHandling.ts +++ b/frontend/src/composables/useErrorHandling.ts @@ -6,14 +6,13 @@ import { useNotificationStore } from "~/lib/store/notification"; import { I18n } from "~/lib/i18n"; import { createError } from "#imports"; -export function handleRequestError(err: AxiosError, i18n: Composer = I18n.value, msg: string | undefined = undefined) { +export function handleRequestError(err: AxiosError | unknown, i18n: Composer = I18n.value, msg: string | undefined = undefined) { if (import.meta.env.SSR) { _handleRequestError(err, i18n); - return ref(); } const notfication = useNotificationStore(); const transformed = transformAxiosError(err); - if (!err.isAxiosError) { + if (!axios.isAxiosError(err)) { // everything should be an AxiosError console.log("no axios request error", transformed); notfication.error(transformed.message?.toString() || "Unknown error"); @@ -38,10 +37,9 @@ export function handleRequestError(err: AxiosError, i18n: Composer = I18n.value, console.log("unknown error", transformed); notfication.error(transformed.message?.toString() || "Unknown error"); } - return ref(); } -function _handleRequestError(err: AxiosError, i18n: Composer) { +function _handleRequestError(err: AxiosError | unknown, i18n: Composer) { function writeResponse(object: unknown) { console.log("writeResponse", object); // throw new Error("TODO: Implement me"); // TODO @@ -49,7 +47,7 @@ function _handleRequestError(err: AxiosError, i18n: Composer) { } const transformed = transformAxiosError(err); - if (!err.isAxiosError) { + if (!axios.isAxiosError(err)) { // everything should be an AxiosError writeResponse({ status: 500, diff --git a/frontend/src/composables/useProjectPage.ts b/frontend/src/composables/useProjectPage.ts index dd6d3f9e..20806640 100644 --- a/frontend/src/composables/useProjectPage.ts +++ b/frontend/src/composables/useProjectPage.ts @@ -8,7 +8,7 @@ import { usePage } from "~/composables/useApiHelper"; import { useErrorRedirect } from "~/lib/composables/useErrorRedirect"; export async function useProjectPage(route: RouteLocationNormalizedLoaded, router: Router, i18n: ReturnType, project: HangarProject) { - const page = await usePage(route.params.user as string, route.params.project as string, route.params.all as string).catch((e) => handleRequestError(e)); + const page = await usePage(route.params.user as string, route.params.project as string, route.params.all as string); if (!page) { throw useErrorRedirect(route, 404, "Not found"); } diff --git a/frontend/src/pages/[user].vue b/frontend/src/pages/[user].vue index 905772a6..f57cb68a 100644 --- a/frontend/src/pages/[user].vue +++ b/frontend/src/pages/[user].vue @@ -2,17 +2,16 @@ import { useRoute } from "vue-router"; import { useI18n } from "vue-i18n"; import { useOrganization, useUser } from "~/composables/useApiHelper"; -import { handleRequestError } from "~/composables/useErrorHandling"; import { useErrorRedirect } from "~/lib/composables/useErrorRedirect"; const i18n = useI18n(); const route = useRoute(); -const user = await useUser(route.params.user as string).catch((e) => handleRequestError(e)); +const user = await useUser(route.params.user as string); let organization = null; if (!user || !user.value) { throw useErrorRedirect(useRoute(), 404, "Not found"); } else if (user.value?.isOrganization) { - organization = await useOrganization(route.params.user as string).catch((e) => handleRequestError(e)); + organization = await useOrganization(route.params.user as string); } diff --git a/frontend/src/pages/[user]/[project].vue b/frontend/src/pages/[user]/[project].vue index ce3f96d9..8ff61b64 100644 --- a/frontend/src/pages/[user]/[project].vue +++ b/frontend/src/pages/[user]/[project].vue @@ -5,7 +5,6 @@ import { useI18n } from "vue-i18n"; import { useRoute } from "vue-router"; import { HangarProjectPage } from "hangar-internal"; import { useProject } from "~/composables/useApiHelper"; -import { handleRequestError } from "~/composables/useErrorHandling"; import { useErrorRedirect } from "~/lib/composables/useErrorRedirect"; import ProjectHeader from "~/components/projects/ProjectHeader.vue"; import ProjectNav from "~/components/projects/ProjectNav.vue"; @@ -19,7 +18,7 @@ defineProps({ const i18n = useI18n(); const route = useRoute(); -const project = await useProject(route.params.user as string, route.params.project as string).catch((e) => handleRequestError(e)); +const project = await useProject(route.params.user as string, route.params.project as string); if (!project || !project.value) { throw useErrorRedirect(route, 404, "Not found"); } diff --git a/frontend/src/pages/[user]/[project]/channels.vue b/frontend/src/pages/[user]/[project]/channels.vue index 7f989440..7f43dd41 100644 --- a/frontend/src/pages/[user]/[project]/channels.vue +++ b/frontend/src/pages/[user]/[project]/channels.vue @@ -30,7 +30,7 @@ const props = defineProps<{ }>(); const i18n = useI18n(); const route = useRoute(); -const channels = await useProjectChannels(props.project.namespace.owner, props.project.namespace.slug).catch((e) => handleRequestError(e)); +const channels = await useProjectChannels(props.project.namespace.owner, props.project.namespace.slug); const validations = useBackendData.validations; const notifications = useNotificationStore(); @@ -42,7 +42,7 @@ async function refreshChannels() { const newChannels = await useInternalApi(`channels/${props.project.namespace.owner}/${props.project.namespace.slug}`).catch((e) => handleRequestError(e) ); - if (channels && newChannels) { + if (channels?.value && newChannels) { channels.value = newChannels; } } diff --git a/frontend/src/pages/[user]/[project]/flags.vue b/frontend/src/pages/[user]/[project]/flags.vue index dbc66233..87ea0770 100644 --- a/frontend/src/pages/[user]/[project]/flags.vue +++ b/frontend/src/pages/[user]/[project]/flags.vue @@ -9,7 +9,6 @@ import Link from "~/lib/components/design/Link.vue"; import SortableTable, { Header } from "~/components/SortableTable.vue"; import Alert from "~/lib/components/design/Alert.vue"; import { useProjectFlags } from "~/composables/useApiHelper"; -import { handleRequestError } from "~/composables/useErrorHandling"; import { useSeo } from "~/composables/useSeo"; import { projectIconUrl } from "~/composables/useUrlHelper"; import { definePageMeta } from "#imports"; @@ -24,7 +23,7 @@ const props = defineProps<{ }>(); const i18n = useI18n(); const route = useRoute(); -const flags = await useProjectFlags(props.project.id).catch((e) => handleRequestError(e)); +const flags = await useProjectFlags(props.project.id); const headers = [ { title: "Submitter", name: "user" }, diff --git a/frontend/src/pages/[user]/[project]/notes.vue b/frontend/src/pages/[user]/[project]/notes.vue index a2450437..6539b5ad 100644 --- a/frontend/src/pages/[user]/[project]/notes.vue +++ b/frontend/src/pages/[user]/[project]/notes.vue @@ -28,7 +28,7 @@ const props = defineProps<{ }>(); const i18n = useI18n(); const route = useRoute(); -const notes = await useProjectNotes(props.project.id).catch((e) => handleRequestError(e)); +const notes = await useProjectNotes(props.project.id); const text = ref(""); const loading = ref(false); @@ -50,7 +50,7 @@ async function addNote() { }).catch((e) => handleRequestError(e)); text.value = ""; const newNotes = await useInternalApi("projects/notes/" + props.project.id).catch((e) => handleRequestError(e)); - if (notes && newNotes) { + if (notes?.value && newNotes) { notes.value = newNotes; } loading.value = false; diff --git a/frontend/src/pages/[user]/[project]/stars.vue b/frontend/src/pages/[user]/[project]/stars.vue index 36bb51e6..ce39cda4 100644 --- a/frontend/src/pages/[user]/[project]/stars.vue +++ b/frontend/src/pages/[user]/[project]/stars.vue @@ -3,7 +3,6 @@ import { useRoute } from "vue-router"; import { useI18n } from "vue-i18n"; import { useHead } from "@vueuse/head"; import { HangarProject } from "hangar-internal"; -import { handleRequestError } from "~/composables/useErrorHandling"; import Card from "~/lib/components/design/Card.vue"; import PageTitle from "~/lib/components/design/PageTitle.vue"; import UserAvatar from "~/components/UserAvatar.vue"; @@ -15,7 +14,7 @@ import { useSeo } from "~/composables/useSeo"; const route = useRoute(); const i18n = useI18n(); -const stargazers = await useStargazers(route.params.user as string, route.params.project as string).catch((e) => handleRequestError(e)); +const stargazers = await useStargazers(route.params.user as string, route.params.project as string); const props = defineProps<{ project: HangarProject; @@ -37,8 +36,8 @@ useHead( {{ i18n.t("project.stargazers") }} -
-
+
+
{{ stargazer.name }}
diff --git a/frontend/src/pages/[user]/[project]/versions/[version].vue b/frontend/src/pages/[user]/[project]/versions/[version].vue index a481286d..c3bea7b8 100644 --- a/frontend/src/pages/[user]/[project]/versions/[version].vue +++ b/frontend/src/pages/[user]/[project]/versions/[version].vue @@ -2,7 +2,6 @@ import { useI18n } from "vue-i18n"; import { useRoute, useRouter } from "vue-router"; import { HangarProject } from "hangar-internal"; -import { handleRequestError } from "~/composables/useErrorHandling"; import { useProjectVersionsInternal } from "~/composables/useApiHelper"; import { useErrorRedirect } from "~/lib/composables/useErrorRedirect"; import { Platform } from "~/types/enums"; @@ -14,10 +13,8 @@ const props = defineProps<{ project: HangarProject; }>(); -const version = await useProjectVersionsInternal(route.params.user as string, route.params.project as string, route.params.version as string).catch((e) => - handleRequestError(e) -); -if (!version || !version.value) { +const version = await useProjectVersionsInternal(route.params.user as string, route.params.project as string, route.params.version as string); +if (!version?.value) { throw useErrorRedirect(route, 404, "Not found"); } diff --git a/frontend/src/pages/[user]/[project]/versions/index.vue b/frontend/src/pages/[user]/[project]/versions/index.vue index 838eb2bb..e27d8780 100644 --- a/frontend/src/pages/[user]/[project]/versions/index.vue +++ b/frontend/src/pages/[user]/[project]/versions/index.vue @@ -48,10 +48,10 @@ const requestOptions = computed(() => { }; }); -const channels = await useProjectChannels(route.params.user as string, route.params.project as string).catch((e) => handleRequestError(e)); -const versions = await useProjectVersions(route.params.user as string, route.params.project as string).catch((e) => handleRequestError(e)); +const channels = await useProjectChannels(route.params.user as string, route.params.project as string); +const versions = await useProjectVersions(route.params.user as string, route.params.project as string); -if (channels) { +if (channels.value) { filter.channels.push(...(channels.value?.map((c) => c.name) || [])); filter.platforms.push(...platforms.value.map((p) => p.enumName)); } diff --git a/frontend/src/pages/[user]/[project]/watchers.vue b/frontend/src/pages/[user]/[project]/watchers.vue index 9a8b712d..4298cb67 100644 --- a/frontend/src/pages/[user]/[project]/watchers.vue +++ b/frontend/src/pages/[user]/[project]/watchers.vue @@ -3,7 +3,6 @@ import { useRoute } from "vue-router"; import { useI18n } from "vue-i18n"; import { useHead } from "@vueuse/head"; import { HangarProject } from "hangar-internal"; -import { handleRequestError } from "~/composables/useErrorHandling"; import Card from "~/lib/components/design/Card.vue"; import PageTitle from "~/lib/components/design/PageTitle.vue"; import UserAvatar from "~/components/UserAvatar.vue"; @@ -15,7 +14,7 @@ import { useSeo } from "~/composables/useSeo"; const route = useRoute(); const i18n = useI18n(); -const watchers = await useWatchers(route.params.user as string, route.params.project as string).catch((e) => handleRequestError(e)); +const watchers = await useWatchers(route.params.user as string, route.params.project as string); const props = defineProps<{ project: HangarProject; @@ -37,8 +36,8 @@ useHead( {{ i18n.t("project.watchers") }} -
-
+
+
{{ watcher.name }}
diff --git a/frontend/src/pages/[user]/index.vue b/frontend/src/pages/[user]/index.vue index 1341bd61..a0d6f83b 100644 --- a/frontend/src/pages/[user]/index.vue +++ b/frontend/src/pages/[user]/index.vue @@ -37,7 +37,8 @@ const props = defineProps<{ const i18n = useI18n(); const route = useRoute(); -const { starred, watching, projects, organizations, pinned } = (await useUserData(props.user.name)).value || {}; +const userData = await useUserData(props.user.name); +const { starred, watching, projects, organizations, pinned } = userData.value || { starred: null }; let organizationVisibility = null; if (props.user.name === useAuthStore().user?.name) { organizationVisibility = await useOrgVisibility(props.user.name); diff --git a/frontend/src/pages/admin/approval/versions.vue b/frontend/src/pages/admin/approval/versions.vue index a028d768..567ef487 100644 --- a/frontend/src/pages/admin/approval/versions.vue +++ b/frontend/src/pages/admin/approval/versions.vue @@ -6,7 +6,6 @@ import { useRoute } from "vue-router"; import SortableTable, { Header } from "~/components/SortableTable.vue"; import { ReviewAction } from "~/types/enums"; import { useVersionApprovals } from "~/composables/useApiHelper"; -import { handleRequestError } from "~/composables/useErrorHandling"; import Card from "~/lib/components/design/Card.vue"; import Link from "~/lib/components/design/Link.vue"; import Tag from "~/components/Tag.vue"; @@ -20,7 +19,7 @@ definePageMeta({ const i18n = useI18n(); const route = useRoute(); -const data = await useVersionApprovals().catch((e) => handleRequestError(e)); +const data = await useVersionApprovals(); const actions = { ongoing: [ReviewAction.START, ReviewAction.MESSAGE, ReviewAction.UNDO_APPROVAL, ReviewAction.REOPEN], diff --git a/frontend/src/pages/admin/flags.vue b/frontend/src/pages/admin/flags.vue index df43d11b..05a8f5f3 100644 --- a/frontend/src/pages/admin/flags.vue +++ b/frontend/src/pages/admin/flags.vue @@ -3,8 +3,6 @@ import { useI18n } from "vue-i18n"; import { useRoute } from "vue-router"; import { ref } from "vue"; import { useHead } from "@vueuse/head"; -import { useUnresolvedFlags } from "~/composables/useApiHelper"; -import { handleRequestError } from "~/composables/useErrorHandling"; import PageTitle from "~/lib/components/design/PageTitle.vue"; import { useSeo } from "~/composables/useSeo"; import Flags from "~/components/Flags.vue"; @@ -17,7 +15,6 @@ definePageMeta({ const i18n = useI18n(); const route = useRoute(); -const flags = await useUnresolvedFlags().catch((e) => handleRequestError(e)); const loading = ref<{ [key: number]: boolean }>({}); const selectedTab = ref("unresolved"); diff --git a/frontend/src/pages/admin/health.vue b/frontend/src/pages/admin/health.vue index a4829d47..0cd0f017 100644 --- a/frontend/src/pages/admin/health.vue +++ b/frontend/src/pages/admin/health.vue @@ -3,7 +3,6 @@ import { useI18n } from "vue-i18n"; import { useRoute } from "vue-router"; import { useHead } from "@vueuse/head"; import { useHealthReport } from "~/composables/useApiHelper"; -import { handleRequestError } from "~/composables/useErrorHandling"; import Card from "~/lib/components/design/Card.vue"; import Link from "~/lib/components/design/Link.vue"; import PageTitle from "~/lib/components/design/PageTitle.vue"; @@ -16,7 +15,7 @@ definePageMeta({ const i18n = useI18n(); const route = useRoute(); -const healthReport = await useHealthReport().catch((e) => handleRequestError(e)); +const healthReport = await useHealthReport(); useHead(useSeo(i18n.t("health.title"), null, route, null)); diff --git a/frontend/src/pages/admin/log.vue b/frontend/src/pages/admin/log.vue index ca4578e0..ccf50544 100644 --- a/frontend/src/pages/admin/log.vue +++ b/frontend/src/pages/admin/log.vue @@ -8,7 +8,6 @@ import { LoggedAction, LoggedActionType } from "hangar-internal"; import { debounce } from "lodash-es"; import PageTitle from "~/lib/components/design/PageTitle.vue"; import { useActionLogs } from "~/composables/useApiHelper"; -import { handleRequestError } from "~/composables/useErrorHandling"; import Card from "~/lib/components/design/Card.vue"; import SortableTable, { Header } from "~/components/SortableTable.vue"; import Link from "~/lib/components/design/Link.vue"; @@ -27,7 +26,7 @@ definePageMeta({ const i18n = useI18n(); const route = useRoute(); -const loggedActions = await useActionLogs().catch((e) => handleRequestError(e)); +const loggedActions = await useActionLogs(); // TODO add support for sorting const headers = [ diff --git a/frontend/src/pages/admin/user/[user].vue b/frontend/src/pages/admin/user/[user].vue index 1337a241..2cf600e5 100644 --- a/frontend/src/pages/admin/user/[user].vue +++ b/frontend/src/pages/admin/user/[user].vue @@ -15,7 +15,7 @@ import SortableTable, { Header } from "~/components/SortableTable.vue"; import InputCheckbox from "~/lib/components/ui/InputCheckbox.vue"; import { useSeo } from "~/composables/useSeo"; import { authUrl, forumUserUrl } from "~/composables/useUrlHelper"; -import { useUser } from "~/composables/useApiHelper"; +import { useProjects, useUser } from "~/composables/useApiHelper"; import Tag from "~/components/Tag.vue"; import InputSelect from "~/lib/components/ui/InputSelect.vue"; import { useBackendData } from "~/store/backendData"; @@ -30,13 +30,11 @@ const i18n = useI18n(); const route = useRoute(); const router = useRouter(); -const projects = await useApi>("projects", "get", { - owner: route.params.user, -}).catch((e) => handleRequestError(e)); +const projects = await useProjects({ owner: route.params.user }); const orgs = await useInternalApi<{ [key: string]: OrganizationRoleTable }>(`organizations/${route.params.user}/userOrganizations`).catch((e) => handleRequestError(e) ); -const user = await useUser(route.params.user as string).catch((e) => handleRequestError(e)); +const user = await useUser(route.params.user as string); const projectsConfig = [ { title: i18n.t("userAdmin.project"), name: "name" }, @@ -67,7 +65,7 @@ const selectedRole = ref(); async function processRole(add: boolean) { try { await useInternalApi("/admin/user/" + route.params.user + "/" + selectedRole.value, add ? "POST" : "DELETE"); - if (user) { + if (user?.value) { user.value = await useApi(("users/" + route.params.user) as string); } } catch (e) { @@ -90,7 +88,7 @@ useHead(useSeo(i18n.t("userAdmin.title") + " " + route.params.user, null, route,
- +
@@ -98,12 +96,12 @@ useHead(useSeo(i18n.t("userAdmin.title") + " " + route.params.user, null, route,
-
-
diff --git a/frontend/src/pages/admin/user/index.vue b/frontend/src/pages/admin/user/index.vue index 5f030e82..5e758b78 100644 --- a/frontend/src/pages/admin/user/index.vue +++ b/frontend/src/pages/admin/user/index.vue @@ -10,7 +10,7 @@ import Tag from "~/components/Tag.vue"; import { useApi } from "~/composables/useApi"; import { Header } from "~/components/SortableTable.vue"; import { useSeo } from "~/composables/useSeo"; -import { definePageMeta, handleRequestError, watch } from "#imports"; +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"; @@ -33,7 +33,7 @@ const headers = [ { name: "org", title: i18n.t("pages.headers.organization"), sortable: true }, ] as Header[]; -const users = await useUsers().catch((e) => handleRequestError(e)); +const users = await useUsers(); const page = ref(0); const sort = ref([]); const query = ref(); diff --git a/frontend/src/pages/authors.vue b/frontend/src/pages/authors.vue index d430e6ee..8e8d42aa 100644 --- a/frontend/src/pages/authors.vue +++ b/frontend/src/pages/authors.vue @@ -32,7 +32,7 @@ const requestParams = computed(() => { sort: sort.value, }; }); -const authors = await useAuthors(requestParams.value).catch((e) => handleRequestError(e)); +const authors = await useAuthors(requestParams.value); async function updateSort(col: string, sorter: Record) { sort.value = [...Object.keys(sorter)] diff --git a/frontend/src/pages/index.vue b/frontend/src/pages/index.vue index 7a37a0e1..f75399ec 100644 --- a/frontend/src/pages/index.vue +++ b/frontend/src/pages/index.vue @@ -9,7 +9,6 @@ import InputCheckbox from "~/lib/components/ui/InputCheckbox.vue"; import { useBackendData, useVisibleCategories, useVisiblePlatforms } from "~/store/backendData"; import ProjectList from "~/components/projects/ProjectList.vue"; import { useProjects } from "~/composables/useApiHelper"; -import { handleRequestError } from "~/composables/useErrorHandling"; import Card from "~/lib/components/design/Card.vue"; import Container from "~/lib/components/design/Container.vue"; import { useSeo } from "~/composables/useSeo"; @@ -67,7 +66,7 @@ const requestParams = computed(() => { return params; }); -const p = await useProjects(requestParams.value).catch((e) => handleRequestError(e)); +const p = await useProjects(requestParams.value); if (p && p.value) { projects.value = p.value; await checkOffsetLargerCount(); @@ -141,7 +140,7 @@ const script = { if (isRef(meta.script)) { meta.script.value.push(script); } else { - meta.script = meta.script || []; + meta.script = (meta.script || []) as []; meta.script.push(script); } useHead(meta); diff --git a/frontend/src/pages/notifications.vue b/frontend/src/pages/notifications.vue index 6901318e..81b8835a 100644 --- a/frontend/src/pages/notifications.vue +++ b/frontend/src/pages/notifications.vue @@ -30,11 +30,11 @@ const route = useRoute(); const notificationStore = useNotificationStore(); // TODO send in one -const unreadNotifications = (await useUnreadNotifications().catch((e) => handleRequestError(e))) as Ref>; -const readNotifications = (await useReadNotifications().catch((e) => handleRequestError(e))) as Ref>; -const allNotifications = (await useNotifications().catch((e) => handleRequestError(e))) as Ref>; -const notifications: Ref> = ref(unreadNotifications.value); -const invites = (await useInvites().catch((e) => handleRequestError(e))) as Ref; +const unreadNotifications = await useUnreadNotifications(); +const readNotifications = await useReadNotifications(); +const allNotifications = await useNotifications(); +const notifications: Ref | null> = ref(unreadNotifications.value); +const invites = await useInvites(); const selectedTab = ref("unread"); const selectedTabs: Tab[] = [ @@ -66,6 +66,7 @@ useHead(useSeo("Notifications", null, route, null)); async function markAllAsRead() { await useInternalApi(`markallread`, "post").catch((e) => handleRequestError(e)); + if (!unreadNotifications.value) return; unreadNotifications.value.result = []; unreadNotifications.value.pagination.limit = 0; unreadNotifications.value.pagination.offset = 0; @@ -75,6 +76,7 @@ async function markAllAsRead() { async function markNotificationRead(notification: HangarNotification, router = true) { await useInternalApi(`notifications/${notification.id}`, "post").catch((e) => handleRequestError(e)); notification.read = true; + if (!notifications.value) return; notifications.value.result = notifications.value.result.filter((n) => n !== notification); if (notification.action && router) { await useRouter().push(notification.action); @@ -86,6 +88,7 @@ async function updateInvite(invite: Invite, status: "accept" | "decline") { if (status === "accept") { invite.accepted = true; } else { + if (!invites.value) return; invites.value[invite.type] = invites.value[invite.type].filter((i) => i.roleTableId !== invite.roleTableId); } notificationStore.success(i18n.t(`notifications.invite.msgs.${status}`, [invite.name])); @@ -112,11 +115,11 @@ function updateSelectedNotifications() { -
+
{{ i18n.t(`notifications.empty.${selectedTab}`) }}
- + - diff --git a/frontend/src/pages/staff.vue b/frontend/src/pages/staff.vue index 90a7d54d..a6d26075 100644 --- a/frontend/src/pages/staff.vue +++ b/frontend/src/pages/staff.vue @@ -34,7 +34,7 @@ const requestParams = computed(() => { sort: sort.value, }; }); -const staff = await useStaff(requestParams.value).catch((e) => handleRequestError(e)); +const staff = await useStaff(requestParams.value); async function updateSort(col: string, sorter: Record) { sort.value = [...Object.keys(sorter)]