remove jetstream inertia properties; remove unused ApiTokenManager;

This commit is contained in:
Gregor Vostrak
2026-06-05 16:32:38 +02:00
committed by Constantin Graf
parent 56ea0ed90e
commit bffd0773be
10 changed files with 9 additions and 377 deletions

View File

@@ -20,12 +20,6 @@ import {
} from '@/packages/ui/src';
const page = usePage<{
jetstream: {
canCreateTeams: boolean;
hasTeamFeatures: boolean;
managesProfilePhotos: boolean;
hasApiFeatures: boolean;
};
auth: {
user: User & {
all_teams: Organization[];
@@ -39,7 +33,7 @@ const switchToTeam = (organization: Organization) => {
</script>
<template>
<DropdownMenu v-if="page.props.jetstream.hasTeamFeatures">
<DropdownMenu>
<DropdownMenuTrigger
class="flex w-full text-left hover:bg-white/10 focus-visible:ring-2 focus-visible:ring-ring cursor-pointer transition pl-2 py-1 rounded w-full items-center justify-between"
as-child>
@@ -78,7 +72,7 @@ const switchToTeam = (organization: Organization) => {
<Link href="/billing" class="inline-flex items-center w-full"> Billing </Link>
</DropdownMenuItem>
<DropdownMenuItem v-if="page.props.jetstream.canCreateTeams" as-child>
<DropdownMenuItem as-child>
<Link
:href="route('teams.create')"
class="inline-flex items-center gap-2.5 w-full">

View File

@@ -10,7 +10,6 @@ import {
} from '@/packages/ui/src';
import {
UserCircleIcon,
KeyIcon,
ArrowLeftOnRectangleIcon,
ChatBubbleLeftRightIcon,
} from '@heroicons/vue/24/solid';
@@ -19,12 +18,6 @@ import { openFeedback } from '@/utils/feedback';
const page = usePage<{
has_services_extension?: boolean;
has_billing_extension?: boolean;
jetstream: {
canCreateTeams: boolean;
hasTeamFeatures: boolean;
managesProfilePhotos: boolean;
hasApiFeatures: boolean;
};
auth: {
user: User & {
all_teams: Organization[];
@@ -61,15 +54,6 @@ const logout = () => {
</Link>
</DropdownMenuItem>
<DropdownMenuItem v-if="page.props.jetstream.hasApiFeatures" as-child>
<Link
:href="route('api-tokens.index')"
class="inline-flex items-center gap-2.5 w-full">
<KeyIcon class="w-5 h-5 text-icon-default" />
<span>API Tokens</span>
</Link>
</DropdownMenuItem>
<DropdownMenuItem v-if="page.props.has_services_extension" as-child>
<button
type="button"

View File

@@ -1,28 +0,0 @@
<script setup lang="ts">
import ApiTokenManager from '@/Pages/API/Partials/ApiTokenManager.vue';
import AppLayout from '@/Layouts/AppLayout.vue';
import type { Token } from '@/types/jetstream';
defineProps<{
tokens: Token[];
availablePermissions: string[];
defaultPermissions: string[];
}>();
</script>
<template>
<AppLayout title="API Tokens">
<template #header>
<h2 class="font-semibold text-xl text-text-primary leading-tight">API Tokens</h2>
</template>
<div>
<div class="max-w-7xl mx-auto py-10 sm:px-6 lg:px-8">
<ApiTokenManager
:tokens="tokens"
:available-permissions="availablePermissions"
:default-permissions="defaultPermissions" />
</div>
</div>
</AppLayout>
</template>

View File

@@ -1,263 +0,0 @@
<script setup lang="ts">
import { ref } from 'vue';
import { useForm, usePage } from '@inertiajs/vue3';
import ActionMessage from '@/Components/ActionMessage.vue';
import ActionSection from '@/Components/ActionSection.vue';
import Checkbox from '@/packages/ui/src/Input/Checkbox.vue';
import ConfirmationModal from '@/Components/ConfirmationModal.vue';
import DangerButton from '@/packages/ui/src/Buttons/DangerButton.vue';
import DialogModal from '@/packages/ui/src/DialogModal.vue';
import FormSection from '@/Components/FormSection.vue';
import { Field, FieldLabel, FieldError } from '@/packages/ui/src/field';
import PrimaryButton from '@/packages/ui/src/Buttons/PrimaryButton.vue';
import SecondaryButton from '@/packages/ui/src/Buttons/SecondaryButton.vue';
import SectionBorder from '@/Components/SectionBorder.vue';
import TextInput from '@/packages/ui/src/Input/TextInput.vue';
import type { Token } from '@/types/jetstream';
const props = defineProps<{
tokens: Token[];
availablePermissions: string[];
defaultPermissions: string[];
}>();
const createApiTokenForm = useForm({
name: '',
permissions: props.defaultPermissions,
});
const page = usePage<{
jetstream: {
flash: {
token: string;
};
};
}>();
const updateApiTokenForm = useForm<{
permissions: string[];
}>({
permissions: [],
});
const deleteApiTokenForm = useForm({});
const displayingToken = ref(false);
const managingPermissionsFor = ref<Token | null>(null);
const apiTokenBeingDeleted = ref<Token | null>(null);
const createApiToken = () => {
createApiTokenForm.post(route('api-tokens.store'), {
preserveScroll: true,
onSuccess: () => {
displayingToken.value = true;
createApiTokenForm.reset();
},
});
};
const manageApiTokenPermissions = (token: Token) => {
updateApiTokenForm.permissions = token.abilities;
managingPermissionsFor.value = token;
};
const updateApiToken = () => {
updateApiTokenForm.put(route('api-tokens.update', managingPermissionsFor.value?.id), {
preserveScroll: true,
preserveState: true,
onSuccess: () => (managingPermissionsFor.value = null),
});
};
const confirmApiTokenDeletion = (token: Token) => {
apiTokenBeingDeleted.value = token;
};
const deleteApiToken = () => {
deleteApiTokenForm.delete(route('api-tokens.destroy', apiTokenBeingDeleted.value?.id), {
preserveScroll: true,
preserveState: true,
onSuccess: () => (apiTokenBeingDeleted.value = null),
});
};
</script>
<template>
<div>
<!-- Generate API Token -->
<FormSection @submitted="createApiToken">
<template #title> Create API Token </template>
<template #description>
API tokens allow third-party services to authenticate with our application on your
behalf.
</template>
<template #form>
<!-- Token Name -->
<Field class="col-span-6 sm:col-span-4">
<FieldLabel for="name">Name</FieldLabel>
<TextInput
id="name"
v-model="createApiTokenForm.name"
type="text"
class="block w-full"
autofocus />
<FieldError v-if="createApiTokenForm.errors.name">{{
createApiTokenForm.errors.name
}}</FieldError>
</Field>
<!-- Token Permissions -->
<div v-if="availablePermissions.length > 0" class="col-span-6">
<FieldLabel for="permissions">Permissions</FieldLabel>
<div class="mt-2 grid grid-cols-1 md:grid-cols-2 gap-4">
<div v-for="permission in availablePermissions" :key="permission">
<label class="flex items-center">
<Checkbox
v-model:checked="createApiTokenForm.permissions"
:value="permission" />
<span class="ms-2 text-sm text-text-secondary">{{
permission
}}</span>
</label>
</div>
</div>
</div>
</template>
<template #actions>
<ActionMessage :on="createApiTokenForm.recentlySuccessful" class="me-3">
Created.
</ActionMessage>
<PrimaryButton
:class="{ 'opacity-25': createApiTokenForm.processing }"
:disabled="createApiTokenForm.processing">
Create
</PrimaryButton>
</template>
</FormSection>
<div v-if="tokens.length > 0">
<SectionBorder />
<!-- Manage API Tokens -->
<div class="mt-10 sm:mt-0">
<ActionSection>
<template #title> Manage API Tokens </template>
<template #description>
You may delete any of your existing tokens if they are no longer needed.
</template>
<!-- API Token List -->
<template #content>
<div class="space-y-6">
<div
v-for="token in tokens"
:key="token.id"
class="flex items-center justify-between">
<div class="break-all text-text-primary">
{{ token.name }}
</div>
<div class="flex items-center ms-2">
<div v-if="token.last_used_ago" class="text-sm text-gray-400">
Last used {{ token.last_used_ago }}
</div>
<button
v-if="availablePermissions.length > 0"
class="cursor-pointer ms-6 text-sm text-gray-400 underline"
@click="manageApiTokenPermissions(token)">
Permissions
</button>
<button
class="cursor-pointer ms-6 text-sm text-red-500"
@click="confirmApiTokenDeletion(token)">
Delete
</button>
</div>
</div>
</div>
</template>
</ActionSection>
</div>
</div>
<!-- Token Value Modal -->
<DialogModal :show="displayingToken" @close="displayingToken = false">
<template #title> API Token </template>
<template #content>
<div>
Please copy your new API token. For your security, it won't be shown again.
</div>
<div
v-if="page.props.jetstream.flash.token"
class="mt-4 bg-card-backgroundpx-4 py-2 rounded font-mono text-sm text-gray-500 break-all">
{{ page.props.jetstream.flash.token }}
</div>
</template>
<template #footer>
<SecondaryButton @click="displayingToken = false"> Close </SecondaryButton>
</template>
</DialogModal>
<!-- API Token Permissions Modal -->
<DialogModal :show="managingPermissionsFor != null" @close="managingPermissionsFor = null">
<template #title> API Token Permissions </template>
<template #content>
<div class="grid grid-cols-1 md:grid-cols-2 gap-4">
<div v-for="permission in availablePermissions" :key="permission">
<label class="flex items-center">
<Checkbox
v-model:checked="updateApiTokenForm.permissions"
:value="permission" />
<span class="ms-2 text-sm text-muted">{{ permission }}</span>
</label>
</div>
</div>
</template>
<template #footer>
<SecondaryButton @click="managingPermissionsFor = null"> Cancel </SecondaryButton>
<PrimaryButton
class="ms-3"
:class="{ 'opacity-25': updateApiTokenForm.processing }"
:disabled="updateApiTokenForm.processing"
@click="updateApiToken">
Save
</PrimaryButton>
</template>
</DialogModal>
<!-- Delete Token Confirmation Modal -->
<ConfirmationModal
:show="apiTokenBeingDeleted != null"
@close="apiTokenBeingDeleted = null">
<template #title> Delete API Token </template>
<template #content> Are you sure you would like to delete this API token? </template>
<template #footer>
<SecondaryButton @click="apiTokenBeingDeleted = null"> Cancel </SecondaryButton>
<DangerButton
class="ms-3"
:class="{ 'opacity-25': deleteApiTokenForm.processing }"
:disabled="deleteApiTokenForm.processing"
@click="deleteApiToken">
Delete
</DangerButton>
</template>
</ConfirmationModal>
</div>
</template>

View File

@@ -30,9 +30,6 @@ const page = usePage<{
terms_url: string | null;
privacy_policy_url: string | null;
newsletter_consent: boolean;
jetstream: {
hasTermsAndPrivacyPolicyFeature: boolean;
};
flash: {
message: string;
};
@@ -117,11 +114,7 @@ const page = usePage<{
</Field>
<div
v-if="
page.props.jetstream.hasTermsAndPrivacyPolicyFeature &&
page.props.terms_url !== null &&
page.props.privacy_policy_url !== null
"
v-if="page.props.terms_url !== null && page.props.privacy_policy_url !== null"
class="mt-4">
<Field orientation="horizontal">
<Checkbox id="terms" v-model:checked="form.terms" name="terms" />

View File

@@ -176,7 +176,6 @@ onBeforeUnmount(() => {
});
const page = usePage<{
jetstream: { managesProfilePhotos: boolean };
timezones: Record<string, string>;
weekdays: Record<string, string>;
}>();
@@ -192,7 +191,7 @@ const page = usePage<{
<template #form>
<!-- Profile Photo -->
<div v-if="page.props.jetstream.managesProfilePhotos" class="col-span-6 sm:col-span-4">
<div class="col-span-6 sm:col-span-4">
<input
id="photo"
ref="photoInput"

View File

@@ -6,8 +6,6 @@ import SectionBorder from '@/Components/SectionBorder.vue';
import TwoFactorAuthenticationForm from '@/Pages/Profile/Partials/TwoFactorAuthenticationForm.vue';
import UpdatePasswordForm from '@/Pages/Profile/Partials/UpdatePasswordForm.vue';
import UpdateProfileInformationForm from '@/Pages/Profile/Partials/UpdateProfileInformationForm.vue';
import { usePage } from '@inertiajs/vue3';
import type { User } from '@/types/models';
import type { Session } from '@/types/jetstream';
import ApiTokensForm from '@/Pages/Profile/Partials/ApiTokensForm.vue';
import ThemeForm from '@/Pages/Profile/Partials/ThemeForm.vue';
@@ -16,18 +14,6 @@ defineProps<{
confirmsTwoFactorAuthentication: boolean;
sessions: Session[];
}>();
const page = usePage<{
jetstream: {
canUpdateProfileInformation: boolean;
canUpdatePassword: boolean;
canManageTwoFactorAuthentication: boolean;
hasAccountDeletionFeatures: boolean;
};
auth: {
user: User;
};
}>();
</script>
<template>
@@ -38,7 +24,7 @@ const page = usePage<{
<div>
<div class="max-w-7xl mx-auto py-10 sm:px-6 lg:px-8">
<div v-if="page.props.jetstream.canUpdateProfileInformation">
<div>
<UpdateProfileInformationForm />
<SectionBorder />
@@ -50,13 +36,13 @@ const page = usePage<{
<SectionBorder />
</div>
<div v-if="page.props.jetstream.canUpdatePassword">
<div>
<UpdatePasswordForm class="mt-10 sm:mt-0" />
<SectionBorder />
</div>
<div v-if="page.props.jetstream.canManageTwoFactorAuthentication">
<div>
<TwoFactorAuthenticationForm
:requires-confirmation="confirmsTwoFactorAuthentication"
class="mt-10 sm:mt-0" />
@@ -69,11 +55,9 @@ const page = usePage<{
<ApiTokensForm></ApiTokensForm>
<template v-if="page.props.jetstream.hasAccountDeletionFeatures">
<SectionBorder />
<SectionBorder />
<DeleteUserForm class="mt-10 sm:mt-0" />
</template>
<DeleteUserForm class="mt-10 sm:mt-0" />
</div>
</div>
</AppLayout>

View File

@@ -9,9 +9,6 @@ declare global {
created_at: Date;
updated_at: Date;
};
jetstream: {
[key: string]: boolean;
};
errorBags: unknown;
errors: unknown;
}

View File

@@ -33,10 +33,3 @@ export interface Role {
export type JetstreamUser = User & {
two_factor_enabled: boolean;
};
export interface Token {
name: string;
token: string;
abilities: string[];
id: string;
last_used_ago: string;
}