github.com/grafana/pyroscope@v1.18.0/public/app/models/app.ts (about)

     1  import { parse, brandQuery, Query } from '@pyroscope/models/query';
     2  import { SpyNameSchema, UnitsSchema } from '@pyroscope/legacy/models';
     3  import { z } from 'zod';
     4  
     5  export const PyroscopeAppLabel = 'pyroscope_app';
     6  export const ServiceNameLabel = 'service_name';
     7  
     8  const AppWithPyroscopeAppIndex = z.object({
     9    __profile_type__: z.string(),
    10    pyroscope_app: z.string(),
    11    // Fake a discriminated union
    12    __name_id__: z.enum([PyroscopeAppLabel]).default(PyroscopeAppLabel),
    13    name: z.string().optional().default(''),
    14  });
    15  
    16  const AppWithServiceNameIndex = z.object({
    17    __profile_type__: z.string(),
    18    service_name: z.string(),
    19    // Fake a discriminated union
    20    __name_id__: z.enum([ServiceNameLabel]).default(ServiceNameLabel),
    21    name: z.string().optional().default(''),
    22  });
    23  
    24  // Backwards compatibility,
    25  // even though https://github.com/grafana/phlare/pull/710 is merged
    26  // we can't guarantee backend is deployed to support that
    27  export const BasicAppSchema = AppWithPyroscopeAppIndex.or(
    28    AppWithServiceNameIndex
    29  ).transform(enhanceWithName);
    30  
    31  const ExtraFields = z.object({
    32    __type__: z.string(),
    33    __name__: z.string(),
    34  });
    35  
    36  export const AppSchema = AppWithPyroscopeAppIndex.merge(ExtraFields)
    37    .or(AppWithServiceNameIndex.merge(ExtraFields))
    38    .transform(enhanceWithName);
    39  
    40  // Always populate the 'field' name, to make it easier for components that
    41  // only need to display a name
    42  function enhanceWithName<
    43    T extends
    44      | { __name_id__: 'pyroscope_app'; pyroscope_app: string; name: string }
    45      | {
    46          __name_id__: 'service_name';
    47          service_name: string;
    48          name: string;
    49        }
    50  >(a: T) {
    51    if (a.__name_id__ === 'pyroscope_app') {
    52      a.name = a.pyroscope_app;
    53    }
    54    if (a.__name_id__ === 'service_name') {
    55      a.name = a.service_name;
    56    }
    57    return a;
    58  }
    59  
    60  export type App = z.infer<typeof AppSchema>;
    61  
    62  export type BasicApp = z.infer<typeof BasicAppSchema>;
    63  
    64  // Given a query returns an App
    65  export function appFromQuery(
    66    query: Query
    67  ): z.infer<typeof BasicAppSchema> | undefined {
    68    const parsed = parse(query);
    69  
    70    if (!parsed) {
    71      return undefined;
    72    }
    73  
    74    const app = {
    75      __profile_type__: parsed?.profileId,
    76      ...parsed?.tags,
    77    };
    78  
    79    const parsedApp = BasicAppSchema.safeParse(app);
    80    if (!parsedApp.success) {
    81      return undefined;
    82    }
    83  
    84    return parsedApp.data;
    85  }
    86  
    87  export function appToQuery(app: z.infer<typeof BasicAppSchema>): Query {
    88    // Useless check just to satisfy type checking
    89    if (app.__name_id__ === 'pyroscope_app') {
    90      return brandQuery(
    91        `${app.__profile_type__}{${app.__name_id__}="${app[app.__name_id__]}"}`
    92      );
    93    }
    94  
    95    return brandQuery(
    96      `${app.__profile_type__}{${app.__name_id__}="${app[app.__name_id__]}"}`
    97    );
    98  }
    99  
   100  // TODO old App type
   101  //
   102  // export type App = z.infer<typeof appModel>;
   103  
   104  export const appModel = z.object({
   105    name: z.string(),
   106    spyName: SpyNameSchema,
   107    units: UnitsSchema,
   108  });
   109  
   110  export const appsModel = z.array(appModel);