xref: /openbmc/webui-vue/src/api/composables/useRedfishRoot.ts (revision d3b05033fe82aed6c53f4f2b52c23d3bd285d423)
1import { useQuery } from '@tanstack/vue-query';
2import api from '@/store/api';
3
4/**
5 * Redfish ServiceRoot response interface
6 */
7export interface ServiceRoot {
8  '@odata.id': string;
9  '@odata.type': string;
10  Id: string;
11  Name: string;
12  RedfishVersion: string;
13  UUID?: string;
14  Systems?: { '@odata.id': string };
15  Chassis?: { '@odata.id': string };
16  Managers?: { '@odata.id': string };
17  SessionService?: { '@odata.id': string };
18  AccountService?: { '@odata.id': string };
19  EventService?: { '@odata.id': string };
20  UpdateService?: { '@odata.id': string };
21  ProtocolFeaturesSupported?: {
22    ExpandQuery?: {
23      ExpandAll?: boolean;
24      Levels?: boolean;
25      Links?: boolean;
26      MaxLevels?: number;
27      NoLinks?: boolean;
28    };
29    FilterQuery?: boolean;
30    SelectQuery?: boolean;
31    OnlyMemberQuery?: boolean;
32  };
33}
34
35/**
36 * Fetches the Redfish ServiceRoot
37 * @returns {Promise<ServiceRoot>}
38 */
39async function fetchServiceRoot(): Promise<ServiceRoot> {
40  const { data } = await api.get('/redfish/v1/');
41  return data;
42}
43
44/**
45 * TanStack Query hook for fetching and caching Redfish ServiceRoot
46 *
47 * @returns {Object} TanStack Query result
48 * @property {ServiceRoot} data - ServiceRoot data
49 * @property {boolean} isLoading - Loading state
50 * @property {boolean} isError - Error state
51 * @property {Error} error - Error object
52 */
53export function useRedfishRoot() {
54  return useQuery({
55    queryKey: ['redfish', 'serviceRoot'],
56    queryFn: fetchServiceRoot,
57    staleTime: Infinity, // ServiceRoot rarely changes, cache indefinitely
58    gcTime: Infinity, // Keep in cache indefinitely (formerly cacheTime in v4)
59    retry: 3,
60    retryDelay: (attemptIndex) => Math.min(1000 * 2 ** attemptIndex, 30000),
61  });
62}
63
64/**
65 * Helper to check if OData $expand is supported
66 * @param {ServiceRoot} serviceRoot - ServiceRoot data
67 * @returns {boolean}
68 */
69export function supportsExpandQuery(
70  serviceRoot: ServiceRoot | undefined,
71): boolean {
72  if (!serviceRoot) return false;
73  const maxLevels =
74    serviceRoot.ProtocolFeaturesSupported?.ExpandQuery?.MaxLevels;
75  return typeof maxLevels === 'number' && maxLevels > 0;
76}
77
78/**
79 * Helper to check if OData $select is supported
80 * @param {ServiceRoot} serviceRoot - ServiceRoot data
81 * @returns {boolean}
82 */
83export function supportsSelectQuery(
84  serviceRoot: ServiceRoot | undefined,
85): boolean {
86  if (!serviceRoot) return false;
87  return serviceRoot.ProtocolFeaturesSupported?.SelectQuery === true;
88}
89
90/**
91 * Helper to check if OData $filter is supported
92 * @param {ServiceRoot} serviceRoot - ServiceRoot data
93 * @returns {boolean}
94 */
95export function supportsFilterQuery(
96  serviceRoot: ServiceRoot | undefined,
97): boolean {
98  if (!serviceRoot) return false;
99  return serviceRoot.ProtocolFeaturesSupported?.FilterQuery === true;
100}
101
102/**
103 * Helper to get max expand levels supported
104 * @param {ServiceRoot} serviceRoot - ServiceRoot data
105 * @returns {number} Max levels (0 if not supported)
106 */
107export function getMaxExpandLevels(
108  serviceRoot: ServiceRoot | undefined,
109): number {
110  if (!serviceRoot) return 0;
111  return serviceRoot.ProtocolFeaturesSupported?.ExpandQuery?.MaxLevels || 0;
112}
113