remove tons of warnings and hydration errors, speed up page loading

This commit is contained in:
MiniDigger | Martin 2022-06-11 15:44:02 +02:00
parent 0381cc4ce4
commit c1294e723e
13 changed files with 112 additions and 62 deletions

View File

@ -78,6 +78,7 @@
"node-fetch": "^3.2.4",
"pnpm": "^7.0.1",
"prettier": "^2.6.2",
"regenerator-runtime": "^0.13.9",
"sass": "^1.51.0",
"typescript": "^4.6.4",
"unplugin-auto-import": "^0.7.1",

View File

@ -55,6 +55,7 @@ specifiers:
prettier: ^2.6.2
prism-theme-vars: ^0.2.2
qs: ^6.10.3
regenerator-runtime: ^0.13.9
sass: ^1.51.0
swagger-ui-dist: ^4.10.3
typescript: ^4.6.4
@ -134,6 +135,7 @@ devDependencies:
node-fetch: 3.2.4
pnpm: 7.0.1
prettier: 2.6.2
regenerator-runtime: 0.13.9
sass: 1.51.0
typescript: 4.6.4
unplugin-auto-import: 0.7.1_utbicujaitsyfhhenhpcxjwwzu
@ -434,7 +436,6 @@ packages:
/@babel/helper-validator-identifier/7.16.7:
resolution: {integrity: sha512-hsEnFemeiW4D08A5gUAZxLBTXpZ39P+a+DGDsHw1yxqyQ/jzFEnxf5uTEGp+3bzAbNOxU1paTgYS4ECU/IgfDw==}
engines: {node: '>=6.9.0'}
dev: true
/@babel/helper-validator-option/7.16.7:
resolution: {integrity: sha512-TRtenOuRUVo9oIQGPC5G9DgK4743cdxvtOw0weQNpZXaS16SCBi5MNjZF8vba3ETURjZpTbVn7Vvcf2eAwFozQ==}
@ -477,12 +478,16 @@ packages:
resolution: {integrity: sha512-n2Q6i+fnJqzOaq2VkdXxy2TCPCWQZHiCo0XqmrCvDWcZQKRyZzYi4Z0yxlBuN0w+r2ZHmre+Q087DSrw3pbJDQ==}
engines: {node: '>=6.0.0'}
hasBin: true
dependencies:
'@babel/types': 7.17.0
dev: true
/@babel/parser/7.17.8:
resolution: {integrity: sha512-BoHhDJrJXqcg+ZL16Xv39H9n+AqJ4pcDrQBGZN+wHxIysrLZ3/ECwCBUch/1zUNhnsXULcONU3Ei5Hmkfk6kiQ==}
engines: {node: '>=6.0.0'}
hasBin: true
dependencies:
'@babel/types': 7.17.0
/@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression/7.16.7_@babel+core@7.17.8:
resolution: {integrity: sha512-anv/DObl7waiGEnC24O9zqL0pSuI9hljihqiDuFHC8d7/bjr/4RLGPWuc8rYOff/QPzbEPSkzG8wGG9aDuhHRg==}
@ -1315,7 +1320,6 @@ packages:
dependencies:
'@babel/helper-validator-identifier': 7.16.7
to-fast-properties: 2.0.0
dev: true
/@eslint/eslintrc/0.4.3:
resolution: {integrity: sha512-J6KFFz5QCYUJq3pf0mjEcCJVERbzv71PUIDczuh9JkwGEzced6CO5ADLHB1rbf/+oPBtoPfMYNOpGDzCANlbXw==}
@ -1943,15 +1947,19 @@ packages:
peerDependencies:
eslint: ^6.2.0 || ^7.0.0 || ^8.0.0
eslint-plugin-vue: ^8.0.1
typescript: '*'
peerDependenciesMeta:
typescript:
optional: true
dependencies:
'@typescript-eslint/eslint-plugin': 5.16.0_jqncz736ernh47yeh2d4pwt2h4
'@typescript-eslint/parser': 5.16.0_t725usgvqspm5woeqpaxbfp2qu
eslint: 8.14.0
eslint-plugin-vue: 8.7.1_eslint@8.14.0
typescript: 4.6.4
vue-eslint-parser: 8.3.0_eslint@8.14.0
transitivePeerDependencies:
- supports-color
- typescript
dev: true
/@vue/reactivity-transform/3.2.33:
@ -2543,6 +2551,8 @@ packages:
finalhandler: 1.1.2
parseurl: 1.3.3
utils-merge: 1.0.1
transitivePeerDependencies:
- supports-color
dev: false
/convert-source-map/1.8.0:
@ -2606,11 +2616,21 @@ packages:
/debug/2.6.9:
resolution: {integrity: sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==}
peerDependencies:
supports-color: '*'
peerDependenciesMeta:
supports-color:
optional: true
dependencies:
ms: 2.0.0
/debug/3.2.7:
resolution: {integrity: sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==}
peerDependencies:
supports-color: '*'
peerDependenciesMeta:
supports-color:
optional: true
dependencies:
ms: 2.1.3
dev: true
@ -3049,14 +3069,33 @@ packages:
dependencies:
debug: 3.2.7
resolve: 1.22.0
transitivePeerDependencies:
- supports-color
dev: true
/eslint-module-utils/2.7.3:
/eslint-module-utils/2.7.3_ulu2225r2ychl26a37c6o2rfje:
resolution: {integrity: sha512-088JEC7O3lDZM9xGe0RerkOMd0EjFl+Yvd1jPWIkMT5u3H9+HC34mWWPnqPrN13gieT9pBOO+Qt07Nb/6TresQ==}
engines: {node: '>=4'}
peerDependencies:
'@typescript-eslint/parser': '*'
eslint-import-resolver-node: '*'
eslint-import-resolver-typescript: '*'
eslint-import-resolver-webpack: '*'
peerDependenciesMeta:
'@typescript-eslint/parser':
optional: true
eslint-import-resolver-node:
optional: true
eslint-import-resolver-typescript:
optional: true
eslint-import-resolver-webpack:
optional: true
dependencies:
debug: 3.2.7
eslint-import-resolver-node: 0.3.6
find-up: 2.1.0
transitivePeerDependencies:
- supports-color
dev: true
/eslint-plugin-eslint-comments/3.2.0_eslint@8.14.0:
@ -3074,7 +3113,11 @@ packages:
resolution: {integrity: sha512-hYfi3FXaM8WPLf4S1cikh/r4IxnO6zrhZbEGz2b660EJRbuxgpDS5gkCuYgGWg2xxh2rBuIr4Pvhve/7c31koA==}
engines: {node: '>=4'}
peerDependencies:
'@typescript-eslint/parser': '*'
eslint: ^2 || ^3 || ^4 || ^5 || ^6 || ^7.2.0 || ^8
peerDependenciesMeta:
'@typescript-eslint/parser':
optional: true
dependencies:
array-includes: 3.1.4
array.prototype.flat: 1.2.5
@ -3082,7 +3125,7 @@ packages:
doctrine: 2.1.0
eslint: 8.14.0
eslint-import-resolver-node: 0.3.6
eslint-module-utils: 2.7.3
eslint-module-utils: 2.7.3_ulu2225r2ychl26a37c6o2rfje
has: 1.0.3
is-core-module: 2.8.1
is-glob: 4.0.3
@ -3090,6 +3133,10 @@ packages:
object.values: 1.1.5
resolve: 1.22.0
tsconfig-paths: 3.14.1
transitivePeerDependencies:
- eslint-import-resolver-typescript
- eslint-import-resolver-webpack
- supports-color
dev: true
/eslint-plugin-unicorn/42.0.0_eslint@8.14.0:
@ -3429,6 +3476,8 @@ packages:
parseurl: 1.3.3
statuses: 1.5.0
unpipe: 1.0.0
transitivePeerDependencies:
- supports-color
dev: false
/find-up/2.1.0:
@ -5141,9 +5190,8 @@ packages:
dev: true
/to-fast-properties/2.0.0:
resolution: {integrity: sha1-3F5pjL0HkmW8c+A3doGk5Og/YW4=}
resolution: {integrity: sha512-/OaKK0xYrs3DmxRYqL/yDc+FxFUVYhDlXMhRmv3z915w2HF1tnN1omB354j8VUGO/hbRzyD6Y3sA7v7GS/ceog==}
engines: {node: '>=4'}
dev: true
/to-regex-range/5.0.1:
resolution: {integrity: sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==}
@ -5580,6 +5628,7 @@ packages:
transitivePeerDependencies:
- encoding
- rollup
- supports-color
dev: false
/vite/2.9.6_sass@1.51.0:

