Skip to content

Commit

Permalink
wip
Browse files Browse the repository at this point in the history
  • Loading branch information
luannmoreira committed Aug 27, 2024
1 parent b595bb8 commit 5aaa88b
Show file tree
Hide file tree
Showing 8 changed files with 582 additions and 24 deletions.
417 changes: 415 additions & 2 deletions ui/src/api/client/api.ts

Large diffs are not rendered by default.

96 changes: 96 additions & 0 deletions ui/src/components/Namespace/NamespaceInviteDialog.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,96 @@
<template>
<v-dialog
transition="dialog-bottom-transition"
width="700"
@click:outside="close();"
>
<v-card class="bg-v-theme-surface" data-test="card-dialog">
<v-card-title class="text-h5 pa-4 bg-primary" data-test="dialog-title">{{ modalTitle }}</v-card-title>
<v-container data-test="dialog-text">
<v-row class="mb-2">
<v-col>
<h4>{{ modalMessage }}</h4>
</v-col>
</v-row>
<v-card-actions>
<v-spacer />
<v-btn
variant="text"
color="primary"
data-test="save-btn"
@click="buttonFunction()"
>
{{ buttonText }}
</v-btn>
</v-card-actions>
</v-container>
</v-card>
</v-dialog>
</template>

<script setup lang="ts">
import { ref, onMounted } from "vue";
import axios, { AxiosError } from "axios";
import { useRouter, useRoute } from "vue-router";
import { useStore } from "@/store";
const store = useStore();
const router = useRouter();
const route = useRoute();
const modalTitle = ref("Accept Namespace Invitation");
const modalMessage = ref<string>("Processing...");
const buttonText = ref("Close");
const close = () => {
store.commit("namespaces/setShowNamespaceInvite", false);
router.push("/");
};
const buttonFunction = async () => {
if (buttonText.value === "Close") {
close();
} else {
await store.dispatch("namespaces/switchNamespace", {
tenant_id: route.query["tenant-id"] as string,
});
window.location.reload();
}
};
onMounted(async () => {
if (store.getters["namespaces/showNamespaceInviteDialog"] === true) {
try {
await router.isReady();
await store.dispatch("namespaces/acceptInvite", {
tenant: route.query["tenant-id"] as string || route.query.tenantid as string,
sig: route.query.sig as string,
});
modalMessage.value = "Invitation accepted successfully!";
buttonText.value = "Switch to new namespace";
} catch (error: unknown) {
if (axios.isAxiosError(error)) {
const axiosError = error as AxiosError;
switch (axiosError.response?.status) {
case 400:
modalMessage.value = "Invalid request. Please check the invitation link.";
break;
case 403:
modalMessage.value = "Invalid or unassociated token. Please verify your credentials. Please try again later.";
break;
case 404:
modalMessage.value = "Namespace or member not found. The invitation may have expired.";
break;
case 500:
modalMessage.value = "Our servers couldn't handle your invitation acceptance. Please try again later.";
break;
default:
modalMessage.value = "Unknown error. Please try again later.";
break;
}
}
buttonText.value = "Close";
}
}
});
</script>
12 changes: 11 additions & 1 deletion ui/src/components/User/UserWarning.vue
Original file line number Diff line number Diff line change
Expand Up @@ -49,10 +49,15 @@
v-model="showPaywall"
data-test="PaywallDialog-component"
/>

<NamespaceInviteDialog
v-if="showNamespaceInviteDialog"
v-model="showNamespaceInviteDialog"
/>
</template>

