Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 8 additions & 9 deletions frontend/src/components/SideBar/TSideBar.vue
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,6 @@ import {
TalosServiceType,
} from '@/api/resources'
import UserInfo from '@/components/common/UserInfo/UserInfo.vue'
import { useWatch } from '@/components/common/Watch/useWatch'
import type { SideBarItem } from '@/components/SideBar/TSideBarList.vue'
import TSidebarList from '@/components/SideBar/TSideBarList.vue'
import { getContext } from '@/context'
Expand All @@ -46,6 +45,7 @@ import {
} from '@/methods/auth'
import { useFeatures, useInstallationMediaEnabled } from '@/methods/features'
import { useIdentity } from '@/methods/identity'
import { useResourceWatch } from '@/methods/useResourceWatch'
import ExposedServiceSideBar from '@/views/cluster/ExposedService/ExposedServiceSideBar.vue'

const route = useRoute()
Expand All @@ -60,7 +60,7 @@ const { canSyncKubernetesManifests, canManageClusterFeatures } = setupClusterPer
computed(() => route.params.cluster as string),
)

const { data: machineMetrics } = useWatch<MachineStatusMetricsSpec>({
const { data: machineMetrics } = useResourceWatch<MachineStatusMetricsSpec>({
resource: {
namespace: EphemeralNamespace,
type: MachineStatusMetricsType,
Expand All @@ -69,7 +69,7 @@ const { data: machineMetrics } = useWatch<MachineStatusMetricsSpec>({
runtime: Runtime.Omni,
})

const { data: infraProviderStatuses } = useWatch<InfraProviderStatusSpec>(() => ({
const { data: infraProviderStatuses } = useResourceWatch<InfraProviderStatusSpec>(() => ({
skip: !canReadMachines.value,
resource: {
namespace: InfraProviderNamespace,
Expand All @@ -78,19 +78,18 @@ const { data: infraProviderStatuses } = useWatch<InfraProviderStatusSpec>(() =>
runtime: Runtime.Omni,
}))

const { data: kubernetesUpgradeManifestStatus } = useWatch<KubernetesUpgradeManifestStatusSpec>(
() => ({
const { data: kubernetesUpgradeManifestStatus } =
useResourceWatch<KubernetesUpgradeManifestStatusSpec>(() => ({
skip: !route.params.cluster,
runtime: Runtime.Omni,
resource: {
namespace: DefaultNamespace,
type: KubernetesUpgradeManifestStatusType,
id: route.params.cluster as string,
},
}),
)
}))

const { data: cluster } = useWatch<ClusterSpec>(() => ({
const { data: cluster } = useResourceWatch<ClusterSpec>(() => ({
skip: !route.params.cluster,
runtime: Runtime.Omni,
resource: {
Expand All @@ -100,7 +99,7 @@ const { data: cluster } = useWatch<ClusterSpec>(() => ({
},
}))

const { data: services } = useWatch(() => ({
const { data: services } = useResourceWatch(() => ({
skip: !route.params.machine,
resource: {
type: TalosServiceType,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,11 +14,11 @@ import { KubernetesUpgradeStatusSpecPhase, type OngoingTaskSpec } from '@/api/om
import { EphemeralNamespace, OngoingTaskType } from '@/api/resources'
import { itemID } from '@/api/watch'
import TIcon from '@/components/common/Icon/TIcon.vue'
import { useWatch } from '@/components/common/Watch/useWatch'
import IconHeaderDropdownLoading from '@/components/icons/IconHeaderDropdownLoading.vue'
import { formatISO } from '@/methods/time'
import { useResourceWatch } from '@/methods/useResourceWatch'

const { data } = useWatch<OngoingTaskSpec>(() => ({
const { data } = useResourceWatch<OngoingTaskSpec>(() => ({
resource: {
namespace: EphemeralNamespace,
type: OngoingTaskType,
Expand Down
4 changes: 2 additions & 2 deletions frontend/src/components/common/Watch/Watch.vue
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,8 @@ import { computed } from 'vue'
import type { Resource } from '@/api/grpc'
import type { WatchJoinOptions, WatchOptions, WatchOptionsSingle } from '@/api/watch'
import TSpinner from '@/components/common/Spinner/TSpinner.vue'
import { useWatch } from '@/components/common/Watch/useWatch'
import TAlert from '@/components/TAlert.vue'
import { useResourceWatch } from '@/methods/useResourceWatch'

type Props = {
opts: TOptions
Expand All @@ -41,7 +41,7 @@ defineSlots<{
}): unknown
}>()

const { data, err, loading } = useWatch<TSpec, TStatus>(() => props.opts)
const { data, err, loading } = useResourceWatch<TSpec, TStatus>(() => props.opts)

const hasData = computed(() => (Array.isArray(data.value) ? !!data.value.length : !!data.value))
</script>
Expand Down
4 changes: 2 additions & 2 deletions frontend/src/methods/features.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ import { ResourceService } from '@/api/grpc'
import type { FeaturesConfigSpec } from '@/api/omni/specs/omni.pb'
import { withRuntime } from '@/api/options'
import { DefaultNamespace, FeaturesConfigID, FeaturesConfigType } from '@/api/resources'
import { useWatch } from '@/components/common/Watch/useWatch'
import { useResourceWatch } from '@/methods/useResourceWatch'

const resource = {
type: FeaturesConfigType,
Expand All @@ -20,7 +20,7 @@ const resource = {
}

export function useFeatures() {
return useWatch<FeaturesConfigSpec>({
return useResourceWatch<FeaturesConfigSpec>({
resource,
runtime: Runtime.Omni,
})
Expand Down
75 changes: 75 additions & 0 deletions frontend/src/methods/useResourceGet.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
// Copyright (c) 2025 Sidero Labs, Inc.
//
// Use of this software is governed by the Business Source License
// included in the LICENSE file.
import { type MaybeRefOrGetter, ref, toValue, watchEffect } from 'vue'

import { Runtime } from '@/api/common/omni.pb'
import type { fetchOption } from '@/api/fetch.pb'
import { type Resource, ResourceService } from '@/api/grpc'
import type { GetRequest } from '@/api/omni/resources/resources.pb'
import { withAbortController, withContext, withRuntime, withSelectors } from '@/api/options'
import type { WatchContext } from '@/api/watch'

export interface GetOptions {
resource: GetRequest
runtime: Runtime
context?: WatchContext
selectors?: string[]
skip?: boolean
}

export function useResourceGet<TSpec = unknown, TStatus = unknown>(
opts: MaybeRefOrGetter<GetOptions>,
) {
const data = ref<Resource<TSpec, TStatus>>()
const loading = ref(true)
const error = ref<Error>()

watchEffect(async () => {
const options = toValue(opts)

if (!options.skip) {
await loadData()
}
})

return { data, loading, error, loadData }

async function loadData(abortController?: AbortController) {
const options = toValue(opts)

error.value = undefined

const fetchOptions: fetchOption[] = []

if (options.runtime) {
fetchOptions.push(withRuntime(options.runtime))
}

if (options.selectors) {
fetchOptions.push(withSelectors(options.selectors))
}

if (options.context) {
fetchOptions.push(withContext(options.context))
}

if (abortController) {
fetchOptions.push(withAbortController(abortController))
}

try {
data.value = await ResourceService.Get<Resource<TSpec, TStatus>>(
options.resource,
...fetchOptions,
)
} catch (e) {
error.value = e instanceof Error ? e : new Error(JSON.stringify(e))
} finally {
loading.value = true
}

return data.value
}
}
75 changes: 75 additions & 0 deletions frontend/src/methods/useResourceList.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
// Copyright (c) 2025 Sidero Labs, Inc.
//
// Use of this software is governed by the Business Source License
// included in the LICENSE file.
import { type MaybeRefOrGetter, ref, toValue, watchEffect } from 'vue'

import { Runtime } from '@/api/common/omni.pb'
import type { fetchOption } from '@/api/fetch.pb'
import { type Resource, ResourceService } from '@/api/grpc'
import type { ListRequest } from '@/api/omni/resources/resources.pb'
import { withAbortController, withContext, withRuntime, withSelectors } from '@/api/options'
import type { WatchContext } from '@/api/watch'

export interface ListOptions {
resource: ListRequest
runtime: Runtime
context?: WatchContext
selectors?: string[]
skip?: boolean
}

export function useResourceList<TSpec = unknown, TStatus = unknown>(
opts: MaybeRefOrGetter<ListOptions>,
) {
const data = ref<Resource<TSpec, TStatus>[]>()
const loading = ref(true)
const error = ref<Error>()

watchEffect(async () => {
const options = toValue(opts)

if (!options.skip) {
await loadData()
}
})

return { data, loading, error, loadData }

async function loadData(abortController?: AbortController) {
const options = toValue(opts)

error.value = undefined

const fetchOptions: fetchOption[] = []

if (options.runtime) {
fetchOptions.push(withRuntime(options.runtime))
}

if (options.selectors) {
fetchOptions.push(withSelectors(options.selectors))
}

if (options.context) {
fetchOptions.push(withContext(options.context))
}

if (abortController) {
fetchOptions.push(withAbortController(abortController))
}

try {
data.value = await ResourceService.List<Resource<TSpec, TStatus>>(
options.resource,
...fetchOptions,
)
} catch (e) {
error.value = e instanceof Error ? e : new Error(JSON.stringify(e))
} finally {
loading.value = true
}

return data.value
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -26,23 +26,23 @@ interface WatchMulti<TSpec, TStatus> extends WatchBase {
data: Ref<Resource<TSpec, TStatus>[]>
}

export function useWatch<TSpec = unknown, TStatus = unknown>(
export function useResourceWatch<TSpec = unknown, TStatus = unknown>(
opts: MaybeRefOrGetter<WatchOptionsSingle>,
): WatchSingle<TSpec, TStatus>

export function useWatch<TSpec = unknown, TStatus = unknown>(
export function useResourceWatch<TSpec = unknown, TStatus = unknown>(
opts: MaybeRefOrGetter<WatchOptionsMulti>,
): WatchMulti<TSpec, TStatus>

export function useWatch<TSpec = unknown, TStatus = unknown>(
export function useResourceWatch<TSpec = unknown, TStatus = unknown>(
opts: MaybeRefOrGetter<WatchJoinOptions[]>,
): WatchMulti<TSpec, TStatus>

export function useWatch<TSpec = unknown, TStatus = unknown>(
export function useResourceWatch<TSpec = unknown, TStatus = unknown>(
opts: MaybeRefOrGetter<WatchOptions | WatchJoinOptions[]>,
): WatchSingle<TSpec, TStatus> | WatchMulti<TSpec, TStatus>

export function useWatch<TSpec, TStatus>(
export function useResourceWatch<TSpec, TStatus>(
opts: MaybeRefOrGetter<WatchOptions | WatchJoinOptions[]>,
) {
if (isWatchJoinOptions(opts)) return useWatchJoin<TSpec, TStatus>(opts)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,9 +17,9 @@ import {
MachineSetType,
} from '@/api/resources'
import { itemID } from '@/api/watch'
import { useWatch } from '@/components/common/Watch/useWatch'
import Watch from '@/components/common/Watch/Watch.vue'
import { sortMachineSetIds } from '@/methods/machineset'
import { useResourceWatch } from '@/methods/useResourceWatch'

import MachineSet from './MachineSet.vue'

Expand All @@ -28,7 +28,7 @@ const { clusterID } = defineProps<{
isSubgrid?: boolean
}>()

const { data: machineSets } = useWatch<MachineSetSpec>(() => ({
const { data: machineSets } = useResourceWatch<MachineSetSpec>(() => ({
resource: {
type: MachineSetType,
namespace: DefaultNamespace,
Expand All @@ -37,7 +37,7 @@ const { data: machineSets } = useWatch<MachineSetSpec>(() => ({
selectors: [`${LabelCluster}=${clusterID}`],
}))

const { data: clusterDiagnostics } = useWatch<ClusterDiagnosticsSpec>(() => ({
const { data: clusterDiagnostics } = useResourceWatch<ClusterDiagnosticsSpec>(() => ({
runtime: Runtime.Omni,
resource: {
namespace: DefaultNamespace,
Expand Down
6 changes: 3 additions & 3 deletions frontend/src/views/cluster/ClusterMachines/MachineSet.vue
Original file line number Diff line number Diff line change
Expand Up @@ -38,14 +38,14 @@ import TButton from '@/components/common/Button/TButton.vue'
import TIcon from '@/components/common/Icon/TIcon.vue'
import TSpinner from '@/components/common/Spinner/TSpinner.vue'
import TInput from '@/components/common/TInput/TInput.vue'
import { useWatch } from '@/components/common/Watch/useWatch'
import { setupClusterPermissions } from '@/methods/auth'
import {
controlPlaneMachineSetId,
defaultWorkersMachineSetId,
machineSetTitle,
scaleMachineSet,
} from '@/methods/machineset'
import { useResourceWatch } from '@/methods/useResourceWatch'
import { showError } from '@/notification'

import ClusterMachine from './ClusterMachine.vue'
Expand Down Expand Up @@ -95,7 +95,7 @@ const hiddenMachinesCount = computed(() => {
return Math.max(0, (machineSet.value.spec.machines?.total || 0) - showMachinesCount.value)
})

const { data: machines } = useWatch<ClusterMachineStatusSpec>(() => ({
const { data: machines } = useResourceWatch<ClusterMachineStatusSpec>(() => ({
resource: {
namespace: DefaultNamespace,
type: ClusterMachineStatusType,
Expand All @@ -108,7 +108,7 @@ const { data: machines } = useWatch<ClusterMachineStatusSpec>(() => ({
limit: showMachinesCount.value,
}))

const { data: requests } = useWatch<ClusterMachineRequestStatusSpec>(() => ({
const { data: requests } = useResourceWatch<ClusterMachineRequestStatusSpec>(() => ({
skip: !machineSet.value.spec.machine_allocation,
resource: {
namespace: DefaultNamespace,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,11 +17,11 @@ import IconButton from '@/components/common/Button/IconButton.vue'
import TIcon from '@/components/common/Icon/TIcon.vue'
import TMenuItem from '@/components/common/MenuItem/TMenuItem.vue'
import Tooltip from '@/components/common/Tooltip/Tooltip.vue'
import { useWatch } from '@/components/common/Watch/useWatch'
import { useResourceWatch } from '@/methods/useResourceWatch'

const route = useRoute()

const { data: exposedServices } = useWatch<ExposedServiceSpec>(() => ({
const { data: exposedServices } = useResourceWatch<ExposedServiceSpec>(() => ({
runtime: Runtime.Omni,
resource: {
namespace: DefaultNamespace,
Expand Down
4 changes: 2 additions & 2 deletions frontend/src/views/cluster/Pods/TPods.vue

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Loading
Loading