View File

@ -3,6 +3,7 @@ import { Menu, MenuButton, MenuItems } from "@headlessui/vue";
import IconMdiMenuDown from "~icons/mdi/menu-down";
import IconMdiMenuUp from "~icons/mdi/menu-up";
import Button from "~/components/design/Button.vue";
import ServerOnly from "~/components/design/Tooltip.vue";
const props = withDefaults(
defineProps<{
@ -23,7 +24,7 @@ const props = withDefaults(
<template>
<Menu v-slot="{ open }">
<div>
<MenuButton>
<MenuButton as="div">
<Button :button-type="props.buttonType" :size="props.buttonSize">
<slot name="button-label">
<span class="mx-1">{{ props.name }}</span>

View File

@ -21,11 +21,10 @@ const hasError = computed<boolean>(() => {
</script>
<template>
<ClientOnly>
<Popper v-bind="$attrs" :show="hasError" arrow placement="bottom" :content="formattedError" class="text-center">
<slot />
</Popper>
</ClientOnly>
<div><slot /></div>
<!--<Popper v-bind="$attrs" :show="hasError" arrow placement="bottom" :content="formattedError" class="text-center">
<slot />
</Popper>-->
</template>
<style scoped>

View File

@ -95,8 +95,8 @@ export interface Step {
</div>
<div class="mt-4">
<Card accent>
<template v-if="settings.mobile" #header>
{{ activeStep.header }}
<template #header>
<span v-show="settings.mobile">{{ activeStep.header }}</span>
</template>
<div v-for="step in steps" :key="step.value">
<slot v-if="internalValue === step.value" :name="step.value" />

View File

@ -132,7 +132,7 @@ interface EditableMember {
<p class="font-semibold">
<Link :to="'/' + member.user.name">{{ member.user.name }}</Link>
</p>
<Tooltip :disabled="member.role.accepted">
<Tooltip v-if="member.role.accepted">
<template #content>
{{ i18n.t("form.memberList.invitedAs", [member.role.role.title]) }}
</template>

View File

@ -68,7 +68,7 @@ function toggleWatch() {
:img-src="imageUrl"
/>
<div class="flex-grow sm:mr-4 <sm:mb-4 overflow-clip">
<p class="text-2xl <sm:text-lg pb-1 inline-flex space-x-1.2 items-center">
<div class="text-2xl <sm:text-lg pb-1 inline-flex space-x-1.2 items-center">
<UserAvatar
class="!w-8 !h-8 sm:hidden"
:username="project.namespace.owner"
@ -78,7 +78,7 @@ function toggleWatch() {
<router-link class="!sm:ml-0" :to="'/' + project.namespace.owner">{{ project.namespace.owner }}</router-link>
<span class="text-gray-500 dark:text-gray-400"> / </span>
<span class="font-semibold">{{ project.name }}</span>
</p>
</div>
<p>{{ project.description }}</p>
</div>
<div class="flex sm:flex-col space-y-2 items-end justify-between sm:justify-around flex-shrink-0">

View File

@ -12,6 +12,8 @@ import devalue from "@nuxt/devalue";
import { settingsLog } from "~/composables/useLog";
import * as domain from "~/composables/useDomain";
import "regenerator-runtime/runtime"; // popper needs this?
const routes = setupLayouts(generatedRoutes);
// we need to override the path on the error route to have the patch math
const errorRoute = routes.find((r) => r.path === "/error");

View File

@ -216,9 +216,9 @@ useHead(
<InputTag
v-model="form.settings.keywords"
counter
:maxlength="backendData.validations.project.keywords.max"
:maxlength="backendData.validations?.project.keywords.max"
:label="i18n.t('project.new.step3.keywords')"
:rules="[required(), maxLength()(backendData.validations.project.keywords.max)]"
:rules="[required(), maxLength()(backendData.validations?.project.keywords.max)]"
/>
</ProjectSettingsSection>
<ProjectSettingsSection>

View File

@ -9,7 +9,7 @@ import { useBackendDataStore } from "~/store/backendData";
import { lastUpdated } from "~/composables/useTime";
import { useInternalApi } from "~/composables/useApi";
import { handleRequestError } from "~/composables/useErrorHandling";
import { Tag } from "hangar-api";
import { Tag, User } from "hangar-api";
import { useErrorRedirect } from "~/composables/useErrorRedirect";
import TagComponent from "~/components/Tag.vue";
import { hasPerms } from "~/composables/usePerm";
@ -25,7 +25,6 @@ import { useNotificationStore } from "~/store/notification";
import DropdownButton from "~/components/design/DropdownButton.vue";
import DropdownItem from "~/components/design/DropdownItem.vue";
import PlatformVersionEditModal from "~/components/modals/PlatformVersionEditModal.vue";
import Tooltip from "~/components/design/Tooltip.vue";
const route = useRoute();
const i18n = useI18n();
@ -38,6 +37,9 @@ const props = defineProps<{
versions: Map<Platform, HangarVersion>;
project: HangarProject;
versionPlatforms: Set<Platform>;
user: User;
platform: string;
version: string;
}>();
const p: Platform = ((route.params.platform as string) || "").toUpperCase() as Platform;

View File

@ -136,7 +136,7 @@ function getNonChannelTags(version: Version): ApiTag[] {
<div class="flex flex-wrap">
<span class="basis-full inline-flex items-center">
<IconMdiAccountArrowRight class="mr-1" />
<Link :to="'/' + version.author">{{ version.author }}</Link>
{{ version.author }}
</span>
<span class="basis-full inline-flex items-center">
<IconMdiFile class="mr-1" />

View File

@ -103,7 +103,7 @@ useHead(useSeo(props.user.name, props.user.tagline, route, avatarUrl(props.user.
<ul>
<li v-for="(orgRole, orgName) in organizations" :key="orgName">
<router-link :to="'/' + orgName" class="flex">
<UserAvatar :username="orgName" :avatar-url="avatarUrl(orgName)" size="xs" />
<UserAvatar :username="orgName" :avatar-url="avatarUrl(orgName)" size="xs" :disable-link="true" />
&nbsp;
{{ orgName }}
&nbsp; ({{ orgRole.role.title }}) &nbsp;

View File

@ -48,48 +48,44 @@ export const useBackendDataStore = defineStore("backendData", () => {
async function initBackendData() {
try {
// todo make these run concurrently to speed up stuff, also consider caching them in node server/globally, these are all always needed
await fetchIfNeeded(async () => {
const categoryResult = await useInternalApi<IProjectCategory[]>("data/categories", false);
for (const c of categoryResult) {
c.title = "project.category." + c.apiName;
}
return convertToMap<ProjectCategory, IProjectCategory>(categoryResult, (value) => value.apiName);
}, projectCategories);
// todo consider caching these in node server/globally, these are all always needed
await Promise.all([
fetchIfNeeded(async () => {
const categoryResult = await useInternalApi<IProjectCategory[]>("data/categories", false);
for (const c of categoryResult) {
c.title = "project.category." + c.apiName;
}
return convertToMap<ProjectCategory, IProjectCategory>(categoryResult, (value) => value.apiName);
}, projectCategories),
await fetchIfNeeded(async () => {
const permissionResultTemp = await useInternalApi<{ value: NamedPermission; frontendName: string; permission: string }[]>("data/permissions", false);
const permissionResult: IPermission[] = permissionResultTemp.map(({ value, frontendName, permission }) => ({
value,
frontendName,
permission: BigInt("0b" + permission),
}));
return convertToMap<NamedPermission, IPermission>(permissionResult, (value) => value.value);
}, permissions);
fetchIfNeeded(async () => {
const permissionResultTemp = await useInternalApi<{ value: NamedPermission; frontendName: string; permission: string }[]>("data/permissions", false);
const permissionResult: IPermission[] = permissionResultTemp.map(({ value, frontendName, permission }) => ({
value,
frontendName,
permission: BigInt("0b" + permission),
}));
return convertToMap<NamedPermission, IPermission>(permissionResult, (value) => value.value);
}, permissions),
await fetchIfNeeded(async () => {
const platformResult: IPlatform[] = await useInternalApi<IPlatform[]>("data/platforms", false);
return convertToMap<Platform, IPlatform>(platformResult, (value) => value.name.toUpperCase());
}, platforms);
fetchIfNeeded(async () => {
const platformResult: IPlatform[] = await useInternalApi<IPlatform[]>("data/platforms", false);
return convertToMap<Platform, IPlatform>(platformResult, (value) => value.name.toUpperCase());
}, platforms),
await fetchIfNeeded(async () => {
const promptsResult: IPrompt[] = await useInternalApi<IPrompt[]>("data/prompts", false);
return convertToMap<Prompt, IPrompt>(promptsResult, (value) => value.name);
}, prompts);
fetchIfNeeded(async () => {
const promptsResult: IPrompt[] = await useInternalApi<IPrompt[]>("data/prompts", false);
return convertToMap<Prompt, IPrompt>(promptsResult, (value) => value.name);
}, prompts),
await fetchIfNeeded(async () => useInternalApi<string[]>("data/licenses", false), licenses);
await fetchIfNeeded(async () => useInternalApi<AnnouncementObject[]>("data/announcements", false), announcements);
await fetchIfNeeded(async () => useInternalApi<IVisibility[]>("data/visibilities", false), visibilities);
await fetchIfNeeded(async () => useInternalApi("data/validations", false), validations);
await fetchIfNeeded(async () => useInternalApi("data/orgRoles", false), orgRoles);
await fetchIfNeeded(async () => useInternalApi("data/channelColors", false), channelColors);
await fetchIfNeeded(async () => useInternalApi("data/projectRoles", false), projectRoles);
fetchIfNeeded(async () => useInternalApi<string[]>("data/licenses", false), licenses),
fetchIfNeeded(async () => useInternalApi<AnnouncementObject[]>("data/announcements", false), announcements),
fetchIfNeeded(async () => useInternalApi<IVisibility[]>("data/visibilities", false), visibilities),
fetchIfNeeded(async () => useInternalApi("data/validations", false), validations),
fetchIfNeeded(async () => useInternalApi("data/orgRoles", false), orgRoles),
fetchIfNeeded(async () => useInternalApi("data/channelColors", false), channelColors),
fetchIfNeeded(async () => useInternalApi("data/projectRoles", false), projectRoles),
]);
} catch (e) {
console.error("ERROR FETCHING BACKEND DATA");
console.error(e);