<script setup lang="ts">
import { ref, computed, onMounted } from "vue";
import { ref, computed, onMounted, watch } from "vue";
import { useRouter } from "vue-router";
import Welcome from "../Welcome/Welcome.vue";
import NamespaceInstructions from "../Namespace/NamespaceInstructions.vue";
Expand All @@ -67,6 +72,7 @@ import DeviceAcceptWarning from "../Devices/DeviceAcceptWarning.vue";
import RecoveryHelper from "../AuthMFA/RecoveryHelper.vue";
import MfaForceRecoveryMail from "../AuthMFA/MfaForceRecoveryMail.vue";
import PaywallDialog from "./PaywallDialog.vue";
import NamespaceInviteDialog from "./../Namespace/NamespaceInviteDialog.vue";
const store = useStore();
const router = useRouter();
Expand All @@ -83,6 +89,10 @@ const hasNamespaces = computed(
const hasWarning = computed(
() => store.getters["devices/getDeviceChooserStatus"],
);
const showNamespaceInviteDialog = computed(() => store.getters["namespaces/showNamespaceInviteDialog"]);
watch(showNamespaceInviteDialog, (newValue) => {
console.log(newValue);
});
const stats = computed(() => store.getters["stats/stats"]);
const announcements = computed(() => store.getters["announcement/list"]);
const announcement = computed(() => store.getters["announcement/get"]);
Expand Down
19 changes: 19 additions & 0 deletions ui/src/interfaces/INamespace.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,3 +22,22 @@ export interface INamespace {
created_at: string;
billing: IBilling;
}

export interface INamespaceInvite {
tenant: string;
sig: string;
}

export interface INamespaceSettings {
connection_announcement: string;
session_record: boolean;
}
export interface INamespaceResponse {
settings: INamespaceSettings;
id: string;
tenant_id: string;
name: string;
user_id: string;
email: string;
role: "administrator" | "operator" | "observer" | "owner";
}
12 changes: 11 additions & 1 deletion ui/src/router/index.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
/* eslint-disable camelcase */
import { RouteRecordRaw, createRouter, createWebHistory } from "vue-router";
import { envVariables } from "../envVariables";
import { store } from "@/store";
Expand All @@ -24,6 +25,7 @@ const SettingNamespace = () => import("@/components/Setting/SettingNamespace.vue
const SettingPrivateKeys = () => import("@/components/Setting/SettingPrivateKeys.vue");
const SettingTags = () => import("@/components/Setting/SettingTags.vue");
const SettingBilling = () => import("@/components/Setting/SettingBilling.vue");
const NamespaceInviteDialog = () => import("@/components/Namespace/NamespaceInviteDialog.vue");

export const routes: Array<RouteRecordRaw> = [
{
Expand Down Expand Up @@ -268,6 +270,11 @@ export const routes: Array<RouteRecordRaw> = [
name: "publicKeys",
component: PublicKeys,
},
{
path: "/accept-invite",
name: "AcceptInvite",
component: NamespaceInviteDialog,
},
{
path: "/settings",
name: "settings",
Expand Down Expand Up @@ -336,7 +343,10 @@ router.beforeEach(async (to, from, next) => {

// Redirect to the appropriate page based on authentication status
if (requiresAuth && !isLoggedIn) {
next({ name: "login" }); // Redirect to login page if authentication is required and user is not logged in
next({
name: "login",
query: { redirect: to.fullPath },
}); // Redirect to login page if authentication is required and user is not logged in
} else if (to.name === "login" && isLoggedIn) {
next({ path: "/" }); // Redirect from login page to home if user is already logged in
} else {
Expand Down
18 changes: 3 additions & 15 deletions ui/src/store/api/namespaces.ts
Original file line number Diff line number Diff line change
@@ -1,20 +1,6 @@
import { INamespace } from "@/interfaces/INamespace";
import { INamespace, INamespaceInvite, INamespaceResponse } from "@/interfaces/INamespace";
import { namespacesApi } from "../../api/http";

interface INamespaceSettings {
connection_announcement: string;
session_record: boolean;
}
interface INamespaceResponse {
settings: INamespaceSettings;
id: string;
tenant_id: string;
name: string;
user_id: string;
email: string;
role: "administrator" | "operator" | "observer" | "owner";
}

export const postNamespace = async (data: string) => namespacesApi.createNamespace({ name: data });

export const fetchNamespaces = async (page: number, perPage: number, filter: string) => {
Expand Down Expand Up @@ -49,3 +35,5 @@ export const removeUserFromNamespace = async (
) => namespacesApi.removeNamespaceMember(data.tenant_id, data.user_id);

export const tenantSwitch = async (data: INamespace) => namespacesApi.getNamespaceToken(data.tenant_id);

export const acceptNamespaceInvite = async (data: INamespaceInvite) => namespacesApi.acceptInvite(data.tenant, { sig: data.sig });
24 changes: 23 additions & 1 deletion ui/src/store/modules/namespaces.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { Module } from "vuex";
import * as apiNamespace from "../api/namespaces";
import { INamespace, INamespaceMember } from "@/interfaces/INamespace";
import { INamespace, INamespaceMember, INamespaceInvite } from "@/interfaces/INamespace";
import { IBilling } from "@/interfaces/IBilling";
import { State } from "..";

Expand All @@ -12,6 +12,9 @@ export interface NamespacesState {
invoicesLength: number;
numberNamespaces: number;
owner: boolean;
inviteObject: INamespaceInvite;
showNamespaceInviteDialog: boolean,

}

export const namespaces: Module<NamespacesState, State> = {
Expand All @@ -24,6 +27,11 @@ export const namespaces: Module<NamespacesState, State> = {
invoicesLength: 0,
numberNamespaces: 0,
owner: false,
inviteObject: {
sig: "",
tenant: "",
},
showNamespaceInviteDialog: false,
},

getters: {
Expand All @@ -32,6 +40,7 @@ export const namespaces: Module<NamespacesState, State> = {
getNumberNamespaces: (state) => state.numberNamespaces,
owner: (state) => state.owner,
billing: (state) => state.billing,
showNamespaceInviteDialog: (state) => state.showNamespaceInviteDialog,
},

mutations: {
Expand All @@ -40,6 +49,10 @@ export const namespaces: Module<NamespacesState, State> = {
state.numberNamespaces = parseInt(res.headers["x-total-count"], 10);
},

setShowNamespaceInvite: (state, status) => {
state.showNamespaceInviteDialog = status;
},

setNamespace: (state, res) => {
state.namespace = res.data;
},
Expand Down Expand Up @@ -161,6 +174,15 @@ export const namespaces: Module<NamespacesState, State> = {
}
},

acceptInvite: async (context, data) => {
try {
await apiNamespace.acceptNamespaceInvite(data);
} catch (error) {
console.error(error);
throw error;
}
},

clearNamespaceList: (context) => {
context.commit("clearNamespaceList");
},
Expand Down
8 changes: 4 additions & 4 deletions ui/src/views/Login.vue
Original file line number Diff line number Diff line change
Expand Up @@ -170,7 +170,8 @@ onMounted(async () => {
const login = async () => {
try {
await store.dispatch("auth/login", { username: username.value, password: password.value });
if (isMfa.value === true) {
if (isMfa.value) {
router.push({ name: "MfaLogin" });
localStorage.setItem("name", username.value);
} else {
Expand All @@ -197,13 +198,12 @@ const login = async () => {
invalidCredentials.value = true;
Object.assign(invalid, {
title: "Your account is blocked for ",
msg: "There was too many failed login attempts. Please wait to try again.",
msg: "There were too many failed login attempts. Please wait to try again.",
timeout: true,
});
break;
default:
snackbar.showError("Something went wrong in our server. Please try again later.");
snackbar.showError("Something went wrong on our server. Please try again later.");
handleError(error);
}
return;
Expand Down

0 comments on commit 5aaa88b

Please sign in to comment.