woodpecker/web/src/views/Login.vue

100 lines
3.3 KiB
Vue

<template>
<main class="flex h-full w-full flex-col items-center justify-center">
<Error v-if="errorMessage" class="w-full md:w-3xl">
<span class="whitespace-pre">{{ errorMessage }}</span>
<span v-if="errorDescription" class="mt-1 whitespace-pre">{{ errorDescription }}</span>
<a
v-if="errorUri"
:href="errorUri"
target="_blank"
class="mt-1 cursor-pointer text-wp-link-100 hover:text-wp-link-200"
>
<span>{{ errorUri }}</span>
</a>
</Error>
<div
class="flex min-h-sm w-full flex-col overflow-hidden border border-wp-background-400 bg-wp-background-100 shadow dark:bg-wp-background-200 md:m-8 md:w-3xl md:flex-row md:rounded-md"
>
<div class="flex min-h-48 items-center justify-center bg-wp-primary-200 dark:bg-wp-primary-300 md:w-3/5">
<WoodpeckerLogo preserveAspectRatio="xMinYMin slice" class="h-32 w-32 md:h-48 md:w-48" />
</div>
<div class="flex min-h-48 flex-col items-center justify-center gap-4 p-4 text-center md:w-2/5">
<h1 class="text-xl text-wp-text-100">{{ $t('welcome') }}</h1>
<div class="flex flex-col gap-2">
<Button
v-for="forge in forges"
:key="forge.id"
:start-icon="forge.type === 'addon' ? 'repo' : forge.type"
class="!whitespace-normal"
@click="doLogin(forge.id)"
>
{{ $t('login_with', { forge: getHostFromUrl(forge) }) }}
</Button>
</div>
</div>
</div>
</main>
</template>
<script lang="ts" setup>
import { onMounted, ref } from 'vue';
import { useI18n } from 'vue-i18n';
import { useRoute, useRouter } from 'vue-router';
import WoodpeckerLogo from '~/assets/logo.svg?component';
import Button from '~/components/atomic/Button.vue';
import Error from '~/components/atomic/Error.vue';
import useApiClient from '~/compositions/useApiClient';
import useAuthentication from '~/compositions/useAuthentication';
import type { Forge } from '~/lib/api/types';
const route = useRoute();
const router = useRouter();
const authentication = useAuthentication();
const i18n = useI18n();
const apiClient = useApiClient();
const forges = ref<Forge[]>([]);
function getHostFromUrl(forge: Forge) {
if (!forge.url) {
return forge.type.charAt(0).toUpperCase() + forge.type.slice(1);
}
const url = new URL(forge.url);
return url.hostname;
}
function doLogin(forgeId?: number) {
const url = typeof route.query.url === 'string' ? route.query.url : '';
authentication.authenticate(url, forgeId);
}
const authErrorMessages = {
oauth_error: i18n.t('oauth_error'),
internal_error: i18n.t('internal_error'),
registration_closed: i18n.t('registration_closed'),
access_denied: i18n.t('access_denied'),
invalid_state: i18n.t('invalid_state'),
org_access_denied: i18n.t('org_access_denied'),
};
const errorMessage = ref<string>();
const errorDescription = ref<string>(route.query.error_description as string);
const errorUri = ref<string>(route.query.error_uri as string);
onMounted(async () => {
if (authentication.isAuthenticated) {
await router.replace({ name: 'home' });
return;
}
forges.value = (await apiClient.getForges()) ?? [];
if (route.query.error) {
const error = route.query.error as keyof typeof authErrorMessages;
errorMessage.value = authErrorMessages[error] ?? error;
}
});
</script>