mirror of
https://github.com/Drop-OSS/drop.git
synced 2025-11-09 20:12:10 +10:00
* fix: release workflow * feat: move mostly to internal tasks system * feat: migrate object clean to new task system * fix: release not getting good base version * chore: set version v0.3.0 * chore: style * feat: basic task concurrency * feat: temp pages to fill in page links * feat: inital i18n support * feat: localize store page * chore: style * fix: weblate doesn't like multifile thing * fix: update nuxt * feat: improved error logging * fix: using old task api * feat: basic translation docs * feat: add i18n eslint plugin * feat: translate store and auth pages * feat: more translation progress * feat: admin dash i18n progress * feat: enable update check by default in prod * fix: using wrong i18n keys * fix: crash in library sources page * feat: finish i18n work * fix: missing i18n translations * feat: use twemoji for emojis * feat: sanatize object ids * fix: EmojiText's alt text * fix: UserWidget not using links * feat: cache and auth for emoji api * fix: add more missing translations
150 lines
5.2 KiB
Vue
150 lines
5.2 KiB
Vue
<template>
|
|
<div>
|
|
<div class="mx-auto max-w-2xl lg:mx-0">
|
|
<h2
|
|
class="mt-2 text-xl font-semibold tracking-tight text-zinc-100 sm:text-3xl"
|
|
>
|
|
{{ $t("account.devices.title") }}
|
|
</h2>
|
|
<p
|
|
class="mt-2 text-pretty text-sm font-medium text-zinc-400 sm:text-md/8"
|
|
>
|
|
{{ $t("account.devices.subheader") }}
|
|
</p>
|
|
</div>
|
|
|
|
<div
|
|
class="mt-8 overflow-hidden rounded-xl border border-zinc-800 bg-zinc-900 shadow-sm"
|
|
>
|
|
<div class="overflow-x-auto">
|
|
<table class="min-w-full divide-y divide-zinc-800">
|
|
<thead>
|
|
<tr class="bg-zinc-800/50">
|
|
<th
|
|
scope="col"
|
|
class="py-3.5 pl-4 pr-3 text-left text-sm font-semibold text-zinc-100 sm:pl-6"
|
|
>
|
|
{{ $t("name") }}
|
|
</th>
|
|
<th
|
|
scope="col"
|
|
class="px-3 py-3.5 text-left text-sm font-semibold text-zinc-100"
|
|
>
|
|
{{ $t("account.devices.platform") }}
|
|
</th>
|
|
<th
|
|
scope="col"
|
|
class="px-3 py-3.5 text-left text-sm font-semibold text-zinc-100"
|
|
>
|
|
{{ $t("account.devices.capabilities") }}
|
|
</th>
|
|
<th
|
|
scope="col"
|
|
class="px-3 py-3.5 text-left text-sm font-semibold text-zinc-100"
|
|
>
|
|
{{ $t("account.devices.lastConnected") }}
|
|
</th>
|
|
<th scope="col" class="relative py-3.5 pl-3 pr-4 sm:pr-6">
|
|
<span class="sr-only">{{ $t("actions") }}</span>
|
|
</th>
|
|
</tr>
|
|
</thead>
|
|
<tbody class="divide-y divide-zinc-800">
|
|
<tr
|
|
v-for="client in clients"
|
|
:key="client.id"
|
|
class="transition-colors duration-150 hover:bg-zinc-800/50"
|
|
>
|
|
<td
|
|
class="whitespace-nowrap py-4 pl-4 pr-3 text-sm font-medium text-zinc-100 sm:pl-6"
|
|
>
|
|
{{ client.name }}
|
|
</td>
|
|
<td class="whitespace-nowrap px-3 py-4 text-sm text-zinc-400">
|
|
<span
|
|
class="inline-flex items-center rounded-md bg-zinc-400/10 px-2 py-1 text-xs font-medium text-zinc-400 ring-1 ring-inset ring-zinc-400/20"
|
|
>
|
|
{{ client.platform }}
|
|
</span>
|
|
</td>
|
|
<td class="whitespace-nowrap px-3 py-4 text-sm text-zinc-400">
|
|
<div class="flex flex-wrap gap-2">
|
|
<span
|
|
v-for="capability in client.capabilities"
|
|
:key="capability"
|
|
class="inline-flex items-center gap-x-1 rounded-md bg-blue-400/10 px-2 py-1 text-xs font-medium text-blue-400 ring-1 ring-inset ring-blue-400/20"
|
|
>
|
|
<CheckIcon class="size-3" />
|
|
{{ capability }}
|
|
</span>
|
|
</div>
|
|
</td>
|
|
<td class="whitespace-nowrap px-3 py-4 text-sm text-zinc-400">
|
|
<RelativeTime :date="client.lastConnected" />
|
|
</td>
|
|
<td
|
|
class="relative whitespace-nowrap py-4 pl-3 pr-4 text-right text-sm font-medium sm:pr-6"
|
|
>
|
|
<button
|
|
class="inline-flex items-center rounded-md bg-red-400/10 px-2 py-1 text-xs font-medium text-red-400 ring-1 ring-inset ring-red-400/20 transition-all duration-200 hover:bg-red-400/20 hover:scale-105 active:scale-95"
|
|
@click="() => revokeClientWrapper(client.id)"
|
|
>
|
|
{{ $t("account.devices.revoke") }}
|
|
<span class="sr-only">
|
|
{{ $t("chars.srComma", [client.name]) }}
|
|
</span>
|
|
</button>
|
|
</td>
|
|
</tr>
|
|
<tr v-if="clients.length === 0">
|
|
<td colspan="5" class="py-8 text-center text-sm text-zinc-400">
|
|
{{ $t("account.devices.noDevices") }}
|
|
</td>
|
|
</tr>
|
|
</tbody>
|
|
</table>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</template>
|
|
|
|
<script setup lang="ts">
|
|
import { CheckIcon } from "@heroicons/vue/24/outline";
|
|
|
|
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
|
// @ts-ignore pending https://github.com/nitrojs/nitro/issues/2758
|
|
const clients = ref(await $dropFetch("/api/v1/user/client"));
|
|
const { t } = useI18n();
|
|
|
|
async function revokeClient(id: string) {
|
|
await $dropFetch(`/api/v1/user/client/${id}`, { method: "DELETE" });
|
|
}
|
|
|
|
// clients.value.push({
|
|
// id: "example-client",
|
|
// userId: "example-user",
|
|
// name: "Example Client",
|
|
// platform: "Windows",
|
|
// capabilities: ["TrackPlaytime"],
|
|
// lastConnected: new Date().toISOString(),
|
|
// });
|
|
|
|
function revokeClientWrapper(id: string) {
|
|
revokeClient(id)
|
|
.then(() => {
|
|
const index = clients.value.findIndex((e) => e.id == id);
|
|
clients.value.splice(index, 1);
|
|
})
|
|
.catch((e) => {
|
|
createModal(
|
|
ModalType.Notification,
|
|
{
|
|
title: t("errors.revokeClient"),
|
|
description: t("errors.revokeClientFull", String(e)),
|
|
},
|
|
(_, c) => c(),
|
|
);
|
|
});
|
|
}
|
|
</script>
|