Skip to content

Commit

Permalink
Merge pull request #5253 from systeminit/wendy/eng-2901-see-expired-a…
Browse files Browse the repository at this point in the history
…nd-revoked-api-tokens

feat(web) - UI for revoking auth tokens, active and inactive token lists
  • Loading branch information
wendybujalski authored Jan 15, 2025
2 parents bc5fec4 + 9682ab5 commit 02d15e0
Show file tree
Hide file tree
Showing 25 changed files with 317 additions and 131 deletions.
5 changes: 3 additions & 2 deletions app/auth-portal/src/App.vue
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
<template>
<div class="text-black dark:text-white">
<div :class="clsx(themeClasses('text-shade-100', 'text-shade-0'))">
<DeployNotification />

<template v-if="BROWSER_IS_MOBILE">
Expand Down Expand Up @@ -244,6 +244,7 @@ import {
DropdownMenuItem,
ErrorMessage,
Inline,
themeClasses,
} from "@si/vue-lib/design-system";
import "floating-vue/dist/style.css";
Expand Down Expand Up @@ -272,7 +273,7 @@ useHead(
bodyAttrs: {
// add some base classes we need these type classes set for capsize plugin to work throughout
// and add dark mode style/class
class: tw`font-sans text-base leading-none text-black dark:text-white`,
class: tw`font-sans text-base leading-none text-shade-100 dark:text-shade-0`,
},
htmlAttrs: {
style: () => `color-scheme: ${rootTheme.value};`,
Expand Down
75 changes: 75 additions & 0 deletions app/auth-portal/src/components/AuthTokenList.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
<template>
<Stack spacing="xs">
<div class="text-lg font-bold line-clamp-3 break-words">{{ title }}</div>
<table class="w-full table-fixed">
<thead>
<tr
:class="
clsx(
'children:p-xs children:font-bold text-left text-xs uppercase',
themeClasses(
'bg-neutral-300 text-shade-100',
'bg-shade-100 text-shade-0',
),
)
"
>
<th scope="col">Name</th>
<th scope="col" class="w-52">Created</th>
<th scope="col" class="w-52">
{{ active ? "Expires" : "Expiration" }}
</th>
<th
v-if="workspace.role === 'OWNER'"
class="w-24 text-center"
scope="col"
>
<template v-if="active">Revoke</template>
<template v-else>Revoked</template>
</th>
</tr>
</thead>
<tbody>
<AuthTokenListItem
v-for="authToken of authTokens"
:key="authToken.token.id"
:authToken="authToken"
:workspace="workspace"
:active="active"
@revoked="emit('revoked', authToken.token.id)"
@renamed="(newName) => emit('renamed', authToken.token.id, newName)"
/>
</tbody>
</table>
</Stack>
</template>

<script lang="ts" setup>
import { computed, PropType } from "vue";
import { Stack, themeClasses } from "@si/vue-lib/design-system";
import clsx from "clsx";
import { Workspace } from "@/store/workspaces.store";
import AuthTokenListItem from "@/components/AuthTokenListItem.vue";
import { AuthToken } from "@/store/authTokens.store";
export interface AuthTokenWithRealtimeData {
token: AuthToken;
isExpired: boolean;
isActive: boolean;
}
const props = defineProps({
workspace: { type: Object as PropType<Workspace>, required: true },
authTokens: { type: Array<AuthTokenWithRealtimeData>, default: [] },
active: { type: Boolean },
});
const title = computed(() =>
props.active ? "Active Tokens" : "Inactive Tokens",
);
const emit = defineEmits<{
(e: "revoked", id: string): void;
(e: "renamed", id: string, newName: string): void;
}>();
</script>
126 changes: 87 additions & 39 deletions app/auth-portal/src/components/AuthTokenListItem.vue
Original file line number Diff line number Diff line change
Expand Up @@ -6,48 +6,82 @@
'odd:bg-neutral-200 even:bg-neutral-100',
'odd:bg-neutral-700 even:bg-neutral-800',
),
'children:p-xs children:truncate text-sm',
active
? themeClasses('text-shade-100', 'text-shade-0')
: themeClasses('text-neutral-700', 'text-neutral-300'),
)
"
class="children:px-sm children:py-xs children:truncate text-sm font-medium text-gray-800 dark:text-gray-200"
>
<td>
<div
class="xl:max-w-[800px] lg:max-w-[60vw] md:max-w-[50vw] sm:max-w-[40vw] max-w-[150px] truncate"
>
{{ authToken.name }}
</div>
<TruncateWithTooltip>{{ token.name }}</TruncateWithTooltip>
</td>
<!-- TODO show user of token if it's not current user--right now only owner can create -->
<td>{{ createdAt }}</td>
<td>{{ expiresAt }}</td>
<!--td class="text-center">
<ErrorMessage :asyncState="revoke" />
<VButton
v-if="workspace.role === 'OWNER'"
:loading="revoke.isLoading.value"
class="cursor-pointer"
icon="trash"
loadingText=""
size="2xs"
variant="transparent"
@click="revoke.execute()"
<td><Timestamp size="long" :date="createdAt" enableDetailTooltip /></td>
<td :class="clsx(!active && expired && 'text-destructive-500 font-bold')">
<Timestamp
v-if="expiresAt"
size="long"
:date="expiresAt"
enableDetailTooltip
/>
</td-->
<template v-else>Never</template>
</td>
<td v-if="workspace.role === 'OWNER'" class="text-center">
<template v-if="active">
<IconButton
v-if="revoke.error.value"
icon="alert-triangle"
iconTone="destructive"
class="w-min mx-auto"
tooltip="Error. Token not revoked!"
tooltipPlacement="top"
@click="revoke.execute()"
/>
<IconButton
v-else
:loading="revoke.isLoading.value"
icon="trash"
iconTone="destructive"
iconIdleTone="shade"
class="w-min mx-auto"
tooltip="Revoke Token"
tooltipPlacement="top"
@click="revoke.execute()"
/>
</template>
<span
v-else-if="revokedAt"
v-tooltip="revokedTooltip"
class="text-destructive-500 font-bold cursor-pointer w-full text-center hover:underline"
>
Yes
</span>
</td>
</tr>
</template>

