mirror of
https://github.com/unraid/api.git
synced 2025-12-30 04:59:51 -06:00
<!-- This is an auto-generated comment: release notes by coderabbit.ai --> ## Summary by CodeRabbit * **New Features** * Added developer CLI tools for toggling GraphQL sandbox and modal testing utilities. * Introduced a "Show Activation Modal" developer component for UI testing. * Added system initial setup detection and related GraphQL queries. * Enhanced login and welcome pages with dynamic server info and initial setup state. * Improved SSO button with internationalization and error handling. * Added internal CLI admin API key management service and internal GraphQL client service. * Introduced comprehensive API report generation service for system and service status. * Added CLI commands and GraphQL mutations/queries for plugin and SSO user management. * Added new modal target components and improved teleport target detection. * **Enhancements** * Refined modal dialog targeting and teleportation for flexible UI placement. * Updated modal components and stores for improved activation/welcome modal control. * Improved plugin and SSO user management via CLI through GraphQL API. * Refactored partner logo components to use props instead of store dependencies. * Enhanced styling and accessibility for buttons and modals. * Streamlined Tailwind CSS integration with shared styles and updated theme variables. * Improved GraphQL module configuration to avoid directive conflicts in tests. * Adjusted Vite config for better dependency handling in test mode. * Improved error handling and logging in CLI commands and services. * Reordered imports and refined component class bindings for UI consistency. * **Bug Fixes** * Resolved issues with duplicate script tags and component registration in the web UI. * Fixed modal close button visibility and activation modal state handling. * Added error handling and logging improvements across CLI commands and services. * Fixed newline issues in last-download-time fixture files. * **Chores** * Added and updated numerous tests for CLI commands, services, and UI components. * Updated translation files and localization resources for new UI messages. * Adjusted environment, configuration, and dependency files for improved development and test workflows. * Cleaned up unused imports and mocks in tests. * Reorganized exports and barrel files in shared and UI modules. * Added integration and dependency resolution tests for core modules. * **Removals & Refactoring** * Removed legacy Redux state management, configuration, and UPnP logic from the backend. * Eliminated deprecated GraphQL subscriptions and client code related to registration and mothership. * Removed direct store manipulation and replaced with service-based approaches in CLI commands. * Deleted unused or redundant test files and configuration listeners. * Refactored SSO user service to consolidate add/remove operations into a single update method. * Simplified API key services with new methods for automatic key management. * Replaced direct plugin and SSO user service calls with GraphQL client interactions in CLI commands. * Removed complex theme fallback and dark mode CSS rules, replacing with streamlined static theme variables. * Cleaned up Tailwind CSS configuration and removed deprecated local styles. * Removed multiple internal utility files and replaced with simplified or centralized implementations. * Removed deprecated local configuration and synchronization files and listeners. * Removed UPnP helper functions and job management classes. * Refactored server resolver to dynamically construct local server data internally. * Removed CORS handler and replaced with simplified or externalized logic. * Removed store synchronization and registration event pubsub handling. * Removed GraphQL client creation utilities for internal API communication. <!-- end of auto-generated comment: release notes by coderabbit.ai -->
164 lines
5.4 KiB
Vue
164 lines
5.4 KiB
Vue
<script lang="ts" setup>
|
|
import { onBeforeMount, onMounted, ref, watch } from 'vue';
|
|
import { useI18n } from 'vue-i18n';
|
|
import { storeToRefs } from 'pinia';
|
|
import { useClipboard } from '@vueuse/core';
|
|
|
|
import { cn, DropdownMenu } from '@unraid/ui';
|
|
import { devConfig } from '~/helpers/env';
|
|
|
|
import type { Server } from '~/types/server';
|
|
|
|
import NotificationsSidebar from '~/components/Notifications/Sidebar.vue';
|
|
import UpcDropdownContent from '~/components/UserProfile/DropdownContent.vue';
|
|
import UpcDropdownTrigger from '~/components/UserProfile/DropdownTrigger.vue';
|
|
import UpcServerState from '~/components/UserProfile/ServerState.vue';
|
|
// Auto-imported components - now manually imported
|
|
import UpcUptimeExpire from '~/components/UserProfile/UptimeExpire.vue';
|
|
import { useCallbackActionsStore } from '~/store/callbackActions';
|
|
import { useServerStore } from '~/store/server';
|
|
import { useThemeStore } from '~/store/theme';
|
|
|
|
export interface Props {
|
|
server?: Server | string;
|
|
}
|
|
const props = defineProps<Props>();
|
|
|
|
const { t } = useI18n();
|
|
|
|
const callbackStore = useCallbackActionsStore();
|
|
const serverStore = useServerStore();
|
|
|
|
const { callbackData } = storeToRefs(callbackStore);
|
|
const { name, description, guid, keyfile, lanIp } = storeToRefs(serverStore);
|
|
const { bannerGradient, theme } = storeToRefs(useThemeStore());
|
|
|
|
/**
|
|
* Copy LAN IP on server name click
|
|
*/
|
|
let copyIpInterval: string | number | NodeJS.Timeout | undefined;
|
|
const { copy, copied, isSupported } = useClipboard({ source: lanIp.value ?? '' });
|
|
const showCopyNotSupported = ref<boolean>(false);
|
|
const copyLanIp = () => {
|
|
// if http then clipboard is not supported
|
|
if (!isSupported || window.location.protocol === 'http:') {
|
|
showCopyNotSupported.value = true;
|
|
return;
|
|
}
|
|
copy(lanIp.value ?? '');
|
|
};
|
|
watch(showCopyNotSupported, (newVal, oldVal) => {
|
|
if (newVal && oldVal === false) {
|
|
clearTimeout(copyIpInterval);
|
|
copyIpInterval = setTimeout(() => {
|
|
showCopyNotSupported.value = false;
|
|
}, 5000);
|
|
}
|
|
});
|
|
|
|
/**
|
|
* Sets the server store and locale messages then listen for callbacks
|
|
*/
|
|
onBeforeMount(() => {
|
|
if (!props.server) {
|
|
throw new Error('Server data not present');
|
|
}
|
|
|
|
if (typeof props.server === 'object') {
|
|
// Handles the testing dev Vue component
|
|
serverStore.setServer(props.server);
|
|
} else if (typeof props.server === 'string') {
|
|
// Handle web component
|
|
const parsedServerProp = JSON.parse(props.server);
|
|
serverStore.setServer(parsedServerProp);
|
|
}
|
|
|
|
// look for any callback params
|
|
callbackStore.watcher();
|
|
|
|
if (guid.value && keyfile.value) {
|
|
if (callbackData.value) {
|
|
return console.debug(
|
|
'Renew callback detected, skipping auto check for key replacement, renewal eligibility, and OS Update.'
|
|
);
|
|
}
|
|
} else {
|
|
console.warn(
|
|
'A valid keyfile and USB Flash boot device are required to check for key renewals, key replacement eligibiliy, and OS update availability.'
|
|
);
|
|
}
|
|
});
|
|
|
|
onMounted(() => {
|
|
if (devConfig.VITE_MOCK_USER_SESSION && devConfig.NODE_ENV === 'development') {
|
|
document.cookie = 'unraid_session_cookie=mockusersession';
|
|
}
|
|
});
|
|
</script>
|
|
|
|
<template>
|
|
<div id="UserProfile" class="text-foreground relative z-20 flex flex-col h-full gap-y-1 pt-2 pr-2">
|
|
<div
|
|
v-if="bannerGradient"
|
|
class="absolute z-0 w-full top-0 bottom-0 right-0"
|
|
:style="bannerGradient"
|
|
/>
|
|
|
|
<div
|
|
:class="
|
|
cn(
|
|
'text-xs text-header-text-secondary text-right font-semibold leading-normal relative z-10 flex flex-wrap xs:flex-row items-baseline justify-end gap-x-1 xs:gap-x-4'
|
|
)
|
|
"
|
|
>
|
|
<UpcUptimeExpire :as="'span'" :t="t" class="text-xs" />
|
|
<span class="hidden xs:block">•</span>
|
|
<UpcServerState :t="t" class="text-xs" />
|
|
</div>
|
|
|
|
<div class="relative z-10 flex flex-row items-center justify-end gap-x-4 h-full">
|
|
<h1
|
|
class="text-md sm:text-lg relative flex flex-col-reverse items-end md:flex-row border-0 text-header-text-primary"
|
|
>
|
|
<template v-if="description && theme?.descriptionShow">
|
|
<span class="text-right text-xs sm:text-lg hidden md:inline-block" v-html="description" />
|
|
<span class="text-header-text-secondary hidden md:inline-block px-2">•</span>
|
|
</template>
|
|
<button
|
|
v-if="lanIp"
|
|
:title="t('Click to Copy LAN IP {0}', [lanIp])"
|
|
class="text-header-text-primary opacity-100 hover:opacity-75 focus:opacity-75 transition-opacity"
|
|
@click="copyLanIp()"
|
|
>
|
|
{{ name }}
|
|
</button>
|
|
<span v-else class="text-header-text-primary">
|
|
{{ name }}
|
|
</span>
|
|
<span
|
|
v-show="copied || showCopyNotSupported"
|
|
class="text-white text-xs leading-none py-1 px-2 absolute top-full right-0 bg-linear-to-r from-unraid-red to-orange text-center block rounded"
|
|
>
|
|
<template v-if="copied">{{ t('LAN IP Copied') }}</template>
|
|
<template v-else>{{ t('LAN IP {0}', [lanIp]) }}</template>
|
|
</span>
|
|
</h1>
|
|
|
|
<div class="block w-[2px] h-6 bg-header-text-secondary" />
|
|
|
|
<NotificationsSidebar />
|
|
|
|
<DropdownMenu align="end" side="bottom" :side-offset="4">
|
|
<template #trigger>
|
|
<UpcDropdownTrigger :t="t" />
|
|
</template>
|
|
<template #content>
|
|
<div class="max-w-[350px] sm:min-w-[350px]">
|
|
<UpcDropdownContent :t="t" />
|
|
</div>
|
|
</template>
|
|
</DropdownMenu>
|
|
</div>
|
|
</div>
|
|
</template>
|