feat: introducing user guidance and error management helpers in admin dashboard (#4548)
This commit is contained in:
committed by
GitHub
parent
dad15133f4
commit
73f3e54c00
@@ -96,7 +96,7 @@
|
|||||||
"last_used_on": "Last used on",
|
"last_used_on": "Last used on",
|
||||||
"no_expiration": "No expiration",
|
"no_expiration": "No expiration",
|
||||||
"no_expiration_verbose": "This token will never expire!",
|
"no_expiration_verbose": "This token will never expire!",
|
||||||
"section_description": "Manage your Hoppscotch users through APIs with Infra tokens",
|
"section_description": "Manage your Hoppscotch users through APIs with Infra tokens.",
|
||||||
"section_title": "Infra Tokens",
|
"section_title": "Infra Tokens",
|
||||||
"tab_title": "Infra Tokens",
|
"tab_title": "Infra Tokens",
|
||||||
"token_expires_on": "This token will expire on",
|
"token_expires_on": "This token will expire on",
|
||||||
@@ -247,6 +247,11 @@
|
|||||||
"users_to_admin_success": "Selected users are elevated to admin status!!",
|
"users_to_admin_success": "Selected users are elevated to admin status!!",
|
||||||
"users_to_admin_failure": "Failed to elevate selected users to admin status!!"
|
"users_to_admin_failure": "Failed to elevate selected users to admin status!!"
|
||||||
},
|
},
|
||||||
|
"support": {
|
||||||
|
"description": "Get help from the Hoppscotch community",
|
||||||
|
"documentation": "Documentation",
|
||||||
|
"more_info": "More Info"
|
||||||
|
},
|
||||||
"teams": {
|
"teams": {
|
||||||
"add_member": "Add Member",
|
"add_member": "Add Member",
|
||||||
"add_members": "Add Members",
|
"add_members": "Add Members",
|
||||||
@@ -325,6 +330,7 @@
|
|||||||
"invalid_user": "Invalid User",
|
"invalid_user": "Invalid User",
|
||||||
"invite_load_list_error": "Unable to Load Invited Users List",
|
"invite_load_list_error": "Unable to Load Invited Users List",
|
||||||
"invite_user": "Invite User",
|
"invite_user": "Invite User",
|
||||||
|
"invite_users_description": "Invite your team members to join Hoppscotch.",
|
||||||
"invited_by": "Invited By",
|
"invited_by": "Invited By",
|
||||||
"invited_on": "Invited On",
|
"invited_on": "Invited On",
|
||||||
"invited_users": "Invited Users",
|
"invited_users": "Invited Users",
|
||||||
@@ -341,6 +347,7 @@
|
|||||||
"not_available": "Not Available",
|
"not_available": "Not Available",
|
||||||
"not_found": "User not found",
|
"not_found": "User not found",
|
||||||
"pending_invites": "Pending Invites",
|
"pending_invites": "Pending Invites",
|
||||||
|
"pending_invites_description": "Manage and track pending user invitations with clear status and actions.",
|
||||||
"remove_admin_privilege": "Remove Admin Privilege",
|
"remove_admin_privilege": "Remove Admin Privilege",
|
||||||
"remove_admin_status": "Remove Admin Status",
|
"remove_admin_status": "Remove Admin Status",
|
||||||
"rename": "Rename",
|
"rename": "Rename",
|
||||||
|
|||||||
@@ -14,6 +14,7 @@ declare module 'vue' {
|
|||||||
AppSidebar: typeof import('./components/app/Sidebar.vue')['default']
|
AppSidebar: typeof import('./components/app/Sidebar.vue')['default']
|
||||||
AppToast: typeof import('./components/app/Toast.vue')['default']
|
AppToast: typeof import('./components/app/Toast.vue')['default']
|
||||||
DashboardMetricsCard: typeof import('./components/dashboard/MetricsCard.vue')['default']
|
DashboardMetricsCard: typeof import('./components/dashboard/MetricsCard.vue')['default']
|
||||||
|
FallbackComponent: typeof import('./components/FallbackComponent.vue')['default']
|
||||||
HoppButtonPrimary: typeof import('@hoppscotch/ui')['HoppButtonPrimary']
|
HoppButtonPrimary: typeof import('@hoppscotch/ui')['HoppButtonPrimary']
|
||||||
HoppButtonSecondary: typeof import('@hoppscotch/ui')['HoppButtonSecondary']
|
HoppButtonSecondary: typeof import('@hoppscotch/ui')['HoppButtonSecondary']
|
||||||
HoppSmartAnchor: typeof import('@hoppscotch/ui')['HoppSmartAnchor']
|
HoppSmartAnchor: typeof import('@hoppscotch/ui')['HoppSmartAnchor']
|
||||||
@@ -34,6 +35,7 @@ declare module 'vue' {
|
|||||||
HoppSmartTabs: typeof import('@hoppscotch/ui')['HoppSmartTabs']
|
HoppSmartTabs: typeof import('@hoppscotch/ui')['HoppSmartTabs']
|
||||||
HoppSmartToggle: typeof import('@hoppscotch/ui')['HoppSmartToggle']
|
HoppSmartToggle: typeof import('@hoppscotch/ui')['HoppSmartToggle']
|
||||||
IconLucideArrowLeft: typeof import('~icons/lucide/arrow-left')['default']
|
IconLucideArrowLeft: typeof import('~icons/lucide/arrow-left')['default']
|
||||||
|
IconLucideArrowUpRight: typeof import('~icons/lucide/arrow-up-right')['default']
|
||||||
IconLucideCheck: typeof import('~icons/lucide/check')['default']
|
IconLucideCheck: typeof import('~icons/lucide/check')['default']
|
||||||
IconLucideChevronDown: typeof import('~icons/lucide/chevron-down')['default']
|
IconLucideChevronDown: typeof import('~icons/lucide/chevron-down')['default']
|
||||||
IconLucideHelpCircle: typeof import('~icons/lucide/help-circle')['default']
|
IconLucideHelpCircle: typeof import('~icons/lucide/help-circle')['default']
|
||||||
|
|||||||
@@ -24,6 +24,16 @@
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="flex items-center">
|
<div class="flex items-center">
|
||||||
|
<div class="inline-flex items-center mr-5">
|
||||||
|
<HoppButtonSecondary
|
||||||
|
to="https://docs.hoppscotch.io/documentation"
|
||||||
|
blank
|
||||||
|
v-tippy="{ theme: 'tooltip' }"
|
||||||
|
:title="t('support.documentation')"
|
||||||
|
:icon="IconHelpCircle"
|
||||||
|
class="rounded hover:bg-primaryDark focus-visible:bg-primaryDark"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
<div v-if="currentUser" class="relative">
|
<div v-if="currentUser" class="relative">
|
||||||
<tippy
|
<tippy
|
||||||
interactive
|
interactive
|
||||||
@@ -69,6 +79,7 @@ import { useSidebar } from '~/composables/useSidebar';
|
|||||||
import { auth } from '~/helpers/auth';
|
import { auth } from '~/helpers/auth';
|
||||||
import IconMenu from '~icons/lucide/menu';
|
import IconMenu from '~icons/lucide/menu';
|
||||||
import IconSidebarOpen from '~icons/lucide/sidebar-open';
|
import IconSidebarOpen from '~icons/lucide/sidebar-open';
|
||||||
|
import IconHelpCircle from '~icons/lucide/help-circle';
|
||||||
import IconSidebarClose from '~icons/lucide/sidebar-close';
|
import IconSidebarClose from '~icons/lucide/sidebar-close';
|
||||||
import { useI18n } from '~/composables/i18n';
|
import { useI18n } from '~/composables/i18n';
|
||||||
|
|
||||||
|
|||||||
@@ -17,13 +17,21 @@
|
|||||||
v-for="provider in workingConfigs.providers"
|
v-for="provider in workingConfigs.providers"
|
||||||
class="space-y-4 py-4"
|
class="space-y-4 py-4"
|
||||||
>
|
>
|
||||||
<div class="flex items-center">
|
<div class="flex justify-between">
|
||||||
<HoppSmartToggle
|
<HoppSmartToggle
|
||||||
:on="provider.enabled"
|
:on="provider.enabled"
|
||||||
@change="provider.enabled = !provider.enabled"
|
@change="provider.enabled = !provider.enabled"
|
||||||
>
|
>
|
||||||
{{ capitalize(provider.name) }}
|
{{ capitalize(provider.name) }}
|
||||||
</HoppSmartToggle>
|
</HoppSmartToggle>
|
||||||
|
<HoppButtonSecondary
|
||||||
|
v-tippy="{ theme: 'tooltip', allowHTML: true }"
|
||||||
|
to="https://docs.hoppscotch.io/documentation/self-host/community-edition/prerequisites#oauth"
|
||||||
|
blank
|
||||||
|
:title="t('support.documentation')"
|
||||||
|
:icon="IconCircleHelp"
|
||||||
|
class="rounded hover:bg-primaryDark focus-visible:bg-primaryDark"
|
||||||
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div v-if="provider.enabled" class="ml-12">
|
<div v-if="provider.enabled" class="ml-12">
|
||||||
@@ -67,6 +75,7 @@ import { useVModel } from '@vueuse/core';
|
|||||||
import { reactive } from 'vue';
|
import { reactive } from 'vue';
|
||||||
import { useI18n } from '~/composables/i18n';
|
import { useI18n } from '~/composables/i18n';
|
||||||
import { ServerConfigs, SsoAuthProviders } from '~/helpers/configs';
|
import { ServerConfigs, SsoAuthProviders } from '~/helpers/configs';
|
||||||
|
import IconCircleHelp from '~icons/lucide/circle-help';
|
||||||
import IconEye from '~icons/lucide/eye';
|
import IconEye from '~icons/lucide/eye';
|
||||||
import IconEyeOff from '~icons/lucide/eye-off';
|
import IconEyeOff from '~icons/lucide/eye-off';
|
||||||
|
|
||||||
|
|||||||
@@ -13,12 +13,22 @@
|
|||||||
</h4>
|
</h4>
|
||||||
|
|
||||||
<div class="flex items-center space-y-4 py-4">
|
<div class="flex items-center space-y-4 py-4">
|
||||||
<HoppSmartToggle
|
<div class="flex justify-between w-full">
|
||||||
:on="dataSharingConfigs.enabled"
|
<HoppSmartToggle
|
||||||
@change="dataSharingConfigs.enabled = !dataSharingConfigs.enabled"
|
:on="dataSharingConfigs.enabled"
|
||||||
>
|
@change="dataSharingConfigs.enabled = !dataSharingConfigs.enabled"
|
||||||
{{ t('configs.data_sharing.toggle_description') }}
|
>
|
||||||
</HoppSmartToggle>
|
{{ t('configs.data_sharing.toggle_description') }}
|
||||||
|
</HoppSmartToggle>
|
||||||
|
<HoppButtonSecondary
|
||||||
|
v-tippy="{ theme: 'tooltip', allowHTML: true }"
|
||||||
|
blank
|
||||||
|
to="https://docs.hoppscotch.io/documentation/self-host/community-edition/telemetry"
|
||||||
|
:title="t('support.documentation')"
|
||||||
|
:icon="IconHelpCircle"
|
||||||
|
class="rounded hover:bg-primaryDark focus-visible:bg-primaryDark"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<HoppButtonSecondary
|
<HoppButtonSecondary
|
||||||
@@ -30,6 +40,9 @@
|
|||||||
blank
|
blank
|
||||||
class="w-min my-2"
|
class="w-min my-2"
|
||||||
/>
|
/>
|
||||||
|
<p class="my-1 text-secondaryLight">
|
||||||
|
{{ t('configs.data_sharing.description') }}
|
||||||
|
</p>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
@@ -40,6 +53,7 @@ import { computed } from 'vue';
|
|||||||
import { useI18n } from '~/composables/i18n';
|
import { useI18n } from '~/composables/i18n';
|
||||||
import { ServerConfigs } from '~/helpers/configs';
|
import { ServerConfigs } from '~/helpers/configs';
|
||||||
import IconShieldQuestion from '~icons/lucide/shield-question';
|
import IconShieldQuestion from '~icons/lucide/shield-question';
|
||||||
|
import IconHelpCircle from '~icons/lucide/help-circle';
|
||||||
|
|
||||||
const t = useI18n();
|
const t = useI18n();
|
||||||
|
|
||||||
|
|||||||
@@ -15,12 +15,22 @@
|
|||||||
|
|
||||||
<div class="space-y-4 py-4">
|
<div class="space-y-4 py-4">
|
||||||
<div class="flex items-center">
|
<div class="flex items-center">
|
||||||
<HoppSmartToggle
|
<div class="flex justify-between w-full">
|
||||||
:on="smtpConfigs.enabled"
|
<HoppSmartToggle
|
||||||
@change="smtpConfigs.enabled = !smtpConfigs.enabled"
|
:on="smtpConfigs.enabled"
|
||||||
>
|
@change="smtpConfigs.enabled = !smtpConfigs.enabled"
|
||||||
{{ t('configs.mail_configs.enable_smtp') }}
|
>
|
||||||
</HoppSmartToggle>
|
{{ t('configs.mail_configs.enable_smtp') }}
|
||||||
|
</HoppSmartToggle>
|
||||||
|
<HoppButtonSecondary
|
||||||
|
blank
|
||||||
|
v-tippy="{ theme: 'tooltip', allowHTML: true }"
|
||||||
|
to="https://docs.hoppscotch.io/documentation/self-host/community-edition/prerequisites#email-delivery"
|
||||||
|
:title="t('support.documentation')"
|
||||||
|
:icon="IconHelpCircle"
|
||||||
|
class="rounded hover:bg-primaryDark focus-visible:bg-primaryDark"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div v-if="smtpConfigs.enabled" class="ml-12">
|
<div v-if="smtpConfigs.enabled" class="ml-12">
|
||||||
@@ -94,6 +104,7 @@ import { useI18n } from '~/composables/i18n';
|
|||||||
import { ServerConfigs } from '~/helpers/configs';
|
import { ServerConfigs } from '~/helpers/configs';
|
||||||
import IconEye from '~icons/lucide/eye';
|
import IconEye from '~icons/lucide/eye';
|
||||||
import IconEyeOff from '~icons/lucide/eye-off';
|
import IconEyeOff from '~icons/lucide/eye-off';
|
||||||
|
import IconHelpCircle from '~icons/lucide/help-circle';
|
||||||
|
|
||||||
const t = useI18n();
|
const t = useI18n();
|
||||||
|
|
||||||
|
|||||||
@@ -5,9 +5,18 @@
|
|||||||
{{ t('infra_tokens.section_title') }}
|
{{ t('infra_tokens.section_title') }}
|
||||||
</h4>
|
</h4>
|
||||||
|
|
||||||
<p class="text-secondaryLight">
|
<div class="flex">
|
||||||
{{ t('infra_tokens.section_description') }}
|
<p class="text-secondaryLight">
|
||||||
</p>
|
{{ t('infra_tokens.section_description') }}
|
||||||
|
</p>
|
||||||
|
<HoppSmartAnchor
|
||||||
|
blank
|
||||||
|
to="https://docs.hoppscotch.io/documentation/self-host/community-edition/admin-dashboard#infratokens"
|
||||||
|
:label="t('support.more_info')"
|
||||||
|
class="underline ml-1"
|
||||||
|
/>
|
||||||
|
<icon-lucide-arrow-up-right class="underline w-4 h-4" />
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<HoppButtonSecondary
|
<HoppButtonSecondary
|
||||||
|
|||||||
@@ -13,18 +13,34 @@
|
|||||||
/>
|
/>
|
||||||
</template>
|
</template>
|
||||||
<template #footer>
|
<template #footer>
|
||||||
<span class="flex space-x-2">
|
<div class="w-full">
|
||||||
<HoppButtonPrimary
|
<p class="text-secondaryLight mb-5 text-center">
|
||||||
:label="t('users.add_user')"
|
{{ t('users.invite_users_description') }}
|
||||||
@click="emit('send-invite', email)"
|
</p>
|
||||||
/>
|
|
||||||
<HoppButtonSecondary
|
<div class="flex justify-between">
|
||||||
:label="t('users.cancel')"
|
<HoppButtonSecondary
|
||||||
outline
|
v-tippy="{ theme: 'tooltip', allowHTML: true }"
|
||||||
filled
|
to="https://docs.hoppscotch.io/documentation"
|
||||||
@click="hideModal"
|
blank
|
||||||
/>
|
:title="t('support.documentation')"
|
||||||
</span>
|
:icon="IconCircleHelp"
|
||||||
|
class="rounded hover:bg-primaryDark focus-visible:bg-primaryDark"
|
||||||
|
/>
|
||||||
|
<span class="flex space-x-2">
|
||||||
|
<HoppButtonPrimary
|
||||||
|
:label="t('users.add_user')"
|
||||||
|
@click="emit('send-invite', email)"
|
||||||
|
/>
|
||||||
|
<HoppButtonSecondary
|
||||||
|
:label="t('users.cancel')"
|
||||||
|
outline
|
||||||
|
filled
|
||||||
|
@click="hideModal"
|
||||||
|
/>
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
</template>
|
</template>
|
||||||
</HoppSmartModal>
|
</HoppSmartModal>
|
||||||
</template>
|
</template>
|
||||||
@@ -32,6 +48,7 @@
|
|||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { ref } from 'vue';
|
import { ref } from 'vue';
|
||||||
import { useI18n } from '~/composables/i18n';
|
import { useI18n } from '~/composables/i18n';
|
||||||
|
import IconCircleHelp from '~icons/lucide/circle-help';
|
||||||
|
|
||||||
const t = useI18n();
|
const t = useI18n();
|
||||||
|
|
||||||
|
|||||||
@@ -1,7 +1,15 @@
|
|||||||
|
/*
|
||||||
|
* Type used to send error data to the Fallback catch-all component
|
||||||
|
*/
|
||||||
|
export type ErrorPageData = {
|
||||||
|
message: string;
|
||||||
|
statusCode?: number;
|
||||||
|
};
|
||||||
|
|
||||||
/* No cookies were found in the auth request
|
/* No cookies were found in the auth request
|
||||||
* (AuthService)
|
* (AuthService)
|
||||||
*/
|
*/
|
||||||
export const COOKIES_NOT_FOUND = 'auth/cookies_not_found' as const;
|
export const COOKIES_NOT_FOUND = '[GraphQL] auth/cookies_not_found' as const;
|
||||||
|
|
||||||
export const UNAUTHORIZED = 'Unauthorized' as const;
|
export const UNAUTHORIZED = 'Unauthorized' as const;
|
||||||
|
|
||||||
|
|||||||
@@ -1,65 +1,74 @@
|
|||||||
import { createApp } from 'vue';
|
|
||||||
import urql, { createClient, cacheExchange, fetchExchange } from '@urql/vue';
|
|
||||||
import { authExchange } from '@urql/exchange-auth';
|
import { authExchange } from '@urql/exchange-auth';
|
||||||
|
import urql, { cacheExchange, createClient, fetchExchange } from '@urql/vue';
|
||||||
|
import { createApp, h } from 'vue';
|
||||||
import App from './App.vue';
|
import App from './App.vue';
|
||||||
|
import ErrorComponent from './pages/_.vue';
|
||||||
|
|
||||||
// STYLES
|
// STYLES
|
||||||
import '@hoppscotch/ui/style.css';
|
|
||||||
import '../assets/scss/styles.scss';
|
|
||||||
import '../assets/scss/tailwind.scss';
|
|
||||||
import '@fontsource-variable/inter';
|
import '@fontsource-variable/inter';
|
||||||
import '@fontsource-variable/material-symbols-rounded';
|
import '@fontsource-variable/material-symbols-rounded';
|
||||||
import '@fontsource-variable/roboto-mono';
|
import '@fontsource-variable/roboto-mono';
|
||||||
|
import '@hoppscotch/ui/style.css';
|
||||||
|
import '../assets/scss/styles.scss';
|
||||||
|
import '../assets/scss/tailwind.scss';
|
||||||
// END STYLES
|
// END STYLES
|
||||||
|
|
||||||
import { HOPP_MODULES } from './modules';
|
|
||||||
import { auth } from './helpers/auth';
|
|
||||||
import { pipe } from 'fp-ts/function';
|
import { pipe } from 'fp-ts/function';
|
||||||
import * as O from 'fp-ts/Option';
|
import * as O from 'fp-ts/Option';
|
||||||
|
import { auth } from './helpers/auth';
|
||||||
import { GRAPHQL_UNAUTHORIZED } from './helpers/errors';
|
import { GRAPHQL_UNAUTHORIZED } from './helpers/errors';
|
||||||
|
import { HOPP_MODULES } from './modules';
|
||||||
|
|
||||||
// Top-level await is not available in our targets
|
|
||||||
(async () => {
|
(async () => {
|
||||||
const app = createApp(App).use(
|
try {
|
||||||
urql,
|
// Create URQL client
|
||||||
createClient({
|
const urqlClient = createClient({
|
||||||
url: import.meta.env.VITE_BACKEND_GQL_URL,
|
url: import.meta.env.VITE_BACKEND_GQL_URL,
|
||||||
requestPolicy: 'network-only',
|
requestPolicy: 'network-only',
|
||||||
fetchOptions: () => {
|
fetchOptions: () => ({
|
||||||
return {
|
credentials: 'include',
|
||||||
credentials: 'include',
|
}),
|
||||||
};
|
|
||||||
},
|
|
||||||
exchanges: [
|
exchanges: [
|
||||||
cacheExchange,
|
cacheExchange,
|
||||||
authExchange(async () => {
|
authExchange(async () => ({
|
||||||
return {
|
addAuthToOperation(operation) {
|
||||||
addAuthToOperation(operation) {
|
return operation;
|
||||||
return operation;
|
},
|
||||||
},
|
async refreshAuth() {
|
||||||
|
pipe(
|
||||||
async refreshAuth() {
|
await auth.performAuthRefresh(),
|
||||||
pipe(
|
O.getOrElseW(() => auth.signOutUser(true))
|
||||||
await auth.performAuthRefresh(),
|
);
|
||||||
O.getOrElseW(() => auth.signOutUser(true))
|
},
|
||||||
);
|
didAuthError(error, _operation) {
|
||||||
},
|
return error.message === GRAPHQL_UNAUTHORIZED;
|
||||||
|
},
|
||||||
didAuthError(error, _operation) {
|
})),
|
||||||
return error.message === GRAPHQL_UNAUTHORIZED;
|
|
||||||
},
|
|
||||||
};
|
|
||||||
}),
|
|
||||||
fetchExchange,
|
fetchExchange,
|
||||||
],
|
],
|
||||||
})
|
});
|
||||||
);
|
|
||||||
|
|
||||||
// Initialize auth
|
// Initialize auth
|
||||||
await auth.performAuthInit();
|
await auth.performAuthInit();
|
||||||
|
|
||||||
// Initialize modules
|
const app = createApp({
|
||||||
HOPP_MODULES.forEach((mod) => mod.onVueAppInit?.(app));
|
render: () => h(App),
|
||||||
|
}).use(urql, urqlClient);
|
||||||
|
|
||||||
app.mount('#app');
|
// Initialize modules
|
||||||
|
HOPP_MODULES.forEach((mod) => mod.onVueAppInit?.(app));
|
||||||
|
|
||||||
|
app.mount('#app');
|
||||||
|
} catch (error) {
|
||||||
|
// Mount the fallback component in case of an error
|
||||||
|
createApp({
|
||||||
|
render: () =>
|
||||||
|
h(ErrorComponent, {
|
||||||
|
error: {
|
||||||
|
message:
|
||||||
|
'Failed to connect to the backend server, make sure the backend is setup correctly',
|
||||||
|
},
|
||||||
|
}),
|
||||||
|
}).mount('#app');
|
||||||
|
}
|
||||||
})();
|
})();
|
||||||
|
|||||||
@@ -1,41 +1,44 @@
|
|||||||
<!-- The Catch-All Page -->
|
<!-- The Fallback Catch-All Page -->
|
||||||
<!-- Reserved for Critical Errors and 404 ONLY -->
|
|
||||||
<template>
|
<template>
|
||||||
<div
|
<div
|
||||||
class="flex flex-col items-center justify-center"
|
class="flex flex-col items-center h-screen"
|
||||||
:class="{ 'min-h-screen': statusCode !== 404 }"
|
:class="{ 'min-h-screen': props.error?.statusCode !== 404 }"
|
||||||
>
|
>
|
||||||
<img
|
<div class="flex flex-col items-center justify-center h-full">
|
||||||
:src="imgUrl"
|
<img
|
||||||
loading="lazy"
|
:src="imgUrl"
|
||||||
class="inline-flex flex-col object-contain object-center mb-2 h-46 w-46"
|
loading="lazy"
|
||||||
:alt="message"
|
class="inline-flex flex-col object-contain object-center mb-2 h-46 w-46"
|
||||||
/>
|
:alt="message"
|
||||||
<h1 class="mb-2 text-4xl heading">
|
|
||||||
{{ statusCode }}
|
|
||||||
</h1>
|
|
||||||
<p class="mb-4 text-secondaryLight">{{ message }}</p>
|
|
||||||
<p class="mt-4 space-x-2">
|
|
||||||
<HoppButtonSecondary to="/" :icon="IconHome" filled label="Home" />
|
|
||||||
<HoppButtonSecondary
|
|
||||||
:icon="IconRefreshCW"
|
|
||||||
label="Reload"
|
|
||||||
filled
|
|
||||||
@click="reloadApplication"
|
|
||||||
/>
|
/>
|
||||||
</p>
|
<h1 v-if="props.error?.statusCode" class="mb-2 text-4xl heading">
|
||||||
|
{{ props.error.statusCode }}
|
||||||
|
</h1>
|
||||||
|
<p class="mb-4 text-lg text-secondaryDark">{{ message }}</p>
|
||||||
|
<p class="mt-4 space-x-2">
|
||||||
|
<HoppButtonSecondary
|
||||||
|
to="https://docs.hoppscotch.io/documentation"
|
||||||
|
:icon="IconTextSearch"
|
||||||
|
filled
|
||||||
|
blank
|
||||||
|
label="Documentation"
|
||||||
|
/>
|
||||||
|
<HoppButtonSecondary
|
||||||
|
:icon="IconRefreshCW"
|
||||||
|
label="Reload"
|
||||||
|
filled
|
||||||
|
@click="reloadApplication"
|
||||||
|
/>
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import IconRefreshCW from '~icons/lucide/refresh-cw';
|
|
||||||
import IconHome from '~icons/lucide/home';
|
|
||||||
import { PropType, computed } from 'vue';
|
import { PropType, computed } from 'vue';
|
||||||
|
import { ErrorPageData } from '~/helpers/errors';
|
||||||
export type ErrorPageData = {
|
import IconRefreshCW from '~icons/lucide/refresh-cw';
|
||||||
message: string;
|
import IconTextSearch from '~icons/lucide/text-search';
|
||||||
statusCode: number;
|
|
||||||
};
|
|
||||||
|
|
||||||
const props = defineProps({
|
const props = defineProps({
|
||||||
error: {
|
error: {
|
||||||
@@ -44,9 +47,7 @@ const props = defineProps({
|
|||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
const imgUrl = `${import.meta.env.BASE_URL}images/youre_lost.svg`
|
const imgUrl = `${import.meta.env.BASE_URL}images/youre_lost.svg`;
|
||||||
|
|
||||||
const statusCode = computed(() => props.error?.statusCode ?? 404);
|
|
||||||
|
|
||||||
const message = computed(
|
const message = computed(
|
||||||
() => props.error?.message ?? 'The page you are looking for does not exist.'
|
() => props.error?.message ?? 'The page you are looking for does not exist.'
|
||||||
|
|||||||
@@ -7,9 +7,14 @@
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="flex justify-between items-center py-6">
|
<div class="flex justify-between items-center py-6">
|
||||||
<h3 class="text-lg font-bold text-accentContrast">
|
<div>
|
||||||
{{ t('users.pending_invites') }}
|
<h3 class="text-lg font-bold text-accentContrast">
|
||||||
</h3>
|
{{ t('users.pending_invites') }}
|
||||||
|
</h3>
|
||||||
|
<p class="my-1 text-secondaryLight">
|
||||||
|
{{ t('users.pending_invites_description') }}
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
|
||||||
<HoppButtonSecondary
|
<HoppButtonSecondary
|
||||||
v-if="pendingInvites?.length"
|
v-if="pendingInvites?.length"
|
||||||
|
|||||||
Reference in New Issue
Block a user