Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix: #1610 refactor authentication handling and session management #1627

Open
wants to merge 9 commits into
base: feat/frontend-stability-refactor
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 8 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
20 changes: 13 additions & 7 deletions .vscode/settings.json
Original file line number Diff line number Diff line change
@@ -1,8 +1,5 @@
{
"editor.rulers": [
80,
120
],
"editor.rulers": [80, 120],
"editor.insertSpaces": true,
"editor.tabSize": 4,
"editor.detectIndentation": true,
Expand All @@ -13,13 +10,22 @@
"python.formatting.provider": "black",
"python.linting.flake8Enabled": true,
"python.linting.enabled": true,
"python.linting.flake8Args": ["--append-config=${workspaceFolder}/server/backend/.flake8"],
"python.linting.flake8Args": [
"--append-config=${workspaceFolder}/server/backend/.flake8"
],
"python.testing.cwd": "./server/backend",

"recommendations": ["Vue.volar", "Vue.vscode-typescript-vue-plugin"],
"python.languageServer": "Pylance",
"files.trimTrailingWhitespace": true,
"files.eol": "\n",
"editor.formatOnSave": true,
"editor.defaultFormatter": "esbenp.prettier-vscode",
"prettier.tabWidth": 4,
"[vue]": {
"editor.defaultFormatter": "esbenp.prettier-vscode"
},
"[typescript]": {
"editor.defaultFormatter": "esbenp.prettier-vscode"
}
}


31 changes: 16 additions & 15 deletions frontend/src/App.vue
Original file line number Diff line number Diff line change
@@ -1,14 +1,14 @@
<script setup lang="ts">
import { defineAsyncComponent, shallowRef, watch, type Component } from 'vue';
import { RouterView } from 'vue-router';
import { useRoute } from 'vue-router';
import ToastMessage from '@/components/common/ToastMessage.vue';
import { VueQueryDevtools } from '@tanstack/vue-query-devtools'
import { defineAsyncComponent, shallowRef, watch, type Component } from "vue";
import { useRoute } from "vue-router";
import AuthProvider from "@/providers/AuthProvider.vue";
import { VueQueryDevtools } from "@tanstack/vue-query-devtools";

const route = useRoute();
const layout_component = shallowRef<Component>();