<script lang="ts" setup>
import clsx from "clsx";
import { themeClasses } from "@si/vue-lib/design-system";
import {
themeClasses,
IconButton,
TruncateWithTooltip,
Timestamp,
} from "@si/vue-lib/design-system";
import { computed } from "vue";
import { useAsyncState } from "@vueuse/core";
import { apiData } from "@si/vue-lib/pinia";
import { Workspace } from "@/store/workspaces.store";
import { AuthToken } from "@/store/authTokens.store";
import { useAuthTokensApi } from "@/store/authTokens.store";
import { AuthTokenWithRealtimeData } from "./AuthTokenList.vue";
// const api = useAuthTokensApi();
const api = useAuthTokensApi();
const props = defineProps<{
authToken: AuthToken;
authToken: AuthTokenWithRealtimeData;
workspace: Readonly<Workspace>;
active: boolean;
}>();
const emit = defineEmits<{
Expand All @@ -56,26 +90,40 @@ const emit = defineEmits<{
}>();
/** Action to revoke token */
// const revoke = useAsyncState(
// async () => {
// const { workspace, authToken } = props;
// await apiData(api.REVOKE_AUTH_TOKEN(workspace.id, authToken.id));
// emit("revoked");
// },
// undefined,
// { immediate: false },
// );
const createdAt = computed(() =>
new Date(props.authToken.createdAt).toLocaleString(),
const revoke = useAsyncState(
async () => {
const { workspace, authToken } = props;
await apiData(api.REVOKE_AUTH_TOKEN(workspace.id, authToken.token.id));
emit("revoked");
},
undefined,
{ immediate: false },
);
const token = computed(() => props.authToken.token);
const createdAt = computed(() => new Date(token.value.createdAt));
const expiresAt = computed(() =>
props.authToken.expiresAt
? new Date(props.authToken.expiresAt).toLocaleString()
: undefined,
token.value.expiresAt ? new Date(token.value.expiresAt) : undefined,
);
const expired = computed(() => props.authToken.isExpired);
const revokedAt = computed(() =>
token.value.revokedAt ? new Date(token.value.revokedAt) : undefined,
);
const revokedTooltip = computed(() => {
if (revokedAt.value) {
return {
content: revokedAt.value,
theme: "instant-show",
};
}
return null;
});
// /** Action to rename token */
// const rename = useAsyncState(
// async () => {
Expand Down
2 changes: 1 addition & 1 deletion app/auth-portal/src/components/MemberListItem.vue
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
<template>
<tr
class="children:px-md children:py-sm children:truncate text-sm font-medium text-gray-800 dark:text-gray-200"
class="children:px-md children:py-sm children:truncate text-sm font-medium text-neutral-800 dark:text-neutral-200"
>
<td class="">
<div
Expand Down
5 changes: 4 additions & 1 deletion app/auth-portal/src/main.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import "@si/vue-lib/tailwind/tailwind.css";
import "@/assets/extra-style.less";

import "./lib/posthog";
import { FLOATING_VUE_THEMES } from "@si/vue-lib/design-system";
import App from "./App.vue";
import store from "./store";
import { initRouterGuards, routerOptions } from "./router";
Expand All @@ -25,7 +26,9 @@ export const createApp = ViteSSG(
}) => {
// install plugins etc.
app.use(store);
app.use(FloatingVue);
app.use(FloatingVue, {
themes: FLOATING_VUE_THEMES,
});

if (isClient) initRouterGuards(router);
},
Expand Down
8 changes: 4 additions & 4 deletions app/auth-portal/src/pages/SetupProductionUser.vue
Original file line number Diff line number Diff line change
Expand Up @@ -120,7 +120,7 @@
<tr
v-for="quarantinedUser in quarantinedUsers"
:key="quarantinedUser.userId"
class="children:px-md children:py-sm children:truncate text-sm font-medium text-gray-800 dark:text-gray-200"
class="children:px-md children:py-sm children:truncate text-sm font-medium text-neutral-800 dark:text-neutral-200"
>
<td class="">
<div
Expand Down Expand Up @@ -247,7 +247,7 @@
<tr
v-for="suspendedUser in suspendedUsers"
:key="suspendedUser.userId"
class="children:px-md children:py-sm children:truncate text-sm font-medium text-gray-800 dark:text-gray-200"
class="children:px-md children:py-sm children:truncate text-sm font-medium text-neutral-800 dark:text-neutral-200"
>
<td class="">
<div
Expand Down Expand Up @@ -320,7 +320,7 @@
class="divide-y divide-neutral-300 dark:divide-neutral-700"
>
<tr
class="children:px-md children:py-sm children:truncate text-sm font-medium text-gray-800 dark:text-gray-200"
class="children:px-md children:py-sm children:truncate text-sm font-medium text-neutral-800 dark:text-neutral-200"
>
<td class="">
<div
Expand Down Expand Up @@ -408,7 +408,7 @@
<tr
v-for="user in userSignups"
:key="user.email"
class="children:px-md children:py-sm children:truncate text-sm font-medium text-gray-800 dark:text-gray-200"
class="children:px-md children:py-sm children:truncate text-sm font-medium text-neutral-800 dark:text-neutral-200"
>
<td class="">
<div
Expand Down
Loading

0 comments on commit 02d15e0

Please sign in to comment.