mirror of
https://github.com/unraid/api.git
synced 2026-01-01 22:20:05 -06:00
refactor: WIP on downgrade and UI / UX
This commit is contained in:
@@ -43,32 +43,32 @@ const testOsReleasesResponse: OsReleasesResponse = {
|
||||
}
|
||||
],
|
||||
"stable": [
|
||||
// {
|
||||
// "version": "6.12.5",
|
||||
// "name": "Unraid Server 6.12.5",
|
||||
// "basefile": "unRAIDServer-6.12.5-x86_64.zip",
|
||||
// "date": "2023-08-31",
|
||||
// "url": "https://dl.stable.unraid.net/unRAIDServer-6.12.5-x86_64.zip",
|
||||
// "changelog": "https://unraid.net/blog/unraid-os-6.12.5-release-notes",
|
||||
// "md5": "FAKEbddcf415f2d0518804e551c16125",
|
||||
// "size": 12345122,
|
||||
// "sha256": "fda177bb1336270b24e4df0fd0c1dd0596c44699204f57c83ce70a0f19173be4",
|
||||
// "plugin_url": "https://dl.stable.unraid.net/unRAIDServer-6.12.5.plg",
|
||||
// "plugin_sha256": "83850536ed6982bd582ed107d977d59e9b9b786363e698b14d1daf52e2dec2d9"
|
||||
// },
|
||||
// {
|
||||
// "version": "6.12.4",
|
||||
// "name": "Unraid Server 6.12.4",
|
||||
// "basefile": "unRAIDServer-6.12.4-x86_64.zip",
|
||||
// "date": "2023-08-31",
|
||||
// "url": "https://dl.stable.unraid.net/unRAIDServer-6.12.4-x86_64.zip",
|
||||
// "changelog": "https://unraid.net/blog/unraid-os-6.12.4-release-notes",
|
||||
// "md5": "9050bddcf415f2d0518804e551c1be98",
|
||||
// "size": 12345122,
|
||||
// "sha256": "fda177bb1336270b24e4df0fd0c1dd0596c44699204f57c83ce70a0f19173be4",
|
||||
// "plugin_url": "https://dl.stable.unraid.net/unRAIDServer-6.12.4.plg",
|
||||
// "plugin_sha256": "83850536ed6982bd582ed107d977d59e9b9b786363e698b14d1daf52e2dec2d9"
|
||||
// },
|
||||
{
|
||||
"version": "6.12.5",
|
||||
"name": "Unraid Server 6.12.5",
|
||||
"basefile": "unRAIDServer-6.12.5-x86_64.zip",
|
||||
"date": "2023-08-31",
|
||||
"url": "https://dl.stable.unraid.net/unRAIDServer-6.12.5-x86_64.zip",
|
||||
"changelog": "https://unraid.net/blog/unraid-os-6.12.5-release-notes",
|
||||
"md5": "FAKEbddcf415f2d0518804e551c16125",
|
||||
"size": 12345122,
|
||||
"sha256": "fda177bb1336270b24e4df0fd0c1dd0596c44699204f57c83ce70a0f19173be4",
|
||||
"plugin_url": "https://dl.stable.unraid.net/unRAIDServer-6.12.5.plg",
|
||||
"plugin_sha256": "83850536ed6982bd582ed107d977d59e9b9b786363e698b14d1daf52e2dec2d9"
|
||||
},
|
||||
{
|
||||
"version": "6.12.4",
|
||||
"name": "Unraid Server 6.12.4",
|
||||
"basefile": "unRAIDServer-6.12.4-x86_64.zip",
|
||||
"date": "2023-08-31",
|
||||
"url": "https://dl.stable.unraid.net/unRAIDServer-6.12.4-x86_64.zip",
|
||||
"changelog": "https://unraid.net/blog/unraid-os-6.12.4-release-notes",
|
||||
"md5": "9050bddcf415f2d0518804e551c1be98",
|
||||
"size": 12345122,
|
||||
"sha256": "fda177bb1336270b24e4df0fd0c1dd0596c44699204f57c83ce70a0f19173be4",
|
||||
"plugin_url": "https://dl.stable.unraid.net/unRAIDServer-6.12.4.plg",
|
||||
"plugin_sha256": "83850536ed6982bd582ed107d977d59e9b9b786363e698b14d1daf52e2dec2d9"
|
||||
},
|
||||
{
|
||||
"version": "6.12.3",
|
||||
"name": "Unraid Server 6.12.3",
|
||||
|
||||
@@ -53,7 +53,7 @@ export const serverState: Server = {
|
||||
guid: randomGuid,
|
||||
// "guid": "0781-5583-8355-81071A2B0211",
|
||||
inIframe: false,
|
||||
keyfile: 'DUMMY_KEYFILE',
|
||||
// keyfile: 'DUMMY_KEYFILE',
|
||||
lanIp: '192.168.254.36',
|
||||
license: '',
|
||||
locale: 'en_US', // en_US, ja
|
||||
|
||||
71
web/components/HeaderOsVersion.ce.vue
Normal file
71
web/components/HeaderOsVersion.ce.vue
Normal file
@@ -0,0 +1,71 @@
|
||||
<script lang="ts" setup>
|
||||
import {
|
||||
BellAlertIcon,
|
||||
CheckCircleIcon,
|
||||
ExclamationTriangleIcon,
|
||||
InformationCircleIcon,
|
||||
} from '@heroicons/vue/24/solid';
|
||||
import { storeToRefs } from 'pinia';
|
||||
import { useI18n } from 'vue-i18n';
|
||||
|
||||
import 'tailwindcss/tailwind.css';
|
||||
import '~/assets/main.css';
|
||||
|
||||
import { useServerStore } from '~/store/server';
|
||||
import { useUpdateOsStore, useUpdateOsActionsStore } from '~/store/updateOsActions';
|
||||
|
||||
const { t } = useI18n();
|
||||
|
||||
const serverStore = useServerStore();
|
||||
const updateOsStore = useUpdateOsStore();
|
||||
const updateOsActionsStore = useUpdateOsActionsStore();
|
||||
|
||||
const { osVersion } = storeToRefs(serverStore);
|
||||
const { available, parsedReleaseTimestamp } = storeToRefs(updateOsStore);
|
||||
const { rebootType } = storeToRefs(updateOsActionsStore);
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div class="flex flex-row justify-center gap-x-8px">
|
||||
<button
|
||||
@click="updateOsActionsStore.viewCurrentReleaseNotes(t('{0} Release Notes', [osVersion]))"
|
||||
class="group"
|
||||
:title="t('View release notes')"
|
||||
>
|
||||
<UiBadge
|
||||
color="custom"
|
||||
:icon="InformationCircleIcon"
|
||||
icon-styles="text-gamma"
|
||||
size="12px"
|
||||
class="text-gamma group-hover:text-orange-dark group-focus:text-orange-dark group-hover:underline group-focus:underline"
|
||||
>
|
||||
{{ osVersion }}
|
||||
</UiBadge>
|
||||
</button>
|
||||
|
||||
<a href="/Tools/Update" class="group" :title="t('Go to Tools > Update')">
|
||||
<UiBadge
|
||||
v-if="available && rebootType === 'none'"
|
||||
color="orange"
|
||||
:icon="BellAlertIcon"
|
||||
size="12px"
|
||||
>
|
||||
{{ t('Update Available') }}
|
||||
</UiBadge>
|
||||
<UiBadge
|
||||
v-else-if="rebootType !== 'none'"
|
||||
:color="'yellow'"
|
||||
:icon="ExclamationTriangleIcon"
|
||||
size="12px"
|
||||
>
|
||||
{{ rebootType === 'downgrade' ? t('Reboot Required for Downgrade') : t('Reboot Required for Update') }}
|
||||
</UiBadge>
|
||||
</a>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<style lang="postcss">
|
||||
@tailwind base;
|
||||
@tailwind components;
|
||||
@tailwind utilities;
|
||||
</style>
|
||||
@@ -4,14 +4,16 @@ import BrandLoading from '~/components/Brand/Loading.vue';
|
||||
import BrandLoadingWhite from '~/components/Brand/LoadingWhite.vue';
|
||||
|
||||
const props = withDefaults(defineProps<{
|
||||
color?: 'gray' | 'red' | 'yellow' | 'green' | 'blue' | 'indigo' | 'purple' | 'pink' | 'orange' | 'black' | 'white' | 'transparent' | 'current';
|
||||
color?: 'alpha' | 'beta' | 'gamma' | 'gray' | 'red' | 'yellow' | 'green' | 'blue' | 'indigo' | 'purple' | 'pink' | 'orange' | 'black' | 'white' | 'transparent' | 'current' | 'custom';
|
||||
icon?: typeof XCircleIcon | typeof BrandLoading | typeof BrandLoadingWhite;
|
||||
iconRight?: typeof XCircleIcon | typeof BrandLoading | typeof BrandLoadingWhite;
|
||||
iconStyles?: string;
|
||||
size?: '12px' | '14px' | '16px' | '18px' | '20px' | '24px';
|
||||
}>(), {
|
||||
color: 'gray',
|
||||
icon: undefined,
|
||||
iconRight: undefined,
|
||||
iconStyles: '',
|
||||
size: '16px',
|
||||
});
|
||||
|
||||
@@ -20,6 +22,15 @@ const computedStyleClasses = computed(() => {
|
||||
let textSize = '';
|
||||
let iconSize = '';
|
||||
switch (props.color) {
|
||||
case 'alpha':
|
||||
colorClasses = 'bg-alpha text-white group-hover:opacity-75 group-focus:opacity-75';
|
||||
break;
|
||||
case 'beta':
|
||||
colorClasses = 'bg-beta text-white group-hover:opacity-75 group-focus:opacity-75';
|
||||
break;
|
||||
case 'gamma':
|
||||
colorClasses = 'bg-gamma text-white group-hover:opacity-75 group-focus:opacity-75';
|
||||
break;
|
||||
case 'red':
|
||||
colorClasses = 'bg-unraid-red text-white group-hover:bg-orange-dark group-focus:bg-orange-dark';
|
||||
break;
|
||||
@@ -27,7 +38,7 @@ const computedStyleClasses = computed(() => {
|
||||
colorClasses = 'bg-yellow-100 text-yellow-800 group-hover:bg-yellow-200 group-focus:bg-yellow-200';
|
||||
break;
|
||||
case 'green':
|
||||
colorClasses = 'bg-green-100 text-green-800 group-hover:bg-green-200 group-focus:bg-green-200';
|
||||
colorClasses = 'bg-green-200 text-green-800 group-hover:bg-green-300 group-focus:bg-green-300';
|
||||
break;
|
||||
case 'blue':
|
||||
colorClasses = 'bg-blue-100 text-blue-800 group-hover:bg-blue-200 group-focus:bg-blue-200';
|
||||
@@ -59,37 +70,40 @@ const computedStyleClasses = computed(() => {
|
||||
case 'gray':
|
||||
colorClasses = 'bg-gray-200 text-gray-800 group-hover:bg-gray-300 group-focus:bg-gray-300';
|
||||
break;
|
||||
case 'custom':
|
||||
colorClasses = '';
|
||||
break;
|
||||
}
|
||||
switch (props.size) {
|
||||
case '12px':
|
||||
textSize = 'text-12px px-8px py-4px';
|
||||
textSize = 'text-12px px-8px py-4px gap-4px';
|
||||
iconSize = 'w-12px';
|
||||
break;
|
||||
case '14px':
|
||||
textSize = 'text-14px px-8px py-4px';
|
||||
textSize = 'text-14px px-8px py-4px gap-8px';
|
||||
iconSize = 'w-14px';
|
||||
break;
|
||||
case '16px':
|
||||
textSize = 'text-16px px-12px py-8px';
|
||||
textSize = 'text-16px px-12px py-8px gap-8px';
|
||||
iconSize = 'w-16px';
|
||||
break;
|
||||
case '18px':
|
||||
textSize = 'text-18px px-12px py-8px';
|
||||
textSize = 'text-18px px-12px py-8px gap-8px';
|
||||
iconSize = 'w-18px';
|
||||
break;
|
||||
case '20px':
|
||||
textSize = 'text-20px px-16px py-12px';
|
||||
textSize = 'text-20px px-16px py-12px gap-8px';
|
||||
iconSize = 'w-20px';
|
||||
break;
|
||||
case '24px':
|
||||
textSize = 'text-24px px-16px py-12px';
|
||||
textSize = 'text-24px px-16px py-12px gap-8px';
|
||||
iconSize = 'w-24px';
|
||||
break;
|
||||
}
|
||||
|
||||
return {
|
||||
badge: `${textSize} ${colorClasses}`,
|
||||
icon: iconSize,
|
||||
icon: `${iconSize} ${props.iconStyles}`,
|
||||
};
|
||||
});
|
||||
</script>
|
||||
@@ -99,7 +113,6 @@ const computedStyleClasses = computed(() => {
|
||||
class="inline-flex items-center rounded-full font-semibold leading-none transition-all duration-200 ease-in-out"
|
||||
:class="[
|
||||
computedStyleClasses.badge,
|
||||
icon || iconRight ? 'gap-8px' : '',
|
||||
]"
|
||||
>
|
||||
<component :is="icon" v-if="icon" class="flex-shrink-0" :class="computedStyleClasses.icon" />
|
||||
|
||||
@@ -4,12 +4,9 @@
|
||||
* @todo require keyfile to update
|
||||
* @todo require valid guid / server state to update
|
||||
*/
|
||||
import dayjs, { extend } from 'dayjs';
|
||||
import relativeTime from 'dayjs/plugin/relativeTime';
|
||||
import { storeToRefs } from 'pinia';
|
||||
import { useI18n } from 'vue-i18n';
|
||||
|
||||
import { useUpdateOsStore } from '~/store/updateOsActions';
|
||||
import { useUpdateOsActionsStore } from '~/store/updateOsActions';
|
||||
|
||||
import 'tailwindcss/tailwind.css';
|
||||
import '~/assets/main.css';
|
||||
@@ -17,30 +14,31 @@ import '~/assets/main.css';
|
||||
const { t } = useI18n();
|
||||
|
||||
export interface Props {
|
||||
rebootType?: 'downgrade' | 'upgrade' | 'none';
|
||||
restoreVersion?: string;
|
||||
}
|
||||
withDefaults(defineProps<Props>(), {
|
||||
const props = withDefaults(defineProps<Props>(), {
|
||||
rebootType: 'none',
|
||||
restoreVersion: '',
|
||||
});
|
||||
|
||||
const updateOsStore = useUpdateOsStore();
|
||||
const { cachedReleasesTimestamp } = storeToRefs(updateOsStore);
|
||||
const updateOsActionsStore = useUpdateOsActionsStore();
|
||||
|
||||
extend(relativeTime);
|
||||
const parsedReleaseTimestamp = computed(() => {
|
||||
if (!cachedReleasesTimestamp.value) { return ''; }
|
||||
return {
|
||||
formatted: dayjs(cachedReleasesTimestamp.value).format('YYYY-MM-DD HH:mm:ss'),
|
||||
relative: dayjs().to(dayjs(cachedReleasesTimestamp.value)),
|
||||
};
|
||||
onBeforeMount(() => {
|
||||
updateOsActionsStore.setRebootType(props.rebootType);
|
||||
});
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div class="grid gap-y-24px max-w-1024px mx-auto">
|
||||
<UpdateOsStatus :release-check-time="parsedReleaseTimestamp" :t="t" />
|
||||
<UpdateOsUpdate :release-check-time="parsedReleaseTimestamp" :t="t" />
|
||||
<UpdateOsDowngrade v-if="restoreVersion" :version="restoreVersion" :t="t" />
|
||||
<UpdateOsStatus :t="t" />
|
||||
<UpdateOsUpdate
|
||||
v-if="rebootType === 'none'"
|
||||
:t="t" />
|
||||
<UpdateOsDowngrade
|
||||
v-if="restoreVersion && rebootType === 'none'"
|
||||
:version="restoreVersion"
|
||||
:t="t" />
|
||||
</div>
|
||||
</template>
|
||||
|
||||
|
||||
@@ -7,34 +7,27 @@
|
||||
*/
|
||||
import { Switch, SwitchGroup, SwitchLabel } from '@headlessui/vue';
|
||||
import { storeToRefs } from 'pinia';
|
||||
import { ref, watchEffect } from 'vue';
|
||||
import { ref } from 'vue';
|
||||
|
||||
import 'tailwindcss/tailwind.css';
|
||||
import '~/assets/main.css';
|
||||
|
||||
import { useServerStore } from '~/store/server';
|
||||
import { useUpdateOsStore, useUpdateOsActionsStore } from '~/store/updateOsActions';
|
||||
import type { UserProfileLink } from '~/types/userProfile';
|
||||
import { stat } from 'fs';
|
||||
import { useUpdateOsStore } from '~/store/updateOsActions';
|
||||
|
||||
const props = defineProps<{
|
||||
releaseCheckTime: {
|
||||
formatted: string;
|
||||
relative: string;
|
||||
};
|
||||
t: any;
|
||||
}>();
|
||||
|
||||
const serverStore = useServerStore();
|
||||
const updateOsStore = useUpdateOsStore();
|
||||
const updateOsActionsStore = useUpdateOsActionsStore();
|
||||
|
||||
const { guid, keyfile, osVersion } = storeToRefs(serverStore);
|
||||
const { available } = storeToRefs(updateOsStore);
|
||||
const { parsedReleaseTimestamp } = storeToRefs(updateOsStore);
|
||||
|
||||
const includeNext = ref(false);
|
||||
|
||||
const status = ref<'ready' | 'checking'>('ready');
|
||||
const status = ref<'ready' | 'checking' | 'ineligible'>('ready');
|
||||
|
||||
const buttonText = computed(() => {
|
||||
if (status.value === 'checking') {
|
||||
@@ -44,6 +37,10 @@ const buttonText = computed(() => {
|
||||
});
|
||||
|
||||
const check = async () => {
|
||||
if (status.value === 'ineligible') {
|
||||
return;
|
||||
}
|
||||
|
||||
status.value = 'checking';
|
||||
|
||||
await updateOsStore.checkForUpdate({
|
||||
@@ -57,32 +54,74 @@ const check = async () => {
|
||||
status.value = 'ready';
|
||||
})
|
||||
};
|
||||
|
||||
watchEffect(() => {
|
||||
if (!guid.value || !keyfile.value) {
|
||||
status.value = 'ineligible';
|
||||
} else {
|
||||
status.value = 'ready';
|
||||
}
|
||||
});
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div class="flex flex-col sm:flex-shrink-0 items-center gap-16px">
|
||||
<div v-if="status !== 'ineligible'" class="flex flex-col sm:flex-shrink-0 items-center gap-16px">
|
||||
<SwitchGroup as="div">
|
||||
<div class="flex flex-shrink-0 items-center gap-16px">
|
||||
<Switch v-model="includeNext" :class="[includeNext ? 'bg-green-500' : 'bg-gray-200', 'relative inline-flex h-24px w-[44px] flex-shrink-0 cursor-pointer rounded-full border-2 border-transparent transition-colors duration-200 ease-in-out focus:outline-none focus:ring-2 focus:ring-indigo-600 focus:ring-offset-2']">
|
||||
<span :class="[includeNext ? 'translate-x-20px' : 'translate-x-0', 'pointer-events-none relative inline-block h-20px w-20px transform rounded-full bg-white shadow ring-0 transition duration-200 ease-in-out']">
|
||||
<span :class="[includeNext ? 'opacity-0 duration-100 ease-out' : 'opacity-100 duration-200 ease-in', 'absolute inset-0 flex h-full w-full items-center justify-center transition-opacity']" aria-hidden="true">
|
||||
<Switch
|
||||
v-model="includeNext"
|
||||
:class="[
|
||||
includeNext ? 'bg-green-500' : 'bg-gray-200',
|
||||
'relative inline-flex h-24px w-[44px] flex-shrink-0 cursor-pointer rounded-full border-2 border-transparent transition-colors duration-200 ease-in-out focus:outline-none focus:ring-2 focus:ring-indigo-600 focus:ring-offset-2',
|
||||
]"
|
||||
>
|
||||
<span
|
||||
:class="[
|
||||
includeNext ? 'translate-x-20px' : 'translate-x-0',
|
||||
'pointer-events-none relative inline-block h-20px w-20px transform rounded-full bg-white shadow ring-0 transition duration-200 ease-in-out',
|
||||
]"
|
||||
>
|
||||
<span
|
||||
:class="[
|
||||
includeNext ? 'opacity-0 duration-100 ease-out' : 'opacity-100 duration-200 ease-in',
|
||||
'absolute inset-0 flex h-full w-full items-center justify-center transition-opacity',
|
||||
]"
|
||||
aria-hidden="true"
|
||||
>
|
||||
<svg class="h-12px w-12px text-gray-400" fill="none" viewBox="0 0 12 12">
|
||||
<path d="M4 8l2-2m0 0l2-2M6 6L4 4m2 2l2 2" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" />
|
||||
</svg>
|
||||
</span>
|
||||
<span :class="[includeNext ? 'opacity-100 duration-200 ease-in' : 'opacity-0 duration-100 ease-out', 'absolute inset-0 flex h-full w-full items-center justify-center transition-opacity']" aria-hidden="true">
|
||||
<span
|
||||
:class="[
|
||||
includeNext ? 'opacity-100 duration-200 ease-in' : 'opacity-0 duration-100 ease-out',
|
||||
'absolute inset-0 flex h-full w-full items-center justify-center transition-opacity',
|
||||
]"
|
||||
aria-hidden="true"
|
||||
>
|
||||
<svg class="h-12px w-12px text-green-500" fill="currentColor" viewBox="0 0 12 12">
|
||||
<path d="M3.707 5.293a1 1 0 00-1.414 1.414l1.414-1.414zM5 8l-.707.707a1 1 0 001.414 0L5 8zm4.707-3.293a1 1 0 00-1.414-1.414l1.414 1.414zm-7.414 2l2 2 1.414-1.414-2-2-1.414 1.414zm3.414 2l4-4-1.414-1.414-4 4 1.414 1.414z" />
|
||||
</svg>
|
||||
</span>
|
||||
</span>
|
||||
</Switch>
|
||||
<SwitchLabel class="text-14px">{{ t('Include Prereleases') }}</SwitchLabel>
|
||||
<SwitchLabel class="text-14px">{{ t('Check Prereleases') }}</SwitchLabel>
|
||||
</div>
|
||||
</SwitchGroup>
|
||||
<span class="flex flex-col gap-y-8px">
|
||||
<BrandButton @click="check" :disabled="status === 'checking'" btn-style="outline" :text="buttonText" class="flex-0" />
|
||||
<span class="text-14px opacity-75 text-center" :title="releaseCheckTime.formatted">{{ t('Last checked: {0}', [releaseCheckTime.relative]) }}</span>
|
||||
<BrandButton
|
||||
@click="check"
|
||||
:disabled="status !== 'ready'"
|
||||
btn-style="outline"
|
||||
:text="buttonText"
|
||||
class="flex-0" />
|
||||
<span
|
||||
v-if="parsedReleaseTimestamp"
|
||||
class="text-14px opacity-75 text-center"
|
||||
:title="parsedReleaseTimestamp.formatted"
|
||||
>
|
||||
{{ t('Last checked: {0}', [parsedReleaseTimestamp.relative]) }}
|
||||
</span>
|
||||
</span>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
@@ -1,11 +1,17 @@
|
||||
<script lang="ts" setup>
|
||||
import { ArrowUturnDownIcon, InformationCircleIcon } from '@heroicons/vue/24/solid';
|
||||
import {
|
||||
ArrowTopRightOnSquareIcon,
|
||||
ArrowUturnDownIcon,
|
||||
InformationCircleIcon,
|
||||
LifebuoyIcon,
|
||||
} from '@heroicons/vue/24/solid';
|
||||
import type { SemVer } from 'semver';
|
||||
import { ref } from 'vue';
|
||||
|
||||
import 'tailwindcss/tailwind.css';
|
||||
import '~/assets/main.css';
|
||||
|
||||
import { FORUMS_BUG_REPORT } from '~/helpers/urls';
|
||||
import { useUpdateOsActionsStore } from '~/store/updateOsActions';
|
||||
import type { UserProfileLink } from '~/types/userProfile';
|
||||
|
||||
@@ -16,6 +22,11 @@ const props = defineProps<{
|
||||
|
||||
const updateOsActionsStore = useUpdateOsActionsStore();
|
||||
|
||||
const visible = ref(false);
|
||||
const toggleVisible = () => {
|
||||
visible.value = !visible.value;
|
||||
};
|
||||
|
||||
const downgradeButton = ref<UserProfileLink | undefined>({
|
||||
click: () => {
|
||||
// @ts-ignore – global function provided by the webgui on the update page
|
||||
@@ -28,18 +39,37 @@ const downgradeButton = ref<UserProfileLink | undefined>({
|
||||
|
||||
<template>
|
||||
<UiCardWrapper :increased-padding="true">
|
||||
<div class="flex flex-col sm:flex-row sm:items-start sm:justify-between gap-20px sm:gap-24px">
|
||||
<div
|
||||
class="flex flex-col sm:flex-row sm:justify-between gap-20px sm:gap-24px"
|
||||
:class="{
|
||||
'sm:items-center': !visible,
|
||||
'sm:items-start': visible,
|
||||
}"
|
||||
>
|
||||
<div class="grid gap-y-16px">
|
||||
<h3 class="text-20px font-semibold leading-6 flex flex-row items-center gap-8px">
|
||||
<ArrowUturnDownIcon class="w-20px shrink-0" />
|
||||
{{ t('Downgrade Unraid OS to {0}', [version]) }}
|
||||
</h3>
|
||||
<div class="text-16px leading-relaxed opacity-75 whitespace-normal">
|
||||
<p>{{ t('Downgrades are only recommended if you\'re unable to solve a critical issue. In the rare event you need to downgrade we ask that you please provide us with Diagnostics so we can investigate your issue. You will be prompted with the option download the Diagnostics zip once the downgrade process is started. From there please open a bug report on our forums.') }}</p>
|
||||
<div v-if="visible" class="text-16px leading-relaxed opacity-75 whitespace-normal">
|
||||
<p>{{ t('Downgrades are only recommended if you\'re unable to solve a critical issue. In the rare event you need to downgrade we ask that you please provide us with Diagnostics so we can investigate your issue. You will be prompted with the option to download the Diagnostics zip once the downgrade process is started. From there please open a bug report on our forums with a description of the issue and include your diagnostics.') }}</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div v-if="downgradeButton" class="flex flex-col sm:flex-shrink-0 items-center gap-16px">
|
||||
<BrandButton
|
||||
v-if="!visible"
|
||||
@click="toggleVisible"
|
||||
:btn-style="'outline'"
|
||||
:text="t('Learn More')" />
|
||||
|
||||
<div v-else-if="downgradeButton" class="flex flex-col sm:flex-shrink-0 items-center gap-16px">
|
||||
<BrandButton
|
||||
:btn-style="'underline'"
|
||||
:external="true"
|
||||
:href="FORUMS_BUG_REPORT.toString()"
|
||||
:icon="LifebuoyIcon"
|
||||
:icon-right="ArrowTopRightOnSquareIcon"
|
||||
:text="t('Open a bug report')" />
|
||||
<BrandButton
|
||||
@click="downgradeButton?.click"
|
||||
btn-style="underline"
|
||||
|
||||
@@ -1,40 +1,31 @@
|
||||
<script lang="ts" setup>
|
||||
import {
|
||||
ArrowPathIcon,
|
||||
BellAlertIcon,
|
||||
CheckCircleIcon,
|
||||
ExclamationTriangleIcon,
|
||||
InformationCircleIcon,
|
||||
} from '@heroicons/vue/24/solid';
|
||||
import { storeToRefs } from 'pinia';
|
||||
|
||||
import { useServerStore } from '~/store/server';
|
||||
import { useUpdateOsStore } from '~/store/updateOsActions';
|
||||
import { useUpdateOsStore, useUpdateOsActionsStore } from '~/store/updateOsActions';
|
||||
|
||||
const props = defineProps<{
|
||||
releaseCheckTime: {
|
||||
formatted: string;
|
||||
relative: string;
|
||||
};
|
||||
export interface Props {
|
||||
restoreVersion?: string | undefined;
|
||||
t: any;
|
||||
}>();
|
||||
}
|
||||
const props = withDefaults(defineProps<Props>(), {
|
||||
restoreVersion: undefined,
|
||||
});
|
||||
|
||||
const serverStore = useServerStore();
|
||||
const updateOsStore = useUpdateOsStore();
|
||||
const updateOsActionsStore = useUpdateOsActionsStore();
|
||||
|
||||
const { guid, keyfile, osVersion } = storeToRefs(serverStore);
|
||||
const { available } = storeToRefs(updateOsStore);
|
||||
|
||||
const viewReleaseNotes = () => {
|
||||
// @ts-ignore – this is a global function provided by the webgui
|
||||
if (typeof openChanges === 'function') {
|
||||
// @ts-ignore
|
||||
openChanges(
|
||||
'showchanges /var/tmp/unRAIDServer.txt',
|
||||
props.t('{0} Release Notes', [osVersion.value]),
|
||||
);
|
||||
} else {
|
||||
alert('Unable to open release notes');
|
||||
}
|
||||
};
|
||||
const { available, parsedReleaseTimestamp } = storeToRefs(updateOsStore);
|
||||
const { rebootType } = storeToRefs(updateOsActionsStore);
|
||||
</script>
|
||||
|
||||
<template>
|
||||
@@ -43,24 +34,50 @@ const viewReleaseNotes = () => {
|
||||
<div class="flex flex-col md:flex-row gap-16px justify-start md:items-start md:justify-between">
|
||||
<div class="inline-flex gap-8px">
|
||||
<button
|
||||
@click="viewReleaseNotes"
|
||||
@click="updateOsActionsStore.viewCurrentReleaseNotes(t('{0} Release Notes', [osVersion]))"
|
||||
class="group"
|
||||
:title="t('View changelog for current version {0}', [osVersion])"
|
||||
:title="t('View release notes')"
|
||||
>
|
||||
<UiBadge :icon="InformationCircleIcon">
|
||||
<UiBadge :icon="InformationCircleIcon" class="underline">
|
||||
{{ t('Current Version {0}', [osVersion]) }}
|
||||
</UiBadge>
|
||||
</button>
|
||||
|
||||
<UiBadge
|
||||
v-if="!guid || !keyfile"
|
||||
:color="'red'"
|
||||
:icon="ExclamationTriangleIcon"
|
||||
:title="t('A valid keyfile and USB Flash boot device are required to check for updates.')"
|
||||
>
|
||||
{{ t('Unable to check for updates') }}
|
||||
</UiBadge>
|
||||
<UiBadge
|
||||
v-else-if="rebootType === 'none'"
|
||||
:color="available ? 'orange' : 'green'"
|
||||
:icon="available ? BellAlertIcon : CheckCircleIcon"
|
||||
:title="t('Last checked: {0}', [releaseCheckTime.relative])"
|
||||
:title="parsedReleaseTimestamp ? t('Last checked: {0}', [parsedReleaseTimestamp.relative]) : ''"
|
||||
>
|
||||
{{ available ? 'Update Available' : 'Up-to-date' }}
|
||||
{{ available ? t('Update Available') : t('Up-to-date') }}
|
||||
</UiBadge>
|
||||
<UiBadge
|
||||
v-else
|
||||
:color="'yellow'"
|
||||
:icon="ExclamationTriangleIcon"
|
||||
>
|
||||
{{ rebootType === 'downgrade' ? t('Reboot Required for Downgrade') : t('Reboot Required for Update') }}
|
||||
</UiBadge>
|
||||
</div>
|
||||
|
||||
<UpdateOsCheckButton :releaseCheckTime="releaseCheckTime" :t="t" />
|
||||
<div>
|
||||
<UpdateOsCheckButton
|
||||
v-if="rebootType === 'none'"
|
||||
:t="t" />
|
||||
<BrandButton
|
||||
v-else
|
||||
@click="updateOsActionsStore.rebootServer()"
|
||||
:icon="ArrowPathIcon"
|
||||
:text="rebootType === 'downgrade' ? t('Reboot Now to Downgrade') : t('Reboot Now to Update')" />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
@@ -3,7 +3,6 @@
|
||||
* @todo require keyfile to be set before allowing user to check for updates
|
||||
* @todo require keyfile to update
|
||||
* @todo require valid guid / server state to update
|
||||
* @todo detect downgrade possibility
|
||||
*/
|
||||
import { Switch, SwitchGroup, SwitchLabel } from '@headlessui/vue'
|
||||
import {
|
||||
@@ -23,10 +22,6 @@ import { useUpdateOsStore, useUpdateOsActionsStore } from '~/store/updateOsActio
|
||||
import type { UserProfileLink } from '~/types/userProfile';
|
||||
|
||||
const props = defineProps<{
|
||||
releaseCheckTime: {
|
||||
formatted: string;
|
||||
relative: string;
|
||||
};
|
||||
t: any;
|
||||
}>();
|
||||
|
||||
@@ -37,8 +32,6 @@ const updateOsActionsStore = useUpdateOsActionsStore();
|
||||
const { guid, keyfile, osVersion } = storeToRefs(serverStore);
|
||||
const { available } = storeToRefs(updateOsStore);
|
||||
|
||||
const includeNext = ref(false);
|
||||
|
||||
const updateButton = ref<UserProfileLink | undefined>();
|
||||
|
||||
const availableText = computed(() => {
|
||||
@@ -47,16 +40,7 @@ const availableText = computed(() => {
|
||||
}
|
||||
});
|
||||
|
||||
const check = () => {
|
||||
updateOsStore.checkForUpdate({
|
||||
cache: true,
|
||||
guid: guid.value,
|
||||
includeNext: includeNext.value,
|
||||
keyfile: keyfile.value,
|
||||
osVersion: osVersion.value,
|
||||
skipCache: true,
|
||||
});
|
||||
};
|
||||
const ineligible = computed(() => !guid.value || !keyfile.value || !osVersion.value);
|
||||
|
||||
watchEffect(() => {
|
||||
if (available.value) {
|
||||
@@ -79,13 +63,18 @@ watchEffect(() => {
|
||||
</span>
|
||||
</h3>
|
||||
<div class="text-16px leading-relaxed whitespace-normal opacity-75">
|
||||
<p>{{ t('Receive the latest and greatest for Unraid OS. Whether it new features, security patches, or bug fixes – keeping your server up-to-date ensures the best experience that Unraid has to offer.') }}</p>
|
||||
<p v-if="ineligible">{{ t('A valid keyfile and USB Flash boot device are required to check for updates.') }} {{ t('Please fix any errors and try again.') }}</p>
|
||||
<p v-else>{{ t('Receive the latest and greatest for Unraid OS. Whether it new features, security patches, or bug fixes – keeping your server up-to-date ensures the best experience that Unraid has to offer.') }}</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
<BrandButton
|
||||
v-if="available && updateButton"
|
||||
v-if="ineligible"
|
||||
href="/Tools/Registration"
|
||||
:text="t('Go to Tools > Registration')"
|
||||
/>
|
||||
<BrandButton
|
||||
v-else-if="available && updateButton"
|
||||
@click="updateButton?.click"
|
||||
:external="updateButton?.external"
|
||||
:icon-right="ArrowTopRightOnSquareIcon"
|
||||
|
||||
@@ -56,8 +56,11 @@ const outsideDropdown = () => {
|
||||
let copyIpInterval: string | number | NodeJS.Timeout | undefined;
|
||||
const { copy, copied, isSupported } = useClipboard({ source: lanIp.value ?? '' });
|
||||
const showCopyNotSupported = ref<boolean>(false);
|
||||
const copyLanIp = () => {
|
||||
if (!isSupported) { showCopyNotSupported.value = true; }
|
||||
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) => {
|
||||
@@ -86,13 +89,17 @@ onBeforeMount(() => {
|
||||
|
||||
callbackStore.watcher();
|
||||
|
||||
updateOsStore.checkForUpdate({
|
||||
cache: true,
|
||||
guid: guid.value,
|
||||
includeNext: isOsVersionStable.value, // @todo ensure this is correct
|
||||
keyfile: keyfile.value,
|
||||
osVersion: osVersion.value,
|
||||
});
|
||||
if (guid.value && keyfile.value) {
|
||||
updateOsStore.checkForUpdate({
|
||||
cache: true,
|
||||
guid: guid.value,
|
||||
includeNext: isOsVersionStable.value, // @todo ensure this is correct
|
||||
keyfile: keyfile.value,
|
||||
osVersion: osVersion.value,
|
||||
});
|
||||
} else {
|
||||
console.warn('A valid keyfile and USB Flash boot device are required to check for updates.');
|
||||
}
|
||||
});
|
||||
</script>
|
||||
|
||||
|
||||
@@ -1,13 +1,12 @@
|
||||
/**
|
||||
* @todo setup .env
|
||||
*/
|
||||
const ACCOUNT = new URL(import.meta.env.VITE_ACCOUNT ?? 'https://account.unraid.net');
|
||||
const FORUMS = new URL('https://forums.unraid.net');
|
||||
const UNRAID_NET = new URL(import.meta.env.VITE_UNRAID_NET ?? 'https://unraid.net');
|
||||
|
||||
const ACCOUNT_CALLBACK = new URL('c', ACCOUNT);
|
||||
const FORUMS_BUG_REPORT = new URL('/bug-reports', FORUMS);
|
||||
const CONNECT_DOCS = new URL('https://docs.unraid.net/category/unraid-connect');
|
||||
const CONNECT_DASHBOARD = new URL(import.meta.env.VITE_CONNECT ?? 'https://connect.myunraid.net');
|
||||
const CONNECT_FORUMS = new URL('https://forums.unraid.net/forum/94-connect-plugin-support/');
|
||||
const CONNECT_FORUMS = new URL('/forum/94-connect-plugin-support/', FORUMS);
|
||||
const CONTACT = new URL('/contact', UNRAID_NET);
|
||||
const DISCORD = new URL('https://discord.gg/unraid');
|
||||
const GRAPHQL = new URL('/graphql', import.meta.env.VITE_GRAPHQL ?? window.location.origin);
|
||||
@@ -26,6 +25,8 @@ export {
|
||||
CONNECT_FORUMS,
|
||||
CONTACT,
|
||||
DISCORD,
|
||||
FORUMS,
|
||||
FORUMS_BUG_REPORT,
|
||||
GRAPHQL,
|
||||
PURCHASE_CALLBACK,
|
||||
PLUGIN_SETTINGS,
|
||||
|
||||
@@ -210,6 +210,7 @@
|
||||
"Please confirm the update details below": "Please confirm the update details below",
|
||||
"Current Version {0}": "Current Version {0}",
|
||||
"New Version: {0}": "New Version: {0}",
|
||||
"Version: {0}": "Version: {0}",
|
||||
"This update will require a reboot": "This update will require a reboot",
|
||||
"Confirm and start update": "Confirm and start update",
|
||||
"Update Unraid OS": "Update Unraid OS",
|
||||
@@ -219,13 +220,25 @@
|
||||
"Begin restore to Unraid {0}": "Begin restore to Unraid {0}",
|
||||
"Version available for restore {0}": "Version available for restore {0}",
|
||||
"Check for Updates": "Check for Updates",
|
||||
"Include Prereleases": "Include Prereleases",
|
||||
"Check Prereleases": "Check Prereleases",
|
||||
"Receive the latest and greatest for Unraid OS. Whether it new features, security patches, or bug fixes – keeping your server up-to-date ensures the best experience that Unraid has to offer.": "Receive the latest and greatest for Unraid OS. Whether it new features, security patches, or bug fixes – keeping your server up-to-date ensures the best experience that Unraid has to offer.",
|
||||
"Check For Updates": "Check For Updates",
|
||||
"Checking...": "Checking...",
|
||||
"View changelog for current version {0}": "View changelog for current version {0}",
|
||||
"View release notes": "View release notes",
|
||||
"View Changelog for {0}": "View Changelog for {0}",
|
||||
"View changelog & update": "View changelog & update",
|
||||
"{0} Release Notes": "{0} Release Notes",
|
||||
"Unable to open release notes": "Unable to open release notes"
|
||||
"Unable to open release notes": "Unable to open release notes",
|
||||
"Downgrades are only recommended if you're unable to solve a critical issue. In the rare event you need to downgrade we ask that you please provide us with Diagnostics so we can investigate your issue. You will be prompted with the option to download the Diagnostics zip once the downgrade process is started. From there please open a bug report on our forums with a description of the issue and include your diagnostics.": "Downgrades are only recommended if you're unable to solve a critical issue. In the rare event you need to downgrade we ask that you please provide us with Diagnostics so we can investigate your issue. You will be prompted with the option to download the Diagnostics zip once the downgrade process is started. From there please open a bug report on our forums with a description of the issue and include your diagnostics.",
|
||||
"Reboot Now to Downgrade": "Reboot Now to Downgrade",
|
||||
"Reboot Now to Update": "Reboot Now to Update",
|
||||
"Reboot Required for Downgrade": "Reboot Required for Downgrade",
|
||||
"Reboot Required for Update": "Reboot Required for Update",
|
||||
"Update Available": "Update Available",
|
||||
"Up-to-date": "Up-to-date",
|
||||
"Open a bug report": "Open a bug report",
|
||||
"Go to Tools > Update": "Go to Tools > Update",
|
||||
"A valid keyfile and USB Flash boot device are required to check for updates.": "A valid keyfile and USB Flash boot device are required to check for updates.",
|
||||
"Please fix any errors and try again.": "Please fix any errors and try again.",
|
||||
"Go to Tools > Registration": "Go to Tools > Registration"
|
||||
}
|
||||
|
||||
@@ -84,6 +84,10 @@ export default defineNuxtConfig({
|
||||
name: 'UnraidDownloadApiLogs',
|
||||
path: '@/components/DownloadApiLogs.ce',
|
||||
},
|
||||
{
|
||||
name: 'UnraidHeaderOsVersion',
|
||||
path: '@/components/HeaderOsVersion.ce',
|
||||
},
|
||||
{
|
||||
name: 'UnraidKeyActions',
|
||||
path: '@/components/KeyActions.ce',
|
||||
|
||||
@@ -42,6 +42,11 @@ onBeforeMount(() => {
|
||||
</h3>
|
||||
<WanIpCheckCe php-wan-ip="47.184.85.45" />
|
||||
<hr class="border-black dark:border-white">
|
||||
<h3 class="text-lg font-semibold font-mono">
|
||||
HeaderOsVersion
|
||||
</h3>
|
||||
<HeaderOsVersionCe />
|
||||
<hr class="border-black dark:border-white">
|
||||
<h3 class="text-lg font-semibold font-mono">
|
||||
UpdateOsCe
|
||||
</h3>
|
||||
|
||||
@@ -40,6 +40,11 @@ onBeforeMount(() => {
|
||||
</h3>
|
||||
<unraid-wan-ip-check php-wan-ip="47.184.85.45" />
|
||||
<hr class="border-black dark:border-white">
|
||||
<h3 class="text-lg font-semibold font-mono">
|
||||
HeaderOsVersion
|
||||
</h3>
|
||||
<unraid-header-os-version />
|
||||
<hr class="border-black dark:border-white">
|
||||
<h3 class="text-lg font-semibold font-mono">
|
||||
UpdateOsCe
|
||||
</h3>
|
||||
|
||||
@@ -327,7 +327,7 @@ export const useServerStore = defineStore('server', () => {
|
||||
return {
|
||||
actions: [
|
||||
...(!registered.value && connectPluginInstalled.value ? [signInAction.value] : []),
|
||||
...([purchaseAction, redeemAction, trialStartAction]),
|
||||
...([purchaseAction, redeemAction, trialStartAction, recoverAction]),
|
||||
...(registered.value && connectPluginInstalled.value ? [signOutAction.value] : []),
|
||||
],
|
||||
humanReadable: 'No Keyfile',
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
import testReleasesResponse from '~/_data/osReleases'; // test data
|
||||
|
||||
import dayjs, { extend } from 'dayjs';
|
||||
import relativeTime from 'dayjs/plugin/relativeTime';
|
||||
import { defineStore, createPinia, setActivePinia } from 'pinia';
|
||||
import gt from 'semver/functions/gt';
|
||||
import prerelease from 'semver/functions/prerelease';
|
||||
@@ -49,6 +51,8 @@ export interface UpdateOsActionStore {
|
||||
*/
|
||||
setActivePinia(createPinia());
|
||||
|
||||
extend(relativeTime);
|
||||
|
||||
export const RELEASES_LOCAL_STORAGE_KEY = 'unraidReleasesResponse';
|
||||
|
||||
export const useUpdateOsStoreGeneric = (
|
||||
@@ -58,8 +62,8 @@ export const useUpdateOsStoreGeneric = (
|
||||
defineStore('updateOs', () => {
|
||||
// state
|
||||
const available = ref<string>('');
|
||||
const releases = ref<CachedReleasesResponse | undefined>(localStorage.getItem(RELEASES_LOCAL_STORAGE_KEY) ? JSON.parse(localStorage.getItem(RELEASES_LOCAL_STORAGE_KEY) ?? '') : undefined);
|
||||
const osVersion = ref<SemVer | string>('');
|
||||
const releases = ref<CachedReleasesResponse | undefined>(localStorage.getItem(RELEASES_LOCAL_STORAGE_KEY) ? JSON.parse(localStorage.getItem(RELEASES_LOCAL_STORAGE_KEY) ?? '') : undefined);
|
||||
|
||||
if (useUpdateOsActions !== undefined) {
|
||||
const updateOsActions = useUpdateOsActions();
|
||||
@@ -69,7 +73,13 @@ export const useUpdateOsStoreGeneric = (
|
||||
}
|
||||
|
||||
// getters
|
||||
const cachedReleasesTimestamp = computed(() => releases.value?.timestamp);
|
||||
const parsedReleaseTimestamp = computed(() => {
|
||||
if (!releases.value?.timestamp) { return undefined; }
|
||||
return {
|
||||
formatted: dayjs(releases.value?.timestamp).format('YYYY-MM-DD HH:mm:ss'),
|
||||
relative: dayjs().to(dayjs(releases.value?.timestamp)),
|
||||
};
|
||||
});
|
||||
const isOsVersionStable = computed(() => !isVersionStable(osVersion.value));
|
||||
const isAvailableStable = computed(() => {
|
||||
if (!available.value) return undefined;
|
||||
@@ -263,7 +273,7 @@ export const useUpdateOsStoreGeneric = (
|
||||
available,
|
||||
releases,
|
||||
// getters
|
||||
cachedReleasesTimestamp,
|
||||
parsedReleaseTimestamp,
|
||||
isOsVersionStable,
|
||||
isAvailableStable,
|
||||
filteredStableReleases,
|
||||
|
||||
@@ -1,15 +1,9 @@
|
||||
import testOsReleasesResponse from '~/_data/osReleases'; // test data
|
||||
|
||||
import { BellAlertIcon } from '@heroicons/vue/24/solid';
|
||||
import { defineStore, createPinia, setActivePinia } from 'pinia';
|
||||
import gt from 'semver/functions/gt';
|
||||
import coerce from 'semver/functions/coerce';
|
||||
import type { SemVer } from 'semver';
|
||||
|
||||
import useInstallPlugin from '~/composables/installPlugin';
|
||||
import { request } from '~/composables/services/request';
|
||||
|
||||
import { ACCOUNT_CALLBACK, OS_RELEASES } from '~/helpers/urls';
|
||||
import { ACCOUNT_CALLBACK } from '~/helpers/urls';
|
||||
|
||||
import { useCallbackStore } from '~/store/callbackActions';
|
||||
import { useErrorsStore } from '~/store/errors';
|
||||
@@ -17,13 +11,9 @@ import { useServerStore } from '~/store/server';
|
||||
import {
|
||||
useUpdateOsStoreGeneric,
|
||||
type Release,
|
||||
type ReleasesResponse,
|
||||
type CachedReleasesResponse,
|
||||
type UpdateOsActionStore,
|
||||
} from '~/store/updateOs';
|
||||
|
||||
import type { InstallPluginPayload } from '~/composables/installPlugin';
|
||||
import type { ServerStateDataAction } from '~/types/server';
|
||||
import type { UserProfileLink } from '~/types/userProfile';
|
||||
|
||||
/**
|
||||
@@ -44,7 +34,8 @@ export const useUpdateOsActionsStore = defineStore('updateOsActions', () => {
|
||||
// State
|
||||
const osVersion = computed(() => serverStore.osVersion);
|
||||
/** used when coming back from callback, this will be the release to install */
|
||||
const status = ref<'confirming' | 'failed' | 'ready' | 'success' | 'updating' | 'downgrading'>('ready');
|
||||
const rebootType = ref<'downgrade' | 'upgrade' | 'none'>('none');
|
||||
const status = ref<'confirming' | 'checking' | 'ineligible' | 'failed' | 'ready' | 'success' | 'updating' | 'downgrading'>('ready');
|
||||
const callbackUpdateRelease = ref<Release | null>(null);
|
||||
|
||||
// Actions
|
||||
@@ -98,25 +89,46 @@ export const useUpdateOsActionsStore = defineStore('updateOsActions', () => {
|
||||
});
|
||||
};
|
||||
|
||||
const downgradeOs = async () => {
|
||||
setStatus('downgrading');
|
||||
const rebootServer = async () => {
|
||||
// @ts-ignore • global set in the webgui
|
||||
document.rebootNow.submit();
|
||||
};
|
||||
|
||||
const viewCurrentReleaseNotes = (text: string) => {
|
||||
// @ts-ignore – this is a global function provided by the webgui
|
||||
if (typeof openChanges === 'function') {
|
||||
// @ts-ignore
|
||||
openChanges(
|
||||
'showchanges /var/tmp/unRAIDServer.txt',
|
||||
text,
|
||||
);
|
||||
} else {
|
||||
alert('Unable to open release notes');
|
||||
}
|
||||
};
|
||||
|
||||
const setStatus = (payload: typeof status.value) => {
|
||||
status.value = payload;
|
||||
};
|
||||
|
||||
const setRebootType = (payload: typeof rebootType.value) => {
|
||||
rebootType.value = payload;
|
||||
};
|
||||
|
||||
return {
|
||||
// State
|
||||
osVersion,
|
||||
callbackUpdateRelease,
|
||||
osVersion,
|
||||
rebootType,
|
||||
status,
|
||||
// Actions
|
||||
confirmUpdateOs,
|
||||
downgradeOs,
|
||||
installOsUpdate,
|
||||
initUpdateOsCallback,
|
||||
rebootServer,
|
||||
setStatus,
|
||||
setRebootType,
|
||||
viewCurrentReleaseNotes,
|
||||
};
|
||||
});
|
||||
|
||||
|
||||
@@ -54,6 +54,7 @@ export default <Partial<Config>>{
|
||||
'4px': '4px',
|
||||
'6px': '6px',
|
||||
'8px': '8px',
|
||||
'10px': '10px',
|
||||
'12px': '12px',
|
||||
'14px': '14px',
|
||||
'16px': '16px',
|
||||
|
||||
Reference in New Issue
Block a user