watch(
() => route.meta.layout ?? 'SimpleLayout',
() => route.meta.layout ?? "SimpleLayout",
(layout) => {
layout_component.value = defineAsyncComponent(
() => import(`@/layouts/${layout}.vue`)
Expand All @@ -19,16 +19,17 @@ watch(
</script>

<template>
<ToastMessage />
<component :is="layout_component">
<router-view />
</component>
<VueQueryDevtools />
<AuthProvider>
<component :is="layout_component">
<router-view />
</component>
<VueQueryDevtools />
</AuthProvider>
</template>

<style lang="scss">
@import 'primeflex/primeflex.css';
@import '@/assets/styles/styles.scss';
@import 'primevue/resources/primevue.min.css';
@import 'primevue/resources/themes/bootstrap4-light-blue/theme.css';
@import "primeflex/primeflex.css";
@import "@/assets/styles/styles.scss";
@import "primevue/resources/primevue.min.css";
@import "primevue/resources/themes/bootstrap4-light-blue/theme.css";
</style>
1 change: 1 addition & 0 deletions frontend/src/assets/images/auth-loading.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
13 changes: 0 additions & 13 deletions frontend/src/components/AuthCallbackHandler.vue

This file was deleted.

23 changes: 13 additions & 10 deletions frontend/src/components/Landing.vue
Original file line number Diff line number Diff line change
@@ -1,14 +1,17 @@
<script setup lang="ts">
import Button from '@/components/common/Button.vue';
import { IconSize } from '@/enum/IconEnum';
import { IdpProvider } from '@/enum/IdpEnum';
import AuthService from '@/services/AuthService';
import logo from '@/assets/images/bc-gov-logo.png';
import TreeLogs from '@/assets/images/tree-logs.jpg';
import { EnvironmentSettings } from '@/services/EnvironmentSettings';
import Button from "@/components/common/Button.vue";
import { IconSize } from "@/enum/IconEnum";
import { IdpProvider } from "@/enum/IdpEnum";
import { EnvironmentSettings } from "@/services/EnvironmentSettings";

import logo from "@/assets/images/bc-gov-logo.png";
import TreeLogs from "@/assets/images/tree-logs.jpg";
import useAuth from "@/composables/useAuth";

const environmentSettings = new EnvironmentSettings();
const isDevEnvironment = environmentSettings.isDevEnvironment();

const auth = useAuth();
</script>

<template>
Expand All @@ -28,7 +31,7 @@ const isDevEnvironment = environmentSettings.isDevEnvironment();
class="landing-button"
:label="`Login with ${IdpProvider.IDIR}`"
id="login-idir-button"
@click="AuthService.login()"
@click="auth.login(IdpProvider.IDIR)"
>
<Icon icon="login" :size="IconSize.medium" />
</Button>
Expand All @@ -38,7 +41,7 @@ const isDevEnvironment = environmentSettings.isDevEnvironment();
:disabled="!isDevEnvironment"
:label="`Login with ${IdpProvider.BCEIDBUSINESS}`"
id="login-business-bceid-button"
@click="AuthService.loginBusinessBceid()"
@click="auth.login(IdpProvider.BCEIDBUSINESS)"
>
<Icon icon="login" :size="IconSize.medium" />
</Button>
Expand All @@ -55,5 +58,5 @@ const isDevEnvironment = environmentSettings.isDevEnvironment();
</template>

<style scoped lang="scss">
@import '@bcgov-nr/nr-theme/style-sheets/landing-page-components-overrides.scss';
@import "@bcgov-nr/nr-theme/style-sheets/landing-page-components-overrides.scss";
</style>
6 changes: 3 additions & 3 deletions frontend/src/components/NotFound.vue
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
<script setup lang="ts">
import { hashRouter } from '@/router';
import { useRoute } from 'vue-router';
import { hashRouter } from "@/router";
import { useRoute } from "vue-router";

console.warn(`Route "${useRoute().path}" not found, redirect to home.`);
hashRouter.push('/');
hashRouter.push("/");
</script>

<template></template>
116 changes: 68 additions & 48 deletions frontend/src/components/UserPermissionHistoryTable/index.vue
Original file line number Diff line number Diff line change
@@ -1,52 +1,60 @@
<script setup lang="ts">
import { watch } from 'vue';
import { isAxiosError } from 'axios';
import { useQuery } from '@tanstack/vue-query';
import { AppActlApiService } from '@/services/ApiServiceFactory';
import DataTable from 'primevue/datatable';
import Column from 'primevue/column';

import { hashRouter } from '@/router';
import TableSkeleton from '@/components/TableSkeleton';
import DateCol from '@/components/UserPermissionHistoryTable/DateCol.vue';
import PermissionDetailsCol from '@/components/UserPermissionHistoryTable/PermissionDetailsCol.vue';
import ChangePerformerCol from '@/components/UserPermissionHistoryTable/ChangePerformerCol.vue';

import { watch } from "vue";
import { isAxiosError } from "axios";
import { useQuery } from "@tanstack/vue-query";
import { AppActlApiService } from "@/services/ApiServiceFactory";
import DataTable from "primevue/datatable";
import Column from "primevue/column";

import { hashRouter } from "@/router";
import TableSkeleton from "@/components/TableSkeleton";
import DateCol from "@/components/UserPermissionHistoryTable/DateCol.vue";
import PermissionDetailsCol from "@/components/UserPermissionHistoryTable/PermissionDetailsCol.vue";
import ChangePerformerCol from "@/components/UserPermissionHistoryTable/ChangePerformerCol.vue";

const props = defineProps<{
userId: string;
applicationId: string
applicationId: string;
}>();

const auditHistoryQuery = useQuery(
{
queryKey: ['permission-audit-history', { user_id: props.userId, application_id: props.applicationId }],
queryFn:
() => AppActlApiService.permissionAuditApi
.getPermissionAuditHistoryByUserAndApplication(
Number(props.userId), Number(props.applicationId)
).then((res) => res.data),
enabled: !!props.userId && !!props.applicationId,
staleTime: 0,
gcTime: 0,
}
);
const auditHistoryQuery = useQuery({
queryKey: [
"permission-audit-history",
{ user_id: props.userId, application_id: props.applicationId },
],
queryFn: () =>
AppActlApiService.permissionAuditApi
.getPermissionAuditHistoryByUserAndApplication(
Number(props.userId),
Number(props.applicationId)
)
.then((res) => res.data),
enabled: !!props.userId && !!props.applicationId,
staleTime: 0,
gcTime: 0,
});

// Navigate back if user has no permission to view data.
watch(() => auditHistoryQuery.error.value, (error) => {
if (isAxiosError(error) && error.response?.status === 403) {
hashRouter.push('/');
watch(
() => auditHistoryQuery.error.value,
(error) => {
if (isAxiosError(error) && error.response?.status === 403) {
hashRouter.push("/");
}
}
});

const headers = ['Date', 'Activity', 'Details', 'Performed by'];
);

const headers = ["Date", "Activity", "Details", "Performed by"];
</script>

<template>
<!-- Skeleton when data is loading -->
<TableSkeleton class-name="user-permission-table" :headers="headers" :row-amount="5"
v-if="auditHistoryQuery.isFetching.value" />
<TableSkeleton
class-name="user-permission-table"
:headers="headers"
:row-amount="5"
v-if="auditHistoryQuery.isFetching.value"
/>

<!-- Simple error display -->
<div v-else-if="auditHistoryQuery.isError.value">
Expand All @@ -59,33 +67,45 @@ const headers = ['Date', 'Activity', 'Details', 'Performed by'];
</div>

<!-- Table with values -->
<DataTable class="user-permission-table" :value="auditHistoryQuery.data.value" :striped-rows="true" v-else>
<DataTable
class="user-permission-table"
:value="auditHistoryQuery.data.value"
:striped-rows="true"
v-else
>
<template #empty> No User Permissions History found.</template>
<Column field="create_date" :header="headers[0]">
<template #body="slotProps">
<DateCol :utc-date="slotProps.data.create_date" />
</template>
</Column>
<Column class="privilege-type-description-col" field="privilege_change_type_description" :header="headers[1]" />
<Column
class="privilege-type-description-col"
field="privilege_change_type_description"
:header="headers[1]"
/>
<Column field="privilege_details" :header="headers[2]">
<template #body="slotProps">
<PermissionDetailsCol :permission-details="slotProps.data.privilege_details" />
<PermissionDetailsCol
:permission-details="slotProps.data.privilege_details"
/>
</template>
</Column>
<Column field="change_performer_user_details" :header="headers[3]">
<template #body="slotProps">
<ChangePerformerCol :performer-details="slotProps.data.change_performer_user_details" />
<ChangePerformerCol
:performer-details="
slotProps.data.change_performer_user_details
"
/>
</template>
</Column>
</DataTable>


</template>

<style lang="scss">
.user-permission-table {
table {

/* Header Corners */
th:first-child {
border-top-left-radius: 0.5rem;
Expand All @@ -110,12 +130,12 @@ const headers = ['Date', 'Activity', 'Details', 'Performed by'];
}

/* Table Row and Cell Styling */
.p-datatable-tbody>tr>td {
.p-datatable-tbody > tr > td {
padding: 1rem;
}

/* Table Header Styling */
.p-datatable-thead>tr>th {
.p-datatable-thead > tr > th {
background: colors.$gray-20;
height: 4rem;
}
Expand All @@ -135,24 +155,24 @@ const headers = ['Date', 'Activity', 'Details', 'Performed by'];
border: none;

.footer-text {
@include type.type-style('body-compact-01');
@include type.type-style("body-compact-01");
display: flex;
flex-direction: row;
justify-content: center;
}
}

/* Hover Effects */
.p-datatable-tbody>tr:hover {
.p-datatable-tbody > tr:hover {
background-color: inherit;
/* Retains the original color of the row */
}

.p-datatable-tbody>tr:nth-child(even):hover {
.p-datatable-tbody > tr:nth-child(even):hover {
background-color: var(--primevue-striped-row-color);
}

.p-datatable-tbody>tr:nth-child(odd):hover {
.p-datatable-tbody > tr:nth-child(odd):hover {
background-color: colors.$white;
}

Expand Down
Loading
Loading