Files
api/web/components/ApiKey/PermissionCounter.vue
Eli Bosley 674323fd87 feat: generated UI API key management + OAuth-like API Key Flows (#1609)
<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## Summary by CodeRabbit

* **New Features**
* API Key Authorization flow with consent screen, callback support, and
a Tools page.
* Schema-driven API Key creation UI with permission presets, templates,
and Developer Authorization Link.
* Effective Permissions preview and a new multi-select permission
control.

* **UI Improvements**
* Mask/toggle API keys, copy-to-clipboard with toasts, improved select
labels, new label styles, tab wrapping, and accordionized color
controls.

* **Documentation**
  * Public guide for the API Key authorization flow and scopes added.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->
2025-08-27 12:37:39 -04:00

61 lines
1.6 KiB
Vue

<script setup lang="ts">
import { computed } from 'vue';
import { Badge } from '@unraid/ui';
import { actionVariant } from './actionVariant.js';
import type { AuthAction } from '~/composables/gql/graphql';
const props = withDefaults(
defineProps<{
permissions: { resource: string; actions: AuthAction[] }[];
possiblePermissions?: { resource: string; actions: AuthAction[] }[];
hideNumber?: boolean;
label?: string;
}>(),
{
label: '',
possiblePermissions: () => [],
hideNumber: false,
}
);
const possibleActions = computed(() => {
if (!props.possiblePermissions) return [];
return Array.from(new Set(props.possiblePermissions.flatMap((p) => p.actions)));
});
const actionCounts = computed(() => {
const actions = possibleActions.value;
const counts: Record<string, number> = {};
for (const action of actions) {
counts[action] = props.permissions.reduce(
(sum, perm) => sum + perm.actions.filter((a) => a === action).length,
0
);
}
return counts;
});
const filteredActions = computed(() => {
return possibleActions.value.filter((action) => actionCounts.value[action] > 0);
});
</script>
<template>
<div class="flex flex-row items-center gap-1">
<span v-if="label">{{ label }}</span>
<template v-if="possibleActions.length">
<Badge
v-for="action in filteredActions"
:key="action"
:variant="actionVariant(action)"
class="text-xs text-muted-foreground"
>
<span v-if="!hideNumber">{{ action }}: {{ actionCounts[action] || 0 }}</span>
<span v-else>{{ action }}</span>
</Badge>
</template>
</div>
</template>