diff --git a/web/components/UserProfile/DropdownContent.vue b/web/components/UserProfile/DropdownContent.vue index 8d7814c19..1333d3238 100644 --- a/web/components/UserProfile/DropdownContent.vue +++ b/web/components/UserProfile/DropdownContent.vue @@ -13,11 +13,11 @@ const props = defineProps<{ t: any; }>(); const errorsStore = useErrorsStore(); // const promoStore = usePromoStore(); +const updateOsActionsStore = useUpdateOsActionsStore(); const { errors } = storeToRefs(errorsStore); const { keyActions, connectPluginInstalled, registered, stateData } = storeToRefs(useServerStore()); const { available: osUpdateAvailable } = storeToRefs(useUpdateOsStore()); -const { initUpdateOsCallback } = storeToRefs(useUpdateOsActionsStore()); const signInAction = computed(() => stateData.value.actions?.filter((act: { name: string; }) => act.name === 'signIn') ?? []); const signOutAction = computed(() => stateData.value.actions?.filter((act: { name: string; }) => act.name === 'signOut') ?? []); @@ -96,7 +96,7 @@ const showKeyline = computed(() => showConnectStatus.value && (keyActions.value? diff --git a/web/components/UserProfile/DropdownItem.vue b/web/components/UserProfile/DropdownItem.vue index f99f717ba..c5363bd2e 100644 --- a/web/components/UserProfile/DropdownItem.vue +++ b/web/components/UserProfile/DropdownItem.vue @@ -4,6 +4,7 @@ import type { ServerStateDataAction } from '~/types/server'; import type { UserProfileLink } from '~/types/userProfile'; export interface Props { + clickParams?: any; // so we can pass in params to the click handler item: ServerStateDataAction | UserProfileLink; rounded?: boolean; t: any; @@ -32,11 +33,11 @@ const showExternalIconOnHover = computed(() => props.item?.external && props.ite 'rounded-md': rounded, 'disabled:opacity-50 disabled:hover:opacity-50 disabled:focus:opacity-50 disabled:cursor-not-allowed': item?.disabled, }" - @click.stop="item?.click ? item?.click() : null" + @click.stop="item?.click ? item?.click(clickParams) : null" > UpdateOsActionStore, + useUpdateOsActions?: () => UpdateOsActionStore, + currentOsVersion?: SemVer | string, ) => defineStore('updateOs', () => { - const updateOsActions = useUpdateOsActions(); // state const available = ref(''); const releases = ref(localStorage.getItem(RELEASES_LOCAL_STORAGE_KEY) ? JSON.parse(localStorage.getItem(RELEASES_LOCAL_STORAGE_KEY) ?? '') : undefined); - const osVersion = ref(updateOsActions.osVersion); + const osVersion = ref(''); + + if (useUpdateOsActions !== undefined) { + const updateOsActions = useUpdateOsActions(); + osVersion.value = updateOsActions.osVersion; + } else if (currentOsVersion !== undefined && (typeof currentOsVersion === 'string' || currentOsVersion instanceof SemVer)) { + osVersion.value = currentOsVersion; + } + // getters const isOsVersionStable = computed(() => { const hasPrerelease = prerelease(osVersion.value); return !hasPrerelease; }); + + const filteredStableReleases = computed(() => { + if (!osVersion.value) return undefined; + + if (releases.value?.response?.stable) { + return releases.value?.response?.stable.filter(release => { + console.debug('stable: ', release.version, osVersion.value); + return gt(release.version, osVersion.value as string); + }); + } + return undefined; + }); + + const filteredNextReleases = computed(() => { + if (!osVersion.value) return undefined; + + if (releases.value?.response?.next) { + return releases.value?.response?.next.filter(release => { + console.debug('next: ', release.version, osVersion.value); + return gt(release.version, osVersion.value as string); + }); + } + return undefined; + }); + + const allFilteredReleases = computed(() => { + if (!filteredStableReleases.value && !filteredNextReleases.value) return undefined; + + return { + ...(filteredStableReleases.value && { stable: [...filteredStableReleases.value] }), + ...(filteredNextReleases.value && { next: [...filteredNextReleases.value] }), + } + }); // actions const setReleasesState = (response: ReleasesResponse) => { releases.value = { @@ -203,6 +244,9 @@ export const useUpdateOsStoreGeneric = ( releases, // getters isOsVersionStable, + filteredStableReleases, + filteredNextReleases, + allFilteredReleases, // actions checkForUpdate, findReleaseByMd5, diff --git a/web/store/updateOsActions.ts b/web/store/updateOsActions.ts index 5fba937df..ac2661fe0 100644 --- a/web/store/updateOsActions.ts +++ b/web/store/updateOsActions.ts @@ -35,7 +35,8 @@ export const useUpdateOsActionsStore = defineStore('updateOsActions', () => { const callbackStore = useCallbackStore(); const errorsStore = useErrorsStore(); const serverStore = useServerStore(); - const updateOsStoreGeneric = useUpdateOsStoreGeneric(); + const useUpdateOsStore = useUpdateOsStoreGeneric(); + const updateOsStore = useUpdateOsStore(); const { install: installPlugin } = useInstallPlugin(); @@ -46,14 +47,19 @@ export const useUpdateOsActionsStore = defineStore('updateOsActions', () => { const callbackUpdateRelease = ref(null); // Actions - const initUpdateOsCallback = computed((): ServerStateDataAction => { + const initUpdateOsCallback = (includeNextReleases: boolean = false) => { return { - click: () => { + click: (includeNext: boolean = includeNextReleases) => { callbackStore.send( ACCOUNT_CALLBACK.toString(), [{ server: { ...serverStore.serverAccountPayload, + /** + * Prefer the param in the event for when a user is on stable and wants to see Next releases. + * Otherwise if the os version is NOT stable, we'll include next releases + */ + includeNext: includeNext ?? !updateOsStore.isOsVersionStable, }, type: 'updateOs', }], @@ -64,9 +70,11 @@ export const useUpdateOsActionsStore = defineStore('updateOsActions', () => { external: true, icon: BellAlertIcon, name: 'updateOs', - text: 'Unraid OS Update Available', + text: 'Unraid OS {0} Update Available', + textParams: [updateOsStore.available], } - }); + }; + /** * @description When receiving the callback the Account update page we'll use the provided releaseMd5 to find the release in the releases cache. */ diff --git a/web/types/server.ts b/web/types/server.ts index 13d201e1a..4078f61cc 100644 --- a/web/types/server.ts +++ b/web/types/server.ts @@ -52,6 +52,7 @@ export interface Server { flashVendor?: string; guid?: string; inIframe?: boolean; + includeNext?: boolean; keyfile?: string; lanIp?: string; license?: string; diff --git a/web/types/userProfile.ts b/web/types/userProfile.ts index d50b28693..de3c6c364 100644 --- a/web/types/userProfile.ts +++ b/web/types/userProfile.ts @@ -9,6 +9,7 @@ export interface UserProfileLink { icon?: typeof ArrowTopRightOnSquareIcon; name?: string; text: string; + textParams?: string|number[]; title?: string; }