Files
api/web/components/ConnectSettings/ConnectSettings.ce.vue
Eli Bosley 345e83bfb0 feat: upgrade nuxt-custom-elements (#1461)
<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## Summary by CodeRabbit

* **New Features**
* Added new modal dialogs and UI components, including activation steps,
OS update feedback, and expanded notification management.
* Introduced a plugin to configure internationalization, state
management, and Apollo client support in web components.
* Added a new Log Viewer page with a streamlined interface for viewing
logs.

* **Improvements**
* Centralized Pinia state management by consolidating all stores to use
a shared global Pinia instance.
* Simplified component templates by removing redundant
internationalization host wrappers.
* Enhanced ESLint configuration with stricter rules and global variable
declarations.
* Refined custom element build process to prevent jQuery conflicts and
optimize minification.
* Updated component imports and templates for consistent structure and
maintainability.
* Streamlined log viewer dropdowns using simplified select components
with improved formatting.
* Improved notification sidebar with filtering by importance and modular
components.
* Replaced legacy notification popups with new UI components and added
automatic root session creation for localhost requests.
* Updated OS version display and user profile UI with refined styling
and component usage.

* **Bug Fixes**
* Fixed component tag capitalization and improved type annotations
across components.

* **Chores**
* Updated development dependencies including ESLint plugins and build
tools.
* Removed deprecated log viewer patch class and cleaned up related test
fixtures.
  * Removed unused imports and simplified Apollo client setup.
* Cleaned up test mocks and removed obsolete i18n host component tests.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->

---
- To see the specific tasks where the Asana app for GitHub is being
used, see below:
  - https://app.asana.com/0/0/1210730229632804

---------

Co-authored-by: Pujit Mehrotra <pujit@lime-technology.com>
Co-authored-by: Zack Spear <zackspear@users.noreply.github.com>
2025-07-08 10:05:39 -04:00

159 lines
4.7 KiB
Vue

<script lang="ts" setup>
// import { useI18n } from 'vue-i18n';
// const { t } = useI18n();
import { ref, computed, watch } from 'vue';
import { storeToRefs } from 'pinia';
import { watchDebounced } from '@vueuse/core';
import { useMutation, useQuery } from '@vue/apollo-composable';
import { BrandButton, jsonFormsRenderers, Label } from '@unraid/ui';
import { JsonForms } from '@jsonforms/vue';
import { useServerStore } from '~/store/server';
// unified settings values are returned as JSON, so use a generic record type
// import type { ConnectSettingsValues } from '~/composables/gql/graphql';
import { getConnectSettingsForm, updateConnectSettings } from './graphql/settings.query';
const { connectPluginInstalled } = storeToRefs(useServerStore());
/**--------------------------------------------
* Settings State & Form definition
*---------------------------------------------**/
const formState = ref<Record<string, unknown>>({});
const { result, refetch } = useQuery(getConnectSettingsForm);
const settings = computed(() => {
if (!result.value) return;
return result.value.settings.unified;
});
watch(result, () => {
if (!result.value) return;
// unified values are namespaced (e.g., { api: { ... } })
formState.value = structuredClone(result.value.settings.unified.values ?? {});
});
const restartRequired = computed(() => {
interface SandboxValues {
api?: {
sandbox?: boolean;
};
}
const currentSandbox = (settings.value?.values as SandboxValues)?.api?.sandbox;
const updatedSandbox = (formState.value as SandboxValues)?.api?.sandbox;
return currentSandbox !== updatedSandbox;
});
/**--------------------------------------------
* Update Settings Actions
*---------------------------------------------**/
const {
mutate: mutateSettings,
loading: mutateSettingsLoading,
error: mutateSettingsError,
onDone: onMutateSettingsDone,
} = useMutation(updateConnectSettings);
const isUpdating = ref(false);
// prevent ui flash if loading finishes too fast
watchDebounced(
mutateSettingsLoading,
(loading) => {
isUpdating.value = loading;
},
{
debounce: 100,
}
);
// show a toast when the update is done
onMutateSettingsDone(() => {
globalThis.toast.success('Updated API Settings', {
description: restartRequired.value ? 'The API is restarting...' : undefined,
});
});
/**--------------------------------------------
* Form Config & Actions
*---------------------------------------------**/
const jsonFormsConfig = {
restrict: false,
trim: false,
};
const renderers = [...jsonFormsRenderers];
/** Called when the user clicks the "Apply" button */
const submitSettingsUpdate = async () => {
console.log('[ConnectSettings] trying to update settings to', formState.value);
await mutateSettings({ input: formState.value });
await refetch();
};
/** Called whenever a JSONForms form control changes */
const onChange = ({ data }: { data: Record<string, unknown> }) => {
formState.value = data;
};
</script>
<template>
<!-- common api-related actions -->
<div
class="grid grid-cols-settings items-baseline pl-3 gap-y-6 [&>*:nth-child(odd)]:text-end [&>*:nth-child(even)]:ml-10"
>
<template v-if="connectPluginInstalled">
<Label>Account Status:</Label>
<div v-html="'<unraid-auth></unraid-auth>'"></div>
</template>
<Label>Download Unraid API Logs:</Label>
<div
v-html="
'<unraid-download-api-logs></unraid-download-api-logs>'
"
></div>
</div>
<!-- auto-generated settings form -->
<div class="mt-6 pl-3 [&_.vertical-layout]:space-y-6">
<JsonForms
v-if="settings"
:schema="settings.dataSchema"
:uischema="settings.uiSchema"
:renderers="renderers"
:data="formState"
:config="jsonFormsConfig"
:readonly="isUpdating"
@change="onChange"
/>
<!-- form submission & fallback reaction message -->
<div class="mt-6 grid grid-cols-settings gap-y-6 items-baseline">
<div class="text-sm text-end">
<p v-if="isUpdating">Applying Settings...</p>
<p v-else-if="restartRequired">The API will restart after settings are applied.</p>
</div>
<div class="col-start-2 ml-10 space-y-4">
<BrandButton
variant="outline-primary"
padding="lean"
size="12px"
class="leading-normal"
@click="submitSettingsUpdate"
>
Apply
</BrandButton>
<p v-if="mutateSettingsError" class="text-sm text-unraid-red-500">
✕ Error: {{ mutateSettingsError.message }}
</p>
</div>
</div>
</div>
</template>
<style lang="postcss">
/* Import unraid-ui globals first */
@import '@unraid/ui/styles';
@import '../../assets/main.css';
</style>