mirror of
https://github.com/SigNoz/signoz.git
synced 2026-03-24 13:20:27 +00:00
Compare commits
3 Commits
nv/4172
...
feat/v2-us
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
d0de617e0b | ||
|
|
6fa418c72f | ||
|
|
531979543c |
@@ -342,6 +342,34 @@ components:
|
||||
config:
|
||||
$ref: '#/components/schemas/AuthtypesAuthDomainConfig'
|
||||
type: object
|
||||
AuthtypesUserWithRoles:
|
||||
properties:
|
||||
createdAt:
|
||||
format: date-time
|
||||
type: string
|
||||
displayName:
|
||||
type: string
|
||||
email:
|
||||
type: string
|
||||
id:
|
||||
type: string
|
||||
isRoot:
|
||||
type: boolean
|
||||
orgId:
|
||||
type: string
|
||||
roles:
|
||||
items:
|
||||
$ref: '#/components/schemas/AuthtypesRole'
|
||||
nullable: true
|
||||
type: array
|
||||
status:
|
||||
type: string
|
||||
updatedAt:
|
||||
format: date-time
|
||||
type: string
|
||||
required:
|
||||
- id
|
||||
type: object
|
||||
CloudintegrationtypesAWSAccountConfig:
|
||||
properties:
|
||||
regions:
|
||||
@@ -2647,6 +2675,25 @@ components:
|
||||
required:
|
||||
- id
|
||||
type: object
|
||||
TypesUpdatableSelfUser:
|
||||
properties:
|
||||
displayName:
|
||||
type: string
|
||||
required:
|
||||
- displayName
|
||||
type: object
|
||||
TypesUpdatableUser:
|
||||
properties:
|
||||
displayName:
|
||||
type: string
|
||||
roleNames:
|
||||
items:
|
||||
type: string
|
||||
type: array
|
||||
required:
|
||||
- displayName
|
||||
- roleNames
|
||||
type: object
|
||||
TypesUser:
|
||||
properties:
|
||||
createdAt:
|
||||
@@ -7781,6 +7828,66 @@ paths:
|
||||
summary: Readiness check
|
||||
tags:
|
||||
- health
|
||||
/api/v2/roles/{id}/users:
|
||||
get:
|
||||
deprecated: false
|
||||
description: This endpoint returns the users having the role by role id
|
||||
operationId: GetUsersByRoleID
|
||||
parameters:
|
||||
- in: path
|
||||
name: id
|
||||
required: true
|
||||
schema:
|
||||
type: string
|
||||
responses:
|
||||
"200":
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
properties:
|
||||
data:
|
||||
items:
|
||||
$ref: '#/components/schemas/TypesUser'
|
||||
type: array
|
||||
status:
|
||||
type: string
|
||||
required:
|
||||
- status
|
||||
- data
|
||||
type: object
|
||||
description: OK
|
||||
"401":
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: '#/components/schemas/RenderErrorResponse'
|
||||
description: Unauthorized
|
||||
"403":
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: '#/components/schemas/RenderErrorResponse'
|
||||
description: Forbidden
|
||||
"404":
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: '#/components/schemas/RenderErrorResponse'
|
||||
description: Not Found
|
||||
"500":
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: '#/components/schemas/RenderErrorResponse'
|
||||
description: Internal Server Error
|
||||
security:
|
||||
- api_key:
|
||||
- ADMIN
|
||||
- tokenizer:
|
||||
- ADMIN
|
||||
summary: Get users by role id
|
||||
tags:
|
||||
- users
|
||||
/api/v2/sessions:
|
||||
delete:
|
||||
deprecated: false
|
||||
@@ -7939,6 +8046,306 @@ paths:
|
||||
summary: Rotate session
|
||||
tags:
|
||||
- sessions
|
||||
/api/v2/users:
|
||||
get:
|
||||
deprecated: false
|
||||
description: This endpoint lists all users for the organization
|
||||
operationId: ListUsersV2
|
||||
responses:
|
||||
"200":
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
properties:
|
||||
data:
|
||||
items:
|
||||
$ref: '#/components/schemas/TypesUser'
|
||||
type: array
|
||||
status:
|
||||
type: string
|
||||
required:
|
||||
- status
|
||||
- data
|
||||
type: object
|
||||
description: OK
|
||||
"401":
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: '#/components/schemas/RenderErrorResponse'
|
||||
description: Unauthorized
|
||||
"403":
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: '#/components/schemas/RenderErrorResponse'
|
||||
description: Forbidden
|
||||
"500":
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: '#/components/schemas/RenderErrorResponse'
|
||||
description: Internal Server Error
|
||||
security:
|
||||
- api_key:
|
||||
- ADMIN
|
||||
- tokenizer:
|
||||
- ADMIN
|
||||
summary: List users v2
|
||||
tags:
|
||||
- users
|
||||
/api/v2/users/{id}:
|
||||
get:
|
||||
deprecated: false
|
||||
description: This endpoint returns the user by id
|
||||
operationId: GetUserV2
|
||||
parameters:
|
||||
- in: path
|
||||
name: id
|
||||
required: true
|
||||
schema:
|
||||
type: string
|
||||
responses:
|
||||
"200":
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
properties:
|
||||
data:
|
||||
$ref: '#/components/schemas/TypesUser'
|
||||
status:
|
||||
type: string
|
||||
required:
|
||||
- status
|
||||
- data
|
||||
type: object
|
||||
description: OK
|
||||
"401":
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: '#/components/schemas/RenderErrorResponse'
|
||||
description: Unauthorized
|
||||
"403":
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: '#/components/schemas/RenderErrorResponse'
|
||||
description: Forbidden
|
||||
"404":
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: '#/components/schemas/RenderErrorResponse'
|
||||
description: Not Found
|
||||
"500":
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: '#/components/schemas/RenderErrorResponse'
|
||||
description: Internal Server Error
|
||||
security:
|
||||
- api_key:
|
||||
- ADMIN
|
||||
- tokenizer:
|
||||
- ADMIN
|
||||
summary: Get user by user id
|
||||
tags:
|
||||
- users
|
||||
put:
|
||||
deprecated: false
|
||||
description: This endpoint updates the user by id
|
||||
operationId: UpdateUserV2
|
||||
parameters:
|
||||
- in: path
|
||||
name: id
|
||||
required: true
|
||||
schema:
|
||||
type: string
|
||||
requestBody:
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: '#/components/schemas/TypesUpdatableUser'
|
||||
responses:
|
||||
"204":
|
||||
description: No Content
|
||||
"400":
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: '#/components/schemas/RenderErrorResponse'
|
||||
description: Bad Request
|
||||
"401":
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: '#/components/schemas/RenderErrorResponse'
|
||||
description: Unauthorized
|
||||
"403":
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: '#/components/schemas/RenderErrorResponse'
|
||||
description: Forbidden
|
||||
"404":
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: '#/components/schemas/RenderErrorResponse'
|
||||
description: Not Found
|
||||
"500":
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: '#/components/schemas/RenderErrorResponse'
|
||||
description: Internal Server Error
|
||||
security:
|
||||
- api_key:
|
||||
- ADMIN
|
||||
- tokenizer:
|
||||
- ADMIN
|
||||
summary: Update user v2
|
||||
tags:
|
||||
- users
|
||||
/api/v2/users/{id}/roles:
|
||||
get:
|
||||
deprecated: false
|
||||
description: This endpoint returns the user roles by user id
|
||||
operationId: GetUserRoles
|
||||
parameters:
|
||||
- in: path
|
||||
name: id
|
||||
required: true
|
||||
schema:
|
||||
type: string
|
||||
responses:
|
||||
"200":
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
properties:
|
||||
data:
|
||||
items:
|
||||
$ref: '#/components/schemas/AuthtypesRole'
|
||||
type: array
|
||||
status:
|
||||
type: string
|
||||
required:
|
||||
- status
|
||||
- data
|
||||
type: object
|
||||
description: OK
|
||||
"401":
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: '#/components/schemas/RenderErrorResponse'
|
||||
description: Unauthorized
|
||||
"403":
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: '#/components/schemas/RenderErrorResponse'
|
||||
description: Forbidden
|
||||
"404":
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: '#/components/schemas/RenderErrorResponse'
|
||||
description: Not Found
|
||||
"500":
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: '#/components/schemas/RenderErrorResponse'
|
||||
description: Internal Server Error
|
||||
security:
|
||||
- api_key:
|
||||
- ADMIN
|
||||
- tokenizer:
|
||||
- ADMIN
|
||||
summary: Get user roles
|
||||
tags:
|
||||
- users
|
||||
/api/v2/users/me:
|
||||
get:
|
||||
deprecated: false
|
||||
description: This endpoint returns the user I belong to
|
||||
operationId: GetMyUserV2
|
||||
responses:
|
||||
"200":
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
properties:
|
||||
data:
|
||||
$ref: '#/components/schemas/AuthtypesUserWithRoles'
|
||||
status:
|
||||
type: string
|
||||
required:
|
||||
- status
|
||||
- data
|
||||
type: object
|
||||
description: OK
|
||||
"401":
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: '#/components/schemas/RenderErrorResponse'
|
||||
description: Unauthorized
|
||||
"403":
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: '#/components/schemas/RenderErrorResponse'
|
||||
description: Forbidden
|
||||
"500":
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: '#/components/schemas/RenderErrorResponse'
|
||||
description: Internal Server Error
|
||||
security:
|
||||
- tokenizer: []
|
||||
summary: Get my user v2
|
||||
tags:
|
||||
- users
|
||||
put:
|
||||
deprecated: false
|
||||
description: This endpoint updates the user I belong to
|
||||
operationId: UpdateMyUserV2
|
||||
requestBody:
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: '#/components/schemas/TypesUpdatableSelfUser'
|
||||
responses:
|
||||
"204":
|
||||
description: No Content
|
||||
"401":
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: '#/components/schemas/RenderErrorResponse'
|
||||
description: Unauthorized
|
||||
"403":
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: '#/components/schemas/RenderErrorResponse'
|
||||
description: Forbidden
|
||||
"500":
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: '#/components/schemas/RenderErrorResponse'
|
||||
description: Internal Server Error
|
||||
security:
|
||||
- tokenizer: []
|
||||
summary: Update my user v2
|
||||
tags:
|
||||
- users
|
||||
/api/v2/zeus/hosts:
|
||||
get:
|
||||
deprecated: false
|
||||
|
||||
@@ -437,6 +437,48 @@ export interface AuthtypesUpdateableAuthDomainDTO {
|
||||
config?: AuthtypesAuthDomainConfigDTO;
|
||||
}
|
||||
|
||||
export interface AuthtypesUserWithRolesDTO {
|
||||
/**
|
||||
* @type string
|
||||
* @format date-time
|
||||
*/
|
||||
createdAt?: Date;
|
||||
/**
|
||||
* @type string
|
||||
*/
|
||||
displayName?: string;
|
||||
/**
|
||||
* @type string
|
||||
*/
|
||||
email?: string;
|
||||
/**
|
||||
* @type string
|
||||
*/
|
||||
id: string;
|
||||
/**
|
||||
* @type boolean
|
||||
*/
|
||||
isRoot?: boolean;
|
||||
/**
|
||||
* @type string
|
||||
*/
|
||||
orgId?: string;
|
||||
/**
|
||||
* @type array
|
||||
* @nullable true
|
||||
*/
|
||||
roles?: AuthtypesRoleDTO[] | null;
|
||||
/**
|
||||
* @type string
|
||||
*/
|
||||
status?: string;
|
||||
/**
|
||||
* @type string
|
||||
* @format date-time
|
||||
*/
|
||||
updatedAt?: Date;
|
||||
}
|
||||
|
||||
export interface CloudintegrationtypesAWSAccountConfigDTO {
|
||||
/**
|
||||
* @type array
|
||||
@@ -3144,6 +3186,24 @@ export interface TypesStorableAPIKeyDTO {
|
||||
userId?: string;
|
||||
}
|
||||
|
||||
export interface TypesUpdatableSelfUserDTO {
|
||||
/**
|
||||
* @type string
|
||||
*/
|
||||
displayName: string;
|
||||
}
|
||||
|
||||
export interface TypesUpdatableUserDTO {
|
||||
/**
|
||||
* @type string
|
||||
*/
|
||||
displayName: string;
|
||||
/**
|
||||
* @type array
|
||||
*/
|
||||
roleNames: string[];
|
||||
}
|
||||
|
||||
export interface TypesUserDTO {
|
||||
/**
|
||||
* @type string
|
||||
@@ -4183,6 +4243,20 @@ export type Readyz503 = {
|
||||
status: string;
|
||||
};
|
||||
|
||||
export type GetUsersByRoleIDPathParameters = {
|
||||
id: string;
|
||||
};
|
||||
export type GetUsersByRoleID200 = {
|
||||
/**
|
||||
* @type array
|
||||
*/
|
||||
data: TypesUserDTO[];
|
||||
/**
|
||||
* @type string
|
||||
*/
|
||||
status: string;
|
||||
};
|
||||
|
||||
export type GetSessionContext200 = {
|
||||
data: AuthtypesSessionContextDTO;
|
||||
/**
|
||||
@@ -4207,6 +4281,53 @@ export type RotateSession200 = {
|
||||
status: string;
|
||||
};
|
||||
|
||||
export type ListUsersV2200 = {
|
||||
/**
|
||||
* @type array
|
||||
*/
|
||||
data: TypesUserDTO[];
|
||||
/**
|
||||
* @type string
|
||||
*/
|
||||
status: string;
|
||||
};
|
||||
|
||||
export type GetUserV2PathParameters = {
|
||||
id: string;
|
||||
};
|
||||
export type GetUserV2200 = {
|
||||
data: TypesUserDTO;
|
||||
/**
|
||||
* @type string
|
||||
*/
|
||||
status: string;
|
||||
};
|
||||
|
||||
export type UpdateUserV2PathParameters = {
|
||||
id: string;
|
||||
};
|
||||
export type GetUserRolesPathParameters = {
|
||||
id: string;
|
||||
};
|
||||
export type GetUserRoles200 = {
|
||||
/**
|
||||
* @type array
|
||||
*/
|
||||
data: AuthtypesRoleDTO[];
|
||||
/**
|
||||
* @type string
|
||||
*/
|
||||
status: string;
|
||||
};
|
||||
|
||||
export type GetMyUserV2200 = {
|
||||
data: AuthtypesUserWithRolesDTO;
|
||||
/**
|
||||
* @type string
|
||||
*/
|
||||
status: string;
|
||||
};
|
||||
|
||||
export type GetHosts200 = {
|
||||
data: ZeustypesGettableHostDTO;
|
||||
/**
|
||||
|
||||
@@ -25,12 +25,20 @@ import type {
|
||||
CreateInvite201,
|
||||
DeleteUserPathParameters,
|
||||
GetMyUser200,
|
||||
GetMyUserV2200,
|
||||
GetResetPasswordToken200,
|
||||
GetResetPasswordTokenPathParameters,
|
||||
GetUser200,
|
||||
GetUserPathParameters,
|
||||
GetUserRoles200,
|
||||
GetUserRolesPathParameters,
|
||||
GetUsersByRoleID200,
|
||||
GetUsersByRoleIDPathParameters,
|
||||
GetUserV2PathParameters,
|
||||
GetUserV2200,
|
||||
ListAPIKeys200,
|
||||
ListUsers200,
|
||||
ListUsersV2200,
|
||||
RenderErrorResponseDTO,
|
||||
RevokeAPIKeyPathParameters,
|
||||
TypesChangePasswordRequestDTO,
|
||||
@@ -41,9 +49,12 @@ import type {
|
||||
TypesPostableInviteDTO,
|
||||
TypesPostableResetPasswordDTO,
|
||||
TypesStorableAPIKeyDTO,
|
||||
TypesUpdatableSelfUserDTO,
|
||||
TypesUpdatableUserDTO,
|
||||
UpdateAPIKeyPathParameters,
|
||||
UpdateUser200,
|
||||
UpdateUserPathParameters,
|
||||
UpdateUserV2PathParameters,
|
||||
} from '../sigNoz.schemas';
|
||||
|
||||
/**
|
||||
@@ -1345,3 +1356,648 @@ export const useForgotPassword = <
|
||||
|
||||
return useMutation(mutationOptions);
|
||||
};
|
||||
/**
|
||||
* This endpoint returns the users having the role by role id
|
||||
* @summary Get users by role id
|
||||
*/
|
||||
export const getUsersByRoleID = (
|
||||
{ id }: GetUsersByRoleIDPathParameters,
|
||||
signal?: AbortSignal,
|
||||
) => {
|
||||
return GeneratedAPIInstance<GetUsersByRoleID200>({
|
||||
url: `/api/v2/roles/${id}/users`,
|
||||
method: 'GET',
|
||||
signal,
|
||||
});
|
||||
};
|
||||
|
||||
export const getGetUsersByRoleIDQueryKey = ({
|
||||
id,
|
||||
}: GetUsersByRoleIDPathParameters) => {
|
||||
return [`/api/v2/roles/${id}/users`] as const;
|
||||
};
|
||||
|
||||
export const getGetUsersByRoleIDQueryOptions = <
|
||||
TData = Awaited<ReturnType<typeof getUsersByRoleID>>,
|
||||
TError = ErrorType<RenderErrorResponseDTO>
|
||||
>(
|
||||
{ id }: GetUsersByRoleIDPathParameters,
|
||||
options?: {
|
||||
query?: UseQueryOptions<
|
||||
Awaited<ReturnType<typeof getUsersByRoleID>>,
|
||||
TError,
|
||||
TData
|
||||
>;
|
||||
},
|
||||
) => {
|
||||
const { query: queryOptions } = options ?? {};
|
||||
|
||||
const queryKey = queryOptions?.queryKey ?? getGetUsersByRoleIDQueryKey({ id });
|
||||
|
||||
const queryFn: QueryFunction<Awaited<ReturnType<typeof getUsersByRoleID>>> = ({
|
||||
signal,
|
||||
}) => getUsersByRoleID({ id }, signal);
|
||||
|
||||
return {
|
||||
queryKey,
|
||||
queryFn,
|
||||
enabled: !!id,
|
||||
...queryOptions,
|
||||
} as UseQueryOptions<
|
||||
Awaited<ReturnType<typeof getUsersByRoleID>>,
|
||||
TError,
|
||||
TData
|
||||
> & { queryKey: QueryKey };
|
||||
};
|
||||
|
||||
export type GetUsersByRoleIDQueryResult = NonNullable<
|
||||
Awaited<ReturnType<typeof getUsersByRoleID>>
|
||||
>;
|
||||
export type GetUsersByRoleIDQueryError = ErrorType<RenderErrorResponseDTO>;
|
||||
|
||||
/**
|
||||
* @summary Get users by role id
|
||||
*/
|
||||
|
||||
export function useGetUsersByRoleID<
|
||||
TData = Awaited<ReturnType<typeof getUsersByRoleID>>,
|
||||
TError = ErrorType<RenderErrorResponseDTO>
|
||||
>(
|
||||
{ id }: GetUsersByRoleIDPathParameters,
|
||||
options?: {
|
||||
query?: UseQueryOptions<
|
||||
Awaited<ReturnType<typeof getUsersByRoleID>>,
|
||||
TError,
|
||||
TData
|
||||
>;
|
||||
},
|
||||
): UseQueryResult<TData, TError> & { queryKey: QueryKey } {
|
||||
const queryOptions = getGetUsersByRoleIDQueryOptions({ id }, options);
|
||||
|
||||
const query = useQuery(queryOptions) as UseQueryResult<TData, TError> & {
|
||||
queryKey: QueryKey;
|
||||
};
|
||||
|
||||
query.queryKey = queryOptions.queryKey;
|
||||
|
||||
return query;
|
||||
}
|
||||
|
||||
/**
|
||||
* @summary Get users by role id
|
||||
*/
|
||||
export const invalidateGetUsersByRoleID = async (
|
||||
queryClient: QueryClient,
|
||||
{ id }: GetUsersByRoleIDPathParameters,
|
||||
options?: InvalidateOptions,
|
||||
): Promise<QueryClient> => {
|
||||
await queryClient.invalidateQueries(
|
||||
{ queryKey: getGetUsersByRoleIDQueryKey({ id }) },
|
||||
options,
|
||||
);
|
||||
|
||||
return queryClient;
|
||||
};
|
||||
|
||||
/**
|
||||
* This endpoint lists all users for the organization
|
||||
* @summary List users v2
|
||||
*/
|
||||
export const listUsersV2 = (signal?: AbortSignal) => {
|
||||
return GeneratedAPIInstance<ListUsersV2200>({
|
||||
url: `/api/v2/users`,
|
||||
method: 'GET',
|
||||
signal,
|
||||
});
|
||||
};
|
||||
|
||||
export const getListUsersV2QueryKey = () => {
|
||||
return [`/api/v2/users`] as const;
|
||||
};
|
||||
|
||||
export const getListUsersV2QueryOptions = <
|
||||
TData = Awaited<ReturnType<typeof listUsersV2>>,
|
||||
TError = ErrorType<RenderErrorResponseDTO>
|
||||
>(options?: {
|
||||
query?: UseQueryOptions<
|
||||
Awaited<ReturnType<typeof listUsersV2>>,
|
||||
TError,
|
||||
TData
|
||||
>;
|
||||
}) => {
|
||||
const { query: queryOptions } = options ?? {};
|
||||
|
||||
const queryKey = queryOptions?.queryKey ?? getListUsersV2QueryKey();
|
||||
|
||||
const queryFn: QueryFunction<Awaited<ReturnType<typeof listUsersV2>>> = ({
|
||||
signal,
|
||||
}) => listUsersV2(signal);
|
||||
|
||||
return { queryKey, queryFn, ...queryOptions } as UseQueryOptions<
|
||||
Awaited<ReturnType<typeof listUsersV2>>,
|
||||
TError,
|
||||
TData
|
||||
> & { queryKey: QueryKey };
|
||||
};
|
||||
|
||||
export type ListUsersV2QueryResult = NonNullable<
|
||||
Awaited<ReturnType<typeof listUsersV2>>
|
||||
>;
|
||||
export type ListUsersV2QueryError = ErrorType<RenderErrorResponseDTO>;
|
||||
|
||||
/**
|
||||
* @summary List users v2
|
||||
*/
|
||||
|
||||
export function useListUsersV2<
|
||||
TData = Awaited<ReturnType<typeof listUsersV2>>,
|
||||
TError = ErrorType<RenderErrorResponseDTO>
|
||||
>(options?: {
|
||||
query?: UseQueryOptions<
|
||||
Awaited<ReturnType<typeof listUsersV2>>,
|
||||
TError,
|
||||
TData
|
||||
>;
|
||||
}): UseQueryResult<TData, TError> & { queryKey: QueryKey } {
|
||||
const queryOptions = getListUsersV2QueryOptions(options);
|
||||
|
||||
const query = useQuery(queryOptions) as UseQueryResult<TData, TError> & {
|
||||
queryKey: QueryKey;
|
||||
};
|
||||
|
||||
query.queryKey = queryOptions.queryKey;
|
||||
|
||||
return query;
|
||||
}
|
||||
|
||||
/**
|
||||
* @summary List users v2
|
||||
*/
|
||||
export const invalidateListUsersV2 = async (
|
||||
queryClient: QueryClient,
|
||||
options?: InvalidateOptions,
|
||||
): Promise<QueryClient> => {
|
||||
await queryClient.invalidateQueries(
|
||||
{ queryKey: getListUsersV2QueryKey() },
|
||||
options,
|
||||
);
|
||||
|
||||
return queryClient;
|
||||
};
|
||||
|
||||
/**
|
||||
* This endpoint returns the user by id
|
||||
* @summary Get user by user id
|
||||
*/
|
||||
export const getUserV2 = (
|
||||
{ id }: GetUserV2PathParameters,
|
||||
signal?: AbortSignal,
|
||||
) => {
|
||||
return GeneratedAPIInstance<GetUserV2200>({
|
||||
url: `/api/v2/users/${id}`,
|
||||
method: 'GET',
|
||||
signal,
|
||||
});
|
||||
};
|
||||
|
||||
export const getGetUserV2QueryKey = ({ id }: GetUserV2PathParameters) => {
|
||||
return [`/api/v2/users/${id}`] as const;
|
||||
};
|
||||
|
||||
export const getGetUserV2QueryOptions = <
|
||||
TData = Awaited<ReturnType<typeof getUserV2>>,
|
||||
TError = ErrorType<RenderErrorResponseDTO>
|
||||
>(
|
||||
{ id }: GetUserV2PathParameters,
|
||||
options?: {
|
||||
query?: UseQueryOptions<Awaited<ReturnType<typeof getUserV2>>, TError, TData>;
|
||||
},
|
||||
) => {
|
||||
const { query: queryOptions } = options ?? {};
|
||||
|
||||
const queryKey = queryOptions?.queryKey ?? getGetUserV2QueryKey({ id });
|
||||
|
||||
const queryFn: QueryFunction<Awaited<ReturnType<typeof getUserV2>>> = ({
|
||||
signal,
|
||||
}) => getUserV2({ id }, signal);
|
||||
|
||||
return {
|
||||
queryKey,
|
||||
queryFn,
|
||||
enabled: !!id,
|
||||
...queryOptions,
|
||||
} as UseQueryOptions<Awaited<ReturnType<typeof getUserV2>>, TError, TData> & {
|
||||
queryKey: QueryKey;
|
||||
};
|
||||
};
|
||||
|
||||
export type GetUserV2QueryResult = NonNullable<
|
||||
Awaited<ReturnType<typeof getUserV2>>
|
||||
>;
|
||||
export type GetUserV2QueryError = ErrorType<RenderErrorResponseDTO>;
|
||||
|
||||
/**
|
||||
* @summary Get user by user id
|
||||
*/
|
||||
|
||||
export function useGetUserV2<
|
||||
TData = Awaited<ReturnType<typeof getUserV2>>,
|
||||
TError = ErrorType<RenderErrorResponseDTO>
|
||||
>(
|
||||
{ id }: GetUserV2PathParameters,
|
||||
options?: {
|
||||
query?: UseQueryOptions<Awaited<ReturnType<typeof getUserV2>>, TError, TData>;
|
||||
},
|
||||
): UseQueryResult<TData, TError> & { queryKey: QueryKey } {
|
||||
const queryOptions = getGetUserV2QueryOptions({ id }, options);
|
||||
|
||||
const query = useQuery(queryOptions) as UseQueryResult<TData, TError> & {
|
||||
queryKey: QueryKey;
|
||||
};
|
||||
|
||||
query.queryKey = queryOptions.queryKey;
|
||||
|
||||
return query;
|
||||
}
|
||||
|
||||
/**
|
||||
* @summary Get user by user id
|
||||
*/
|
||||
export const invalidateGetUserV2 = async (
|
||||
queryClient: QueryClient,
|
||||
{ id }: GetUserV2PathParameters,
|
||||
options?: InvalidateOptions,
|
||||
): Promise<QueryClient> => {
|
||||
await queryClient.invalidateQueries(
|
||||
{ queryKey: getGetUserV2QueryKey({ id }) },
|
||||
options,
|
||||
);
|
||||
|
||||
return queryClient;
|
||||
};
|
||||
|
||||
/**
|
||||
* This endpoint updates the user by id
|
||||
* @summary Update user v2
|
||||
*/
|
||||
export const updateUserV2 = (
|
||||
{ id }: UpdateUserV2PathParameters,
|
||||
typesUpdatableUserDTO: BodyType<TypesUpdatableUserDTO>,
|
||||
) => {
|
||||
return GeneratedAPIInstance<void>({
|
||||
url: `/api/v2/users/${id}`,
|
||||
method: 'PUT',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
data: typesUpdatableUserDTO,
|
||||
});
|
||||
};
|
||||
|
||||
export const getUpdateUserV2MutationOptions = <
|
||||
TError = ErrorType<RenderErrorResponseDTO>,
|
||||
TContext = unknown
|
||||
>(options?: {
|
||||
mutation?: UseMutationOptions<
|
||||
Awaited<ReturnType<typeof updateUserV2>>,
|
||||
TError,
|
||||
{
|
||||
pathParams: UpdateUserV2PathParameters;
|
||||
data: BodyType<TypesUpdatableUserDTO>;
|
||||
},
|
||||
TContext
|
||||
>;
|
||||
}): UseMutationOptions<
|
||||
Awaited<ReturnType<typeof updateUserV2>>,
|
||||
TError,
|
||||
{
|
||||
pathParams: UpdateUserV2PathParameters;
|
||||
data: BodyType<TypesUpdatableUserDTO>;
|
||||
},
|
||||
TContext
|
||||
> => {
|
||||
const mutationKey = ['updateUserV2'];
|
||||
const { mutation: mutationOptions } = options
|
||||
? options.mutation &&
|
||||
'mutationKey' in options.mutation &&
|
||||
options.mutation.mutationKey
|
||||
? options
|
||||
: { ...options, mutation: { ...options.mutation, mutationKey } }
|
||||
: { mutation: { mutationKey } };
|
||||
|
||||
const mutationFn: MutationFunction<
|
||||
Awaited<ReturnType<typeof updateUserV2>>,
|
||||
{
|
||||
pathParams: UpdateUserV2PathParameters;
|
||||
data: BodyType<TypesUpdatableUserDTO>;
|
||||
}
|
||||
> = (props) => {
|
||||
const { pathParams, data } = props ?? {};
|
||||
|
||||
return updateUserV2(pathParams, data);
|
||||
};
|
||||
|
||||
return { mutationFn, ...mutationOptions };
|
||||
};
|
||||
|
||||
export type UpdateUserV2MutationResult = NonNullable<
|
||||
Awaited<ReturnType<typeof updateUserV2>>
|
||||
>;
|
||||
export type UpdateUserV2MutationBody = BodyType<TypesUpdatableUserDTO>;
|
||||
export type UpdateUserV2MutationError = ErrorType<RenderErrorResponseDTO>;
|
||||
|
||||
/**
|
||||
* @summary Update user v2
|
||||
*/
|
||||
export const useUpdateUserV2 = <
|
||||
TError = ErrorType<RenderErrorResponseDTO>,
|
||||
TContext = unknown
|
||||
>(options?: {
|
||||
mutation?: UseMutationOptions<
|
||||
Awaited<ReturnType<typeof updateUserV2>>,
|
||||
TError,
|
||||
{
|
||||
pathParams: UpdateUserV2PathParameters;
|
||||
data: BodyType<TypesUpdatableUserDTO>;
|
||||
},
|
||||
TContext
|
||||
>;
|
||||
}): UseMutationResult<
|
||||
Awaited<ReturnType<typeof updateUserV2>>,
|
||||
TError,
|
||||
{
|
||||
pathParams: UpdateUserV2PathParameters;
|
||||
data: BodyType<TypesUpdatableUserDTO>;
|
||||
},
|
||||
TContext
|
||||
> => {
|
||||
const mutationOptions = getUpdateUserV2MutationOptions(options);
|
||||
|
||||
return useMutation(mutationOptions);
|
||||
};
|
||||
/**
|
||||
* This endpoint returns the user roles by user id
|
||||
* @summary Get user roles
|
||||
*/
|
||||
export const getUserRoles = (
|
||||
{ id }: GetUserRolesPathParameters,
|
||||
signal?: AbortSignal,
|
||||
) => {
|
||||
return GeneratedAPIInstance<GetUserRoles200>({
|
||||
url: `/api/v2/users/${id}/roles`,
|
||||
method: 'GET',
|
||||
signal,
|
||||
});
|
||||
};
|
||||
|
||||
export const getGetUserRolesQueryKey = ({ id }: GetUserRolesPathParameters) => {
|
||||
return [`/api/v2/users/${id}/roles`] as const;
|
||||
};
|
||||
|
||||
export const getGetUserRolesQueryOptions = <
|
||||
TData = Awaited<ReturnType<typeof getUserRoles>>,
|
||||
TError = ErrorType<RenderErrorResponseDTO>
|
||||
>(
|
||||
{ id }: GetUserRolesPathParameters,
|
||||
options?: {
|
||||
query?: UseQueryOptions<
|
||||
Awaited<ReturnType<typeof getUserRoles>>,
|
||||
TError,
|
||||
TData
|
||||
>;
|
||||
},
|
||||
) => {
|
||||
const { query: queryOptions } = options ?? {};
|
||||
|
||||
const queryKey = queryOptions?.queryKey ?? getGetUserRolesQueryKey({ id });
|
||||
|
||||
const queryFn: QueryFunction<Awaited<ReturnType<typeof getUserRoles>>> = ({
|
||||
signal,
|
||||
}) => getUserRoles({ id }, signal);
|
||||
|
||||
return {
|
||||
queryKey,
|
||||
queryFn,
|
||||
enabled: !!id,
|
||||
...queryOptions,
|
||||
} as UseQueryOptions<
|
||||
Awaited<ReturnType<typeof getUserRoles>>,
|
||||
TError,
|
||||
TData
|
||||
> & { queryKey: QueryKey };
|
||||
};
|
||||
|
||||
export type GetUserRolesQueryResult = NonNullable<
|
||||
Awaited<ReturnType<typeof getUserRoles>>
|
||||
>;
|
||||
export type GetUserRolesQueryError = ErrorType<RenderErrorResponseDTO>;
|
||||
|
||||
/**
|
||||
* @summary Get user roles
|
||||
*/
|
||||
|
||||
export function useGetUserRoles<
|
||||
TData = Awaited<ReturnType<typeof getUserRoles>>,
|
||||
TError = ErrorType<RenderErrorResponseDTO>
|
||||
>(
|
||||
{ id }: GetUserRolesPathParameters,
|
||||
options?: {
|
||||
query?: UseQueryOptions<
|
||||
Awaited<ReturnType<typeof getUserRoles>>,
|
||||
TError,
|
||||
TData
|
||||
>;
|
||||
},
|
||||
): UseQueryResult<TData, TError> & { queryKey: QueryKey } {
|
||||
const queryOptions = getGetUserRolesQueryOptions({ id }, options);
|
||||
|
||||
const query = useQuery(queryOptions) as UseQueryResult<TData, TError> & {
|
||||
queryKey: QueryKey;
|
||||
};
|
||||
|
||||
query.queryKey = queryOptions.queryKey;
|
||||
|
||||
return query;
|
||||
}
|
||||
|
||||
/**
|
||||
* @summary Get user roles
|
||||
*/
|
||||
export const invalidateGetUserRoles = async (
|
||||
queryClient: QueryClient,
|
||||
{ id }: GetUserRolesPathParameters,
|
||||
options?: InvalidateOptions,
|
||||
): Promise<QueryClient> => {
|
||||
await queryClient.invalidateQueries(
|
||||
{ queryKey: getGetUserRolesQueryKey({ id }) },
|
||||
options,
|
||||
);
|
||||
|
||||
return queryClient;
|
||||
};
|
||||
|
||||
/**
|
||||
* This endpoint returns the user I belong to
|
||||
* @summary Get my user v2
|
||||
*/
|
||||
export const getMyUserV2 = (signal?: AbortSignal) => {
|
||||
return GeneratedAPIInstance<GetMyUserV2200>({
|
||||
url: `/api/v2/users/me`,
|
||||
method: 'GET',
|
||||
signal,
|
||||
});
|
||||
};
|
||||
|
||||
export const getGetMyUserV2QueryKey = () => {
|
||||
return [`/api/v2/users/me`] as const;
|
||||
};
|
||||
|
||||
export const getGetMyUserV2QueryOptions = <
|
||||
TData = Awaited<ReturnType<typeof getMyUserV2>>,
|
||||
TError = ErrorType<RenderErrorResponseDTO>
|
||||
>(options?: {
|
||||
query?: UseQueryOptions<
|
||||
Awaited<ReturnType<typeof getMyUserV2>>,
|
||||
TError,
|
||||
TData
|
||||
>;
|
||||
}) => {
|
||||
const { query: queryOptions } = options ?? {};
|
||||
|
||||
const queryKey = queryOptions?.queryKey ?? getGetMyUserV2QueryKey();
|
||||
|
||||
const queryFn: QueryFunction<Awaited<ReturnType<typeof getMyUserV2>>> = ({
|
||||
signal,
|
||||
}) => getMyUserV2(signal);
|
||||
|
||||
return { queryKey, queryFn, ...queryOptions } as UseQueryOptions<
|
||||
Awaited<ReturnType<typeof getMyUserV2>>,
|
||||
TError,
|
||||
TData
|
||||
> & { queryKey: QueryKey };
|
||||
};
|
||||
|
||||
export type GetMyUserV2QueryResult = NonNullable<
|
||||
Awaited<ReturnType<typeof getMyUserV2>>
|
||||
>;
|
||||
export type GetMyUserV2QueryError = ErrorType<RenderErrorResponseDTO>;
|
||||
|
||||
/**
|
||||
* @summary Get my user v2
|
||||
*/
|
||||
|
||||
export function useGetMyUserV2<
|
||||
TData = Awaited<ReturnType<typeof getMyUserV2>>,
|
||||
TError = ErrorType<RenderErrorResponseDTO>
|
||||
>(options?: {
|
||||
query?: UseQueryOptions<
|
||||
Awaited<ReturnType<typeof getMyUserV2>>,
|
||||
TError,
|
||||
TData
|
||||
>;
|
||||
}): UseQueryResult<TData, TError> & { queryKey: QueryKey } {
|
||||
const queryOptions = getGetMyUserV2QueryOptions(options);
|
||||
|
||||
const query = useQuery(queryOptions) as UseQueryResult<TData, TError> & {
|
||||
queryKey: QueryKey;
|
||||
};
|
||||
|
||||
query.queryKey = queryOptions.queryKey;
|
||||
|
||||
return query;
|
||||
}
|
||||
|
||||
/**
|
||||
* @summary Get my user v2
|
||||
*/
|
||||
export const invalidateGetMyUserV2 = async (
|
||||
queryClient: QueryClient,
|
||||
options?: InvalidateOptions,
|
||||
): Promise<QueryClient> => {
|
||||
await queryClient.invalidateQueries(
|
||||
{ queryKey: getGetMyUserV2QueryKey() },
|
||||
options,
|
||||
);
|
||||
|
||||
return queryClient;
|
||||
};
|
||||
|
||||
/**
|
||||
* This endpoint updates the user I belong to
|
||||
* @summary Update my user v2
|
||||
*/
|
||||
export const updateMyUserV2 = (
|
||||
typesUpdatableSelfUserDTO: BodyType<TypesUpdatableSelfUserDTO>,
|
||||
) => {
|
||||
return GeneratedAPIInstance<void>({
|
||||
url: `/api/v2/users/me`,
|
||||
method: 'PUT',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
data: typesUpdatableSelfUserDTO,
|
||||
});
|
||||
};
|
||||
|
||||
export const getUpdateMyUserV2MutationOptions = <
|
||||
TError = ErrorType<RenderErrorResponseDTO>,
|
||||
TContext = unknown
|
||||
>(options?: {
|
||||
mutation?: UseMutationOptions<
|
||||
Awaited<ReturnType<typeof updateMyUserV2>>,
|
||||
TError,
|
||||
{ data: BodyType<TypesUpdatableSelfUserDTO> },
|
||||
TContext
|
||||
>;
|
||||
}): UseMutationOptions<
|
||||
Awaited<ReturnType<typeof updateMyUserV2>>,
|
||||
TError,
|
||||
{ data: BodyType<TypesUpdatableSelfUserDTO> },
|
||||
TContext
|
||||
> => {
|
||||
const mutationKey = ['updateMyUserV2'];
|
||||
const { mutation: mutationOptions } = options
|
||||
? options.mutation &&
|
||||
'mutationKey' in options.mutation &&
|
||||
options.mutation.mutationKey
|
||||
? options
|
||||
: { ...options, mutation: { ...options.mutation, mutationKey } }
|
||||
: { mutation: { mutationKey } };
|
||||
|
||||
const mutationFn: MutationFunction<
|
||||
Awaited<ReturnType<typeof updateMyUserV2>>,
|
||||
{ data: BodyType<TypesUpdatableSelfUserDTO> }
|
||||
> = (props) => {
|
||||
const { data } = props ?? {};
|
||||
|
||||
return updateMyUserV2(data);
|
||||
};
|
||||
|
||||
return { mutationFn, ...mutationOptions };
|
||||
};
|
||||
|
||||
export type UpdateMyUserV2MutationResult = NonNullable<
|
||||
Awaited<ReturnType<typeof updateMyUserV2>>
|
||||
>;
|
||||
export type UpdateMyUserV2MutationBody = BodyType<TypesUpdatableSelfUserDTO>;
|
||||
export type UpdateMyUserV2MutationError = ErrorType<RenderErrorResponseDTO>;
|
||||
|
||||
/**
|
||||
* @summary Update my user v2
|
||||
*/
|
||||
export const useUpdateMyUserV2 = <
|
||||
TError = ErrorType<RenderErrorResponseDTO>,
|
||||
TContext = unknown
|
||||
>(options?: {
|
||||
mutation?: UseMutationOptions<
|
||||
Awaited<ReturnType<typeof updateMyUserV2>>,
|
||||
TError,
|
||||
{ data: BodyType<TypesUpdatableSelfUserDTO> },
|
||||
TContext
|
||||
>;
|
||||
}): UseMutationResult<
|
||||
Awaited<ReturnType<typeof updateMyUserV2>>,
|
||||
TError,
|
||||
{ data: BodyType<TypesUpdatableSelfUserDTO> },
|
||||
TContext
|
||||
> => {
|
||||
const mutationOptions = getUpdateMyUserV2MutationOptions(options);
|
||||
|
||||
return useMutation(mutationOptions);
|
||||
};
|
||||
|
||||
@@ -62,9 +62,6 @@ export const getVolumeQueryPayload = (
|
||||
const k8sPVCNameKey = dotMetricsEnabled
|
||||
? 'k8s.persistentvolumeclaim.name'
|
||||
: 'k8s_persistentvolumeclaim_name';
|
||||
const legendTemplate = dotMetricsEnabled
|
||||
? '{{k8s.namespace.name}}-{{k8s.pod.name}}'
|
||||
: '{{k8s_namespace_name}}-{{k8s_pod_name}}';
|
||||
|
||||
return [
|
||||
{
|
||||
@@ -136,7 +133,7 @@ export const getVolumeQueryPayload = (
|
||||
functions: [],
|
||||
groupBy: [],
|
||||
having: [],
|
||||
legend: legendTemplate,
|
||||
legend: 'Available',
|
||||
limit: null,
|
||||
orderBy: [],
|
||||
queryName: 'A',
|
||||
@@ -228,7 +225,7 @@ export const getVolumeQueryPayload = (
|
||||
functions: [],
|
||||
groupBy: [],
|
||||
having: [],
|
||||
legend: legendTemplate,
|
||||
legend: 'Capacity',
|
||||
limit: null,
|
||||
orderBy: [],
|
||||
queryName: 'A',
|
||||
@@ -319,7 +316,7 @@ export const getVolumeQueryPayload = (
|
||||
},
|
||||
groupBy: [],
|
||||
having: [],
|
||||
legend: legendTemplate,
|
||||
legend: 'Inodes Used',
|
||||
limit: null,
|
||||
orderBy: [],
|
||||
queryName: 'A',
|
||||
@@ -411,7 +408,7 @@ export const getVolumeQueryPayload = (
|
||||
},
|
||||
groupBy: [],
|
||||
having: [],
|
||||
legend: legendTemplate,
|
||||
legend: 'Total Inodes',
|
||||
limit: null,
|
||||
orderBy: [],
|
||||
queryName: 'A',
|
||||
@@ -503,7 +500,7 @@ export const getVolumeQueryPayload = (
|
||||
},
|
||||
groupBy: [],
|
||||
having: [],
|
||||
legend: legendTemplate,
|
||||
legend: 'Inodes Free',
|
||||
limit: null,
|
||||
orderBy: [],
|
||||
queryName: 'A',
|
||||
|
||||
@@ -1,115 +0,0 @@
|
||||
package common
|
||||
|
||||
// ──────────────────────────────────────────────
|
||||
// Shared types
|
||||
// ──────────────────────────────────────────────
|
||||
|
||||
#TelemetryFieldKey: {
|
||||
name: string
|
||||
key?: string
|
||||
description?: string
|
||||
unit?: string
|
||||
signal?: string
|
||||
fieldContext?: string
|
||||
fieldDataType?: string
|
||||
materialized?: bool
|
||||
isIndexed?: bool
|
||||
}
|
||||
|
||||
// ──────────────────────────────────────────────
|
||||
// Panel types
|
||||
// ──────────────────────────────────────────────
|
||||
|
||||
#ContextLinkProps: {
|
||||
url: string
|
||||
label: string
|
||||
}
|
||||
|
||||
#TimePreference: *"globalTime" | "last5Min" | "last15Min" | "last30Min" | "last1Hr" | "last6Hr" | "last1Day" | "last3Days" | "last1Week" | "last1Month"
|
||||
|
||||
#PrecisionOption: *2 | 0 | 1 | 3 | 4 | "full"
|
||||
|
||||
#Axes: {
|
||||
softMin?: number | *null
|
||||
softMax?: number | *null
|
||||
isLogScale?: bool | *false
|
||||
}
|
||||
|
||||
#LegendPosition: *"bottom" | "right"
|
||||
|
||||
#ThresholdWithLabel: {
|
||||
value: number
|
||||
unit?: string
|
||||
color: string
|
||||
format: "Text" | "Background"
|
||||
label?: string
|
||||
}
|
||||
|
||||
#ComparisonThreshold: {
|
||||
value: number
|
||||
operator: ">" | "<" | ">=" | "<=" | "="
|
||||
unit?: string
|
||||
color: string
|
||||
format: "Text" | "Background"
|
||||
}
|
||||
|
||||
// ──────────────────────────────────────────────
|
||||
// Query types
|
||||
// ──────────────────────────────────────────────
|
||||
|
||||
#QueryName: =~"^[A-Za-z][A-Za-z0-9_]*$"
|
||||
|
||||
#Limit: int & >=0 & <=10000
|
||||
|
||||
#Offset: int & >=0
|
||||
|
||||
#ReduceTo: "sum" | "count" | "avg" | "min" | "max" | "last" | "median"
|
||||
|
||||
#MetricAggregation: close({
|
||||
metricName: string & !=""
|
||||
timeAggregation: "latest" | "sum" | "avg" | "min" | "max" | "count" | "rate" | "increase"
|
||||
spaceAggregation: "sum" | "avg" | "min" | "max" | "count" | "p50" | "p75" | "p90" | "p95" | "p99"
|
||||
reduceTo?: #ReduceTo
|
||||
temporality?: "delta" | "cumulative" | "unspecified"
|
||||
})
|
||||
|
||||
#ExpressionAggregation: close({
|
||||
expression: string & !=""
|
||||
alias?: string
|
||||
})
|
||||
|
||||
#Aggregation: #MetricAggregation | #ExpressionAggregation
|
||||
|
||||
#FilterExpression: close({
|
||||
expression: string
|
||||
})
|
||||
|
||||
#GroupByItem: close({
|
||||
name: string & !=""
|
||||
fieldDataType?: string
|
||||
fieldContext?: string
|
||||
})
|
||||
|
||||
#OrderByItem: close({
|
||||
columnName: string & !=""
|
||||
order: "asc" | "desc"
|
||||
})
|
||||
|
||||
#HavingExpression: close({
|
||||
expression: string
|
||||
})
|
||||
|
||||
#Function: close({
|
||||
name: "cutOffMin" | "cutOffMax" | "clampMin" | "clampMax" |
|
||||
"absolute" | "runningDiff" | "log2" | "log10" |
|
||||
"cumulativeSum" | "ewma3" | "ewma5" | "ewma7" |
|
||||
"median3" | "median5" | "median7" | "timeShift" |
|
||||
"anomaly" | "fillZero"
|
||||
args?: [...close({value: number | string | bool})]
|
||||
})
|
||||
|
||||
// ──────────────────────────────────────────────
|
||||
// Variable types
|
||||
// ──────────────────────────────────────────────
|
||||
|
||||
#VariableSortOrder: *"disabled" | "asc" | "desc"
|
||||
@@ -1,4 +0,0 @@
|
||||
module: "github.com/signoz"
|
||||
language: {
|
||||
version: "v0.12.0"
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,868 +0,0 @@
|
||||
{
|
||||
"kind": "Dashboard",
|
||||
"metadata": {
|
||||
"name": "the-everything-dashboard",
|
||||
"project": "signoz"
|
||||
},
|
||||
"spec": {
|
||||
"display": {
|
||||
"name": "The everything dashboard",
|
||||
"description": "Trying to cover as many concepts here as possible"
|
||||
},
|
||||
"duration": "1h",
|
||||
"datasources": {
|
||||
"SigNozDatasource": {
|
||||
"default": true,
|
||||
"plugin": {
|
||||
"kind": "SigNozDatasource",
|
||||
"spec": {}
|
||||
}
|
||||
}
|
||||
},
|
||||
"variables": [
|
||||
{
|
||||
"kind": "ListVariable",
|
||||
"spec": {
|
||||
"name": "serviceName",
|
||||
"display": {
|
||||
"name": "serviceName"
|
||||
},
|
||||
"allowAllValue": true,
|
||||
"allowMultiple": false,
|
||||
"plugin": {
|
||||
"kind": "SigNozDynamicVariable",
|
||||
"spec": {
|
||||
"name": "service.name",
|
||||
"source": "Metrics",
|
||||
"sort": "disabled"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"kind": "ListVariable",
|
||||
"spec": {
|
||||
"name": "statusCodesFromQuery",
|
||||
"display": {
|
||||
"name": "statusCodesFromQuery"
|
||||
},
|
||||
"allowAllValue": true,
|
||||
"allowMultiple": true,
|
||||
"plugin": {
|
||||
"kind": "SigNozQueryVariable",
|
||||
"spec": {
|
||||
"queryValue": "SELECT JSONExtractString(labels, 'http.status_code') AS status_code FROM signoz_metrics.distributed_time_series_v4_1day WHERE status_code != '' GROUP BY status_code",
|
||||
"sort": "asc"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"kind": "ListVariable",
|
||||
"spec": {
|
||||
"name": "limit",
|
||||
"display": {
|
||||
"name": "limit"
|
||||
},
|
||||
"allowAllValue": false,
|
||||
"allowMultiple": false,
|
||||
"plugin": {
|
||||
"kind": "SigNozCustomVariable",
|
||||
"spec": {
|
||||
"customValue": "1,10,20,40,80,160,200",
|
||||
"sort": "disabled"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
],
|
||||
"panels": {
|
||||
"24e2697b": {
|
||||
"kind": "Panel",
|
||||
"spec": {
|
||||
"display": {
|
||||
"name": "total resp size",
|
||||
"description": ""
|
||||
},
|
||||
"plugin": {
|
||||
"kind": "SigNozTimeSeriesPanel",
|
||||
"spec": {
|
||||
"visualization": {
|
||||
"fillSpans": true
|
||||
},
|
||||
"formatting": {
|
||||
"unit": "By",
|
||||
"decimalPrecision": 3
|
||||
},
|
||||
"axes": {
|
||||
"softMax": 800,
|
||||
"isLogScale": true
|
||||
},
|
||||
"legend": {
|
||||
"position": "right",
|
||||
"customColors": {
|
||||
"{service.name=\"sampleapp-gateway\"}": "#9ea5f7"
|
||||
}
|
||||
},
|
||||
"contextLinks": [
|
||||
{
|
||||
"label": "View service details",
|
||||
"url": "http://localhost:8080/{{_service.name}}?dfddf=%7B%7Blimit%7D%7D"
|
||||
}
|
||||
],
|
||||
"thresholds": [
|
||||
{
|
||||
"value": 1024,
|
||||
"unit": "By",
|
||||
"color": "Red",
|
||||
"format": "Text",
|
||||
"label": "upper limit"
|
||||
},
|
||||
{
|
||||
"value": 100,
|
||||
"unit": "By",
|
||||
"color": "Orange",
|
||||
"format": "Text",
|
||||
"label": "kinda bad"
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"queries": [
|
||||
{
|
||||
"kind": "TimeSeriesQuery",
|
||||
"spec": {
|
||||
"plugin": {
|
||||
"kind": "SigNozBuilderQuery",
|
||||
"spec": {
|
||||
"name": "A",
|
||||
"signal": "metrics",
|
||||
"expression": "A",
|
||||
"aggregations": [
|
||||
{
|
||||
"metricName": "http.server.response.body.size.sum",
|
||||
"reduceTo": "sum",
|
||||
"spaceAggregation": "sum",
|
||||
"timeAggregation": "rate"
|
||||
}
|
||||
],
|
||||
"filter": {
|
||||
"expression": "http.response.status_code IN $statusCodesFromQuery"
|
||||
},
|
||||
"groupBy": [
|
||||
{
|
||||
"name": "service.name",
|
||||
"fieldDataType": "string",
|
||||
"fieldContext": "tag"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"ff2f72f1": {
|
||||
"kind": "Panel",
|
||||
"spec": {
|
||||
"display": {
|
||||
"name": "fraction of calls",
|
||||
"description": ""
|
||||
},
|
||||
"plugin": {
|
||||
"kind": "SigNozTimeSeriesPanel",
|
||||
"spec": {
|
||||
"visualization": {
|
||||
"fillSpans": true
|
||||
},
|
||||
"formatting": {
|
||||
"decimalPrecision": 1
|
||||
},
|
||||
"thresholds": [
|
||||
{
|
||||
"value": 1,
|
||||
"color": "Blue",
|
||||
"format": "Background",
|
||||
"label": "max possible"
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"queries": [
|
||||
{
|
||||
"kind": "TimeSeriesQuery",
|
||||
"spec": {
|
||||
"plugin": {
|
||||
"kind": "SigNozCompositeQuery",
|
||||
"spec": {
|
||||
"queries": [
|
||||
{
|
||||
"type": "builder_query",
|
||||
"spec": {
|
||||
"name": "A",
|
||||
"signal": "metrics",
|
||||
"expression": "A",
|
||||
"disabled": true,
|
||||
"aggregations": [
|
||||
{
|
||||
"metricName": "signoz_calls_total",
|
||||
"reduceTo": "sum",
|
||||
"spaceAggregation": "sum",
|
||||
"timeAggregation": "rate"
|
||||
}
|
||||
],
|
||||
"filter": {
|
||||
"expression": "service.name IN $serviceName AND http.status_code IN $statusCodesFromQuery"
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "builder_query",
|
||||
"spec": {
|
||||
"name": "B",
|
||||
"signal": "metrics",
|
||||
"expression": "B",
|
||||
"disabled": true,
|
||||
"aggregations": [
|
||||
{
|
||||
"metricName": "signoz_calls_total",
|
||||
"reduceTo": "sum",
|
||||
"spaceAggregation": "sum",
|
||||
"timeAggregation": "rate"
|
||||
}
|
||||
],
|
||||
"filter": {
|
||||
"expression": "service.name in $serviceName"
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "builder_formula",
|
||||
"spec": {
|
||||
"name": "F1",
|
||||
"expression": "A / B"
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"011605e7": {
|
||||
"kind": "Panel",
|
||||
"spec": {
|
||||
"display": {
|
||||
"name": "total resp size"
|
||||
},
|
||||
"plugin": {
|
||||
"kind": "SigNozBarChartPanel",
|
||||
"spec": {
|
||||
"visualization": {
|
||||
"stackedBarChart": false
|
||||
},
|
||||
"formatting": {
|
||||
"unit": "By"
|
||||
}
|
||||
}
|
||||
},
|
||||
"queries": [
|
||||
{
|
||||
"kind": "TimeSeriesQuery",
|
||||
"spec": {
|
||||
"plugin": {
|
||||
"kind": "SigNozBuilderQuery",
|
||||
"spec": {
|
||||
"name": "A",
|
||||
"signal": "metrics",
|
||||
"expression": "A",
|
||||
"aggregations": [
|
||||
{
|
||||
"metricName": "http.server.response.body.size.sum",
|
||||
"reduceTo": "sum",
|
||||
"spaceAggregation": "sum",
|
||||
"timeAggregation": "rate"
|
||||
}
|
||||
],
|
||||
"filter": {
|
||||
"expression": "http.response.status_code IN $statusCodesFromQuery"
|
||||
},
|
||||
"groupBy": [
|
||||
{
|
||||
"name": "service.name",
|
||||
"fieldDataType": "string",
|
||||
"fieldContext": "tag"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"e23516fc": {
|
||||
"kind": "Panel",
|
||||
"spec": {
|
||||
"display": {
|
||||
"name": "num traces for service"
|
||||
},
|
||||
"plugin": {
|
||||
"kind": "SigNozNumberPanel",
|
||||
"spec": {
|
||||
"formatting": {
|
||||
"unit": "none",
|
||||
"decimalPrecision": 1
|
||||
},
|
||||
"thresholds": [
|
||||
{
|
||||
"value": 1200000,
|
||||
"operator": ">",
|
||||
"unit": "none",
|
||||
"color": "Red",
|
||||
"format": "Text"
|
||||
},
|
||||
{
|
||||
"value": 1200000,
|
||||
"operator": "<=",
|
||||
"unit": "none",
|
||||
"color": "Green",
|
||||
"format": "Text"
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"queries": [
|
||||
{
|
||||
"kind": "TimeSeriesQuery",
|
||||
"spec": {
|
||||
"plugin": {
|
||||
"kind": "SigNozBuilderQuery",
|
||||
"spec": {
|
||||
"name": "A",
|
||||
"signal": "traces",
|
||||
"expression": "A",
|
||||
"aggregations": [
|
||||
{
|
||||
"expression": "count() "
|
||||
}
|
||||
],
|
||||
"filter": {
|
||||
"expression": "service.name = $serviceName "
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"130c8d6b": {
|
||||
"kind": "Panel",
|
||||
"spec": {
|
||||
"display": {
|
||||
"name": "num logs for service"
|
||||
},
|
||||
"plugin": {
|
||||
"kind": "SigNozNumberPanel",
|
||||
"spec": {
|
||||
"formatting": {
|
||||
"unit": "none",
|
||||
"decimalPrecision": 1
|
||||
}
|
||||
}
|
||||
},
|
||||
"queries": [
|
||||
{
|
||||
"kind": "TimeSeriesQuery",
|
||||
"spec": {
|
||||
"plugin": {
|
||||
"kind": "SigNozBuilderQuery",
|
||||
"spec": {
|
||||
"name": "A",
|
||||
"signal": "logs",
|
||||
"expression": "A",
|
||||
"aggregations": [
|
||||
{
|
||||
"expression": "count() "
|
||||
}
|
||||
],
|
||||
"filter": {
|
||||
"expression": "service.name = $serviceName "
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"246f7c6d": {
|
||||
"kind": "Panel",
|
||||
"spec": {
|
||||
"display": {
|
||||
"name": "num traces for service per resp code"
|
||||
},
|
||||
"plugin": {
|
||||
"kind": "SigNozPieChartPanel",
|
||||
"spec": {
|
||||
"formatting": {
|
||||
"decimalPrecision": 1
|
||||
},
|
||||
"legend": {
|
||||
"customColors": {
|
||||
"\"201\"": "#2bc051",
|
||||
"\"400\"": "#cc462e",
|
||||
"\"500\"": "#ff0000"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"queries": [
|
||||
{
|
||||
"kind": "TimeSeriesQuery",
|
||||
"spec": {
|
||||
"plugin": {
|
||||
"kind": "SigNozBuilderQuery",
|
||||
"spec": {
|
||||
"name": "A",
|
||||
"signal": "traces",
|
||||
"expression": "A",
|
||||
"aggregations": [
|
||||
{
|
||||
"expression": "count() "
|
||||
}
|
||||
],
|
||||
"filter": {
|
||||
"expression": "service.name = $serviceName isEntryPoint = 'true'"
|
||||
},
|
||||
"groupBy": [
|
||||
{
|
||||
"name": "http.response.status_code",
|
||||
"fieldDataType": "float64",
|
||||
"fieldContext": "tag"
|
||||
}
|
||||
],
|
||||
"legend": "\"{{http.response.status_code}}\""
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"21f7d4d0": {
|
||||
"kind": "Panel",
|
||||
"spec": {
|
||||
"display": {
|
||||
"name": "average latency per service"
|
||||
},
|
||||
"plugin": {
|
||||
"kind": "SigNozTablePanel",
|
||||
"spec": {
|
||||
"formatting": {
|
||||
"columnUnits": {
|
||||
"A": "s"
|
||||
}
|
||||
},
|
||||
"thresholds": [
|
||||
{
|
||||
"value": 1,
|
||||
"operator": ">",
|
||||
"unit": "min",
|
||||
"color": "Red",
|
||||
"format": "Text",
|
||||
"tableOptions": "A"
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"queries": [
|
||||
{
|
||||
"kind": "TimeSeriesQuery",
|
||||
"spec": {
|
||||
"plugin": {
|
||||
"kind": "SigNozClickHouseSQL",
|
||||
"spec": {
|
||||
"name": "A",
|
||||
"query": "WITH\n __spatial_aggregation_cte AS\n (\n SELECT\n toStartOfInterval(toDateTime(intDiv(unix_milli, 1000)), toIntervalSecond(60)) AS ts,\n `service.name`,\n le,\n sum(value) / 60 AS value\n FROM signoz_metrics.distributed_samples_v4 AS points\n INNER JOIN\n (\n SELECT\n fingerprint,\n JSONExtractString(labels, 'service.name') AS `service.name`,\n JSONExtractString(labels, 'le') AS le\n FROM signoz_metrics.time_series_v4\n WHERE (metric_name IN ('signoz_latency.bucket')) AND (LOWER(temporality) LIKE LOWER('delta')) AND (__normalized = 0)\n GROUP BY\n fingerprint,\n `service.name`,\n le\n ) AS filtered_time_series ON points.fingerprint = filtered_time_series.fingerprint\n WHERE metric_name IN ('signoz_latency.bucket')\n GROUP BY\n ts,\n `service.name`,\n le\n ),\n __histogramCTE AS\n (\n SELECT\n ts,\n `service.name`,\n histogramQuantile(arrayMap(x -> toFloat64(x), groupArray(le)), groupArray(value), 0.9) AS value\n FROM __spatial_aggregation_cte\n GROUP BY\n `service.name`,\n ts\n ORDER BY\n `service.name` ASC,\n ts ASC\n )\nSELECT\n `service.name` AS service,\n avg(value) AS A\nFROM __histogramCTE\nGROUP BY `service.name`"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"ad5fd556": {
|
||||
"kind": "Panel",
|
||||
"spec": {
|
||||
"display": {
|
||||
"name": "logs from service"
|
||||
},
|
||||
"plugin": {
|
||||
"kind": "SigNozListPanel",
|
||||
"spec": {
|
||||
"selectedLogFields": [
|
||||
{
|
||||
"name": "timestamp",
|
||||
"type": "log",
|
||||
"dataType": ""
|
||||
},
|
||||
{
|
||||
"name": "body",
|
||||
"type": "log",
|
||||
"dataType": ""
|
||||
},
|
||||
{
|
||||
"name": "error",
|
||||
"type": "",
|
||||
"dataType": "string"
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"queries": [
|
||||
{
|
||||
"kind": "LogQuery",
|
||||
"spec": {
|
||||
"plugin": {
|
||||
"kind": "SigNozBuilderQuery",
|
||||
"spec": {
|
||||
"name": "A",
|
||||
"signal": "logs",
|
||||
"expression": "A",
|
||||
"aggregations": [
|
||||
{
|
||||
"expression": "count() "
|
||||
}
|
||||
],
|
||||
"filter": {
|
||||
"expression": "service.name = $serviceName"
|
||||
},
|
||||
"groupBy": [],
|
||||
"order": [
|
||||
{
|
||||
"columnName": "timestamp",
|
||||
"order": "desc"
|
||||
},
|
||||
{
|
||||
"columnName": "id",
|
||||
"order": "desc"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"f07b59ee": {
|
||||
"kind": "Panel",
|
||||
"spec": {
|
||||
"display": {
|
||||
"name": "response size buckets"
|
||||
},
|
||||
"plugin": {
|
||||
"kind": "SigNozHistogramPanel",
|
||||
"spec": {
|
||||
"histogramBuckets": {
|
||||
"bucketCount": 60,
|
||||
"mergeAllActiveQueries": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"queries": [
|
||||
{
|
||||
"kind": "TimeSeriesQuery",
|
||||
"spec": {
|
||||
"plugin": {
|
||||
"kind": "SigNozBuilderQuery",
|
||||
"spec": {
|
||||
"name": "A",
|
||||
"signal": "metrics",
|
||||
"expression": "A",
|
||||
"aggregations": [
|
||||
{
|
||||
"metricName": "http.server.response.body.size.bucket",
|
||||
"reduceTo": "avg",
|
||||
"spaceAggregation": "p90",
|
||||
"timeAggregation": "rate"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"e1a41831": {
|
||||
"kind": "Panel",
|
||||
"spec": {
|
||||
"display": {
|
||||
"name": "trace operator",
|
||||
"description": ""
|
||||
},
|
||||
"plugin": {
|
||||
"kind": "SigNozTimeSeriesPanel",
|
||||
"spec": {
|
||||
"legend": {
|
||||
"position": "right"
|
||||
}
|
||||
}
|
||||
},
|
||||
"queries": [
|
||||
{
|
||||
"kind": "TimeSeriesQuery",
|
||||
"spec": {
|
||||
"plugin": {
|
||||
"kind": "SigNozCompositeQuery",
|
||||
"spec": {
|
||||
"queries": [
|
||||
{
|
||||
"type": "builder_query",
|
||||
"spec": {
|
||||
"name": "A",
|
||||
"signal": "traces",
|
||||
"expression": "A",
|
||||
"aggregations": [
|
||||
{
|
||||
"expression": "count() "
|
||||
}
|
||||
],
|
||||
"filter": {
|
||||
"expression": "service.name = 'sampleapp-gateway' "
|
||||
},
|
||||
"legend": "Gateway"
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "builder_query",
|
||||
"spec": {
|
||||
"name": "B",
|
||||
"signal": "traces",
|
||||
"expression": "B",
|
||||
"aggregations": [
|
||||
{
|
||||
"expression": "count() "
|
||||
}
|
||||
],
|
||||
"filter": {
|
||||
"expression": "http.response.status_code = 200"
|
||||
},
|
||||
"legend": "$serviceName"
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "builder_trace_operator",
|
||||
"spec": {
|
||||
"name": "T1",
|
||||
"expression": "A -> B ",
|
||||
"aggregations": [
|
||||
{
|
||||
"expression": "count()",
|
||||
"alias": "request_count"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"f0d70491": {
|
||||
"kind": "Panel",
|
||||
"spec": {
|
||||
"display": {
|
||||
"name": "no results in this promql",
|
||||
"description": ""
|
||||
},
|
||||
"plugin": {
|
||||
"kind": "SigNozTimeSeriesPanel",
|
||||
"spec": {}
|
||||
},
|
||||
"queries": [
|
||||
{
|
||||
"kind": "TimeSeriesQuery",
|
||||
"spec": {
|
||||
"plugin": {
|
||||
"kind": "SigNozCompositeQuery",
|
||||
"spec": {
|
||||
"queries": [
|
||||
{
|
||||
"type": "promql",
|
||||
"spec": {
|
||||
"name": "A",
|
||||
"query": "sum(rate(flask_exporter_info[5m]))"
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "promql",
|
||||
"spec": {
|
||||
"name": "B",
|
||||
"query": "sum(increase(flask_exporter_info[5m]))"
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"0e6eb4ca": {
|
||||
"kind": "Panel",
|
||||
"spec": {
|
||||
"display": {
|
||||
"name": "no results in this promql",
|
||||
"description": ""
|
||||
},
|
||||
"plugin": {
|
||||
"kind": "SigNozTimeSeriesPanel",
|
||||
"spec": {}
|
||||
},
|
||||
"queries": [
|
||||
{
|
||||
"kind": "TimeSeriesQuery",
|
||||
"spec": {
|
||||
"plugin": {
|
||||
"kind": "SigNozPromQLQuery",
|
||||
"spec": {
|
||||
"name": "A",
|
||||
"query": "sum(rate(flask_exporter_info[5m]))"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
},
|
||||
"layouts": [
|
||||
{
|
||||
"kind": "Grid",
|
||||
"spec": {
|
||||
"items": [
|
||||
{
|
||||
"x": 0,
|
||||
"y": 0,
|
||||
"width": 6,
|
||||
"height": 6,
|
||||
"content": {
|
||||
"$ref": "#/spec/panels/24e2697b"
|
||||
}
|
||||
},
|
||||
{
|
||||
"x": 6,
|
||||
"y": 0,
|
||||
"width": 6,
|
||||
"height": 6,
|
||||
"content": {
|
||||
"$ref": "#/spec/panels/ff2f72f1"
|
||||
}
|
||||
},
|
||||
{
|
||||
"x": 0,
|
||||
"y": 6,
|
||||
"width": 6,
|
||||
"height": 6,
|
||||
"content": {
|
||||
"$ref": "#/spec/panels/011605e7"
|
||||
}
|
||||
},
|
||||
{
|
||||
"x": 6,
|
||||
"y": 6,
|
||||
"width": 6,
|
||||
"height": 3,
|
||||
"content": {
|
||||
"$ref": "#/spec/panels/e23516fc"
|
||||
}
|
||||
},
|
||||
{
|
||||
"x": 6,
|
||||
"y": 9,
|
||||
"width": 6,
|
||||
"height": 3,
|
||||
"content": {
|
||||
"$ref": "#/spec/panels/130c8d6b"
|
||||
}
|
||||
},
|
||||
{
|
||||
"x": 0,
|
||||
"y": 12,
|
||||
"width": 6,
|
||||
"height": 6,
|
||||
"content": {
|
||||
"$ref": "#/spec/panels/246f7c6d"
|
||||
}
|
||||
},
|
||||
{
|
||||
"x": 6,
|
||||
"y": 12,
|
||||
"width": 6,
|
||||
"height": 6,
|
||||
"content": {
|
||||
"$ref": "#/spec/panels/21f7d4d0"
|
||||
}
|
||||
},
|
||||
{
|
||||
"x": 0,
|
||||
"y": 18,
|
||||
"width": 6,
|
||||
"height": 6,
|
||||
"content": {
|
||||
"$ref": "#/spec/panels/ad5fd556"
|
||||
}
|
||||
},
|
||||
{
|
||||
"x": 6,
|
||||
"y": 18,
|
||||
"width": 6,
|
||||
"height": 6,
|
||||
"content": {
|
||||
"$ref": "#/spec/panels/f07b59ee"
|
||||
}
|
||||
},
|
||||
{
|
||||
"x": 0,
|
||||
"y": 24,
|
||||
"width": 12,
|
||||
"height": 6,
|
||||
"content": {
|
||||
"$ref": "#/spec/panels/e1a41831"
|
||||
}
|
||||
},
|
||||
{
|
||||
"x": 0,
|
||||
"y": 30,
|
||||
"width": 6,
|
||||
"height": 6,
|
||||
"content": {
|
||||
"$ref": "#/spec/panels/f0d70491"
|
||||
}
|
||||
},
|
||||
{
|
||||
"x": 6,
|
||||
"y": 30,
|
||||
"width": 6,
|
||||
"height": 6,
|
||||
"content": {
|
||||
"$ref": "#/spec/panels/0e6eb4ca"
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
@@ -1,140 +0,0 @@
|
||||
# Adding a new panel plugin
|
||||
|
||||
This guide is for developers adding a new panel kind to the Perses schema. It covers the file structure you need to create, the shared types available in `common.cue`, and how to compose them into your panel's spec.
|
||||
|
||||
---
|
||||
|
||||
## 1. File structure
|
||||
|
||||
Create a new directory under `schemas-wrapper/schemas/` named after your panel:
|
||||
|
||||
```
|
||||
schemas-wrapper/schemas/your-panel-name/
|
||||
├── your-panel-name.cue # Schema definition
|
||||
└── example.json # Example JSON that validates against the schema
|
||||
```
|
||||
|
||||
The CUE file must use `package model` and declare a `kind` and `spec`:
|
||||
|
||||
```cue
|
||||
package model
|
||||
|
||||
import "github.com/signoz/common"
|
||||
|
||||
kind: "YourPanelName"
|
||||
spec: close({
|
||||
// your fields here
|
||||
})
|
||||
```
|
||||
|
||||
Register the panel in `schemas-wrapper/schemas/package.json` by adding an entry to the `plugins` array:
|
||||
|
||||
```json
|
||||
{
|
||||
"kind": "Panel",
|
||||
"spec": {
|
||||
"name": "YourPanelName"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 2. Available shared types from `common.cue`
|
||||
|
||||
These types are defined in `common/common.cue` and can be used via `import "github.com/signoz/common"`. Use them instead of redefining the same structures in your panel.
|
||||
|
||||
## 3. Defining your spec
|
||||
|
||||
Your spec is a `close({})` block containing the fields relevant to your panel. Pick from the shared types above and add panel-specific types as needed. Every field should be optional (suffixed with `?`) since a panel should be valid with just defaults.
|
||||
|
||||
### Typical patterns
|
||||
|
||||
**Panel with graphs** (has axes, legend, thresholds as reference lines):
|
||||
|
||||
```cue
|
||||
spec: close({
|
||||
visualization?: #Visualization
|
||||
formatting?: #Formatting
|
||||
axes?: common.#Axes
|
||||
legend?: #Legend
|
||||
contextLinks?: [...common.#ContextLinkProps]
|
||||
thresholds?: [...common.#ThresholdWithLabel]
|
||||
})
|
||||
```
|
||||
|
||||
**Panel with a single value** (no axes/legend, thresholds as conditional formatting):
|
||||
|
||||
```cue
|
||||
spec: close({
|
||||
visualization?: #Visualization
|
||||
formatting?: #Formatting
|
||||
contextLinks?: [...common.#ContextLinkProps]
|
||||
thresholds?: [...common.#ComparisonThreshold]
|
||||
})
|
||||
```
|
||||
|
||||
**Panel with custom data structure** (panel-specific fields only):
|
||||
|
||||
```cue
|
||||
spec: close({
|
||||
yourCustomConfig?: #YourCustomConfig
|
||||
contextLinks?: [...common.#ContextLinkProps]
|
||||
})
|
||||
```
|
||||
|
||||
### Defining panel-local types
|
||||
|
||||
Types that are specific to your panel (not reusable) should be defined in your CUE file, not in common. For example, `#Visualization` varies per panel because each panel has different rendering options:
|
||||
|
||||
```cue
|
||||
#Visualization: {
|
||||
timePreference?: common.#TimePreference
|
||||
yourCustomFlag?: bool | *false
|
||||
}
|
||||
```
|
||||
|
||||
If your panel needs a threshold type that extends a common one, embed it:
|
||||
|
||||
```cue
|
||||
#YourThreshold: {
|
||||
common.#ComparisonThreshold
|
||||
extraField: string
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 4. Writing the example JSON
|
||||
|
||||
Create an `example.json` that exercises all fields in your spec. This file is used for validation — `./validate.sh` will check it against your schema.
|
||||
|
||||
```json
|
||||
{
|
||||
"kind": "YourPanelName",
|
||||
"spec": {
|
||||
...
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Also add at least one panel using your new kind to `examples/perses.json` so it gets validated as part of a full dashboard.
|
||||
|
||||
---
|
||||
|
||||
## 5. Validation
|
||||
|
||||
Run `./validate.sh` from the `perses/` directory. It lints `examples/perses.json` against all registered schemas. If your schema or example has issues, the error will point to the specific field.
|
||||
|
||||
---
|
||||
|
||||
## Quick reference: existing panels and what they use
|
||||
|
||||
| Field | Time-series | Bar-chart | Number | Pie | Table | Histogram | List |
|
||||
|-------|:-----------:|:---------:|:------:|:---:|:-----:|:---------:|:----:|
|
||||
| `visualization` | yes | yes | yes | yes | yes | — | — |
|
||||
| `formatting` | yes | yes | yes | yes | yes | — | — |
|
||||
| `axes` | yes | yes | — | — | — | — | — |
|
||||
| `legend` | yes | yes | — | yes | — | yes | — |
|
||||
| `contextLinks` | yes | yes | yes | yes | yes | yes | — |
|
||||
| `thresholds` | yes | yes | yes | — | yes | — | — |
|
||||
@@ -1,9 +0,0 @@
|
||||
{
|
||||
"id": "signoz",
|
||||
"name": "signoz",
|
||||
"metaData": {
|
||||
"buildInfo": {
|
||||
"buildVersion": "0.0.1"
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,130 +0,0 @@
|
||||
{
|
||||
"name": "@signoz/signoz-schemas",
|
||||
"version": "0.0.1",
|
||||
"description": "SigNoz schema plugins",
|
||||
"perses": {
|
||||
"schemasPath": ".",
|
||||
"plugins": [
|
||||
{
|
||||
"kind": "Datasource",
|
||||
"spec": {
|
||||
"name": "SigNozDatasource"
|
||||
}
|
||||
},
|
||||
{
|
||||
"kind": "Panel",
|
||||
"spec": {
|
||||
"name": "SigNozTimeSeriesPanel"
|
||||
}
|
||||
},
|
||||
{
|
||||
"kind": "Panel",
|
||||
"spec": {
|
||||
"name": "SigNozBarChartPanel"
|
||||
}
|
||||
},
|
||||
{
|
||||
"kind": "Panel",
|
||||
"spec": {
|
||||
"name": "SigNozNumberPanel"
|
||||
}
|
||||
},
|
||||
{
|
||||
"kind": "Panel",
|
||||
"spec": {
|
||||
"name": "SigNozPieChartPanel"
|
||||
}
|
||||
},
|
||||
{
|
||||
"kind": "Panel",
|
||||
"spec": {
|
||||
"name": "SigNozTablePanel"
|
||||
}
|
||||
},
|
||||
{
|
||||
"kind": "Panel",
|
||||
"spec": {
|
||||
"name": "SigNozHistogramPanel"
|
||||
}
|
||||
},
|
||||
{
|
||||
"kind": "Panel",
|
||||
"spec": {
|
||||
"name": "SigNozListPanel"
|
||||
}
|
||||
},
|
||||
{
|
||||
"kind": "Panel",
|
||||
"spec": {
|
||||
"name": "SigNozIgnoredFieldsChart"
|
||||
}
|
||||
},
|
||||
{
|
||||
"kind": "TimeSeriesQuery",
|
||||
"spec": {
|
||||
"name": "SigNozBuilderQuery"
|
||||
}
|
||||
},
|
||||
{
|
||||
"kind": "TimeSeriesQuery",
|
||||
"spec": {
|
||||
"name": "SigNozClickHouseSQL"
|
||||
}
|
||||
},
|
||||
{
|
||||
"kind": "TimeSeriesQuery",
|
||||
"spec": {
|
||||
"name": "SigNozPromQLQuery"
|
||||
}
|
||||
},
|
||||
{
|
||||
"kind": "TimeSeriesQuery",
|
||||
"spec": {
|
||||
"name": "SigNozCompositeQuery"
|
||||
}
|
||||
},
|
||||
{
|
||||
"kind": "TimeSeriesQuery",
|
||||
"spec": {
|
||||
"name": "SigNozTraceOperator"
|
||||
}
|
||||
},
|
||||
{
|
||||
"kind": "TimeSeriesQuery",
|
||||
"spec": {
|
||||
"name": "SigNozFormula"
|
||||
}
|
||||
},
|
||||
{
|
||||
"kind": "LogQuery",
|
||||
"spec": {
|
||||
"name": "SigNozBuilderQuery"
|
||||
}
|
||||
},
|
||||
{
|
||||
"kind": "TraceQuery",
|
||||
"spec": {
|
||||
"name": "SigNozBuilderQuery"
|
||||
}
|
||||
},
|
||||
{
|
||||
"kind": "Variable",
|
||||
"spec": {
|
||||
"name": "SigNozCustomVariable"
|
||||
}
|
||||
},
|
||||
{
|
||||
"kind": "Variable",
|
||||
"spec": {
|
||||
"name": "SigNozDynamicVariable"
|
||||
}
|
||||
},
|
||||
{
|
||||
"kind": "Variable",
|
||||
"spec": {
|
||||
"name": "SigNozQueryVariable"
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
@@ -1,40 +0,0 @@
|
||||
{
|
||||
"kind": "SigNozBarChartPanel",
|
||||
"spec": {
|
||||
"visualization": {
|
||||
"timePreference": "globalTime",
|
||||
"fillSpans": false,
|
||||
"stackedBarChart": false
|
||||
},
|
||||
"formatting": {
|
||||
"unit": "By",
|
||||
"decimalPrecision": 2
|
||||
},
|
||||
"axes": {
|
||||
"softMin": 0,
|
||||
"softMax": 1000,
|
||||
"isLogScale": false
|
||||
},
|
||||
"legend": {
|
||||
"position": "bottom",
|
||||
"customColors": {
|
||||
"series-A": "#9ea5f7"
|
||||
}
|
||||
},
|
||||
"contextLinks": [
|
||||
{
|
||||
"label": "View details",
|
||||
"url": "http://localhost:8080/{{_service.name}}"
|
||||
}
|
||||
],
|
||||
"thresholds": [
|
||||
{
|
||||
"value": 500,
|
||||
"unit": "By",
|
||||
"color": "Red",
|
||||
"format": "Text",
|
||||
"label": "upper limit"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
@@ -1,29 +0,0 @@
|
||||
package model
|
||||
|
||||
import "github.com/signoz/common"
|
||||
|
||||
kind: "SigNozBarChartPanel"
|
||||
spec: close({
|
||||
visualization?: #Visualization
|
||||
formatting?: #Formatting
|
||||
axes?: common.#Axes
|
||||
legend?: #Legend
|
||||
contextLinks?: [...common.#ContextLinkProps]
|
||||
thresholds?: [...common.#ThresholdWithLabel]
|
||||
})
|
||||
|
||||
#Visualization: {
|
||||
timePreference?: common.#TimePreference
|
||||
fillSpans?: bool | *false
|
||||
stackedBarChart?: bool | *true
|
||||
}
|
||||
|
||||
#Formatting: {
|
||||
unit?: string | *""
|
||||
decimalPrecision?: common.#PrecisionOption
|
||||
}
|
||||
|
||||
#Legend: {
|
||||
position?: common.#LegendPosition
|
||||
customColors?: [string]: string
|
||||
}
|
||||
@@ -1,35 +0,0 @@
|
||||
package model
|
||||
|
||||
import "github.com/signoz/common"
|
||||
|
||||
// Source: pkg/types/querybuildertypes/querybuildertypesv5/builder_query.go — QueryBuilderQuery
|
||||
kind: "SigNozBuilderQuery"
|
||||
spec: close({
|
||||
name: common.#QueryName
|
||||
signal: "metrics" | "logs" | "traces"
|
||||
expression: string
|
||||
disabled?: bool | *false
|
||||
|
||||
aggregations?: [...common.#Aggregation]
|
||||
filter?: common.#FilterExpression
|
||||
groupBy?: [...common.#GroupByItem]
|
||||
order?: [...common.#OrderByItem]
|
||||
selectFields?: [...common.#TelemetryFieldKey]
|
||||
limit?: common.#Limit
|
||||
limitBy?: #LimitBy
|
||||
offset?: common.#Offset
|
||||
cursor?: string
|
||||
having?: common.#HavingExpression
|
||||
// secondaryAggregations not added — not yet implemented.
|
||||
functions?: [...common.#Function]
|
||||
legend?: string
|
||||
stepInterval?: number
|
||||
reduceTo?: common.#ReduceTo
|
||||
pageSize?: int & >=1
|
||||
source?: string
|
||||
})
|
||||
|
||||
#LimitBy: close({
|
||||
keys: [...string]
|
||||
value: string
|
||||
})
|
||||
@@ -1,24 +0,0 @@
|
||||
{
|
||||
"kind": "SigNozBuilderQuery",
|
||||
"spec": {
|
||||
"name": "A",
|
||||
"signal": "metrics",
|
||||
"expression": "A",
|
||||
"aggregations": [
|
||||
{
|
||||
"metricName": "redis_keyspace_hits",
|
||||
"timeAggregation": "rate",
|
||||
"spaceAggregation": "sum",
|
||||
"reduceTo": "sum"
|
||||
}
|
||||
],
|
||||
"filter": {
|
||||
"expression": "host_name IN $host_name"
|
||||
},
|
||||
"groupBy": [],
|
||||
"order": [],
|
||||
"disabled": false,
|
||||
"legend": "Hit/s across all hosts",
|
||||
"stepInterval": 60
|
||||
}
|
||||
}
|
||||
@@ -1,12 +0,0 @@
|
||||
package model
|
||||
|
||||
import "github.com/signoz/common"
|
||||
|
||||
// Source: pkg/types/querybuildertypes/querybuildertypesv5/clickhouse_query.go — ClickHouseQuery
|
||||
kind: "SigNozClickHouseSQL"
|
||||
spec: close({
|
||||
name: common.#QueryName
|
||||
query: string & !=""
|
||||
disabled?: bool | *false
|
||||
legend?: string
|
||||
})
|
||||
@@ -1,9 +0,0 @@
|
||||
{
|
||||
"kind": "SigNozClickHouseSQL",
|
||||
"spec": {
|
||||
"name": "A",
|
||||
"query": "SELECT toStartOfInterval(timestamp, INTERVAL 1 MINUTE) AS ts, count() AS total FROM signoz_logs.distributed_logs GROUP BY ts ORDER BY ts",
|
||||
"disabled": false,
|
||||
"legend": "Log count"
|
||||
}
|
||||
}
|
||||
@@ -1,45 +0,0 @@
|
||||
package model
|
||||
|
||||
import (
|
||||
bq "github.com/signoz/schemas-wrapper/schemas/signoz-builder-query:model"
|
||||
f "github.com/signoz/schemas-wrapper/schemas/signoz-formula:model"
|
||||
to "github.com/signoz/schemas-wrapper/schemas/signoz-trace-operator:model"
|
||||
pql "github.com/signoz/schemas-wrapper/schemas/signoz-promql:model"
|
||||
ch "github.com/signoz/schemas-wrapper/schemas/signoz-clickhouse-sql:model"
|
||||
)
|
||||
|
||||
// Source: pkg/types/querybuildertypes/querybuildertypesv5/req.go — CompositeQuery
|
||||
// SigNozCompositeQuery groups multiple query plugins into a single
|
||||
// query request. Each entry is a typed envelope whose spec is
|
||||
// validated by the corresponding plugin schema.
|
||||
|
||||
// this is to be used when there are multiple queries in a panel
|
||||
// in most cases, there will be only one query, and there it is a better idea to
|
||||
// use the corresponding kind for that query instead of this composite query
|
||||
kind: "SigNozCompositeQuery"
|
||||
spec: close({
|
||||
queries: [...#QueryEnvelope]
|
||||
})
|
||||
|
||||
// QueryEnvelope wraps a single query plugin with a type discriminator.
|
||||
#QueryEnvelope:
|
||||
close({
|
||||
type: "builder_query",
|
||||
spec: bq.spec
|
||||
}) |
|
||||
close({
|
||||
type: "builder_formula",
|
||||
spec: f.spec
|
||||
}) |
|
||||
close({
|
||||
type: "builder_trace_operator",
|
||||
spec: to.spec
|
||||
}) |
|
||||
close({
|
||||
type: "promql",
|
||||
spec: pql.spec
|
||||
}) |
|
||||
close({
|
||||
type: "clickhouse_sql",
|
||||
spec: ch.spec
|
||||
})
|
||||
@@ -1,53 +0,0 @@
|
||||
{
|
||||
"kind": "SigNozCompositeQuery",
|
||||
"spec": {
|
||||
"queries": [
|
||||
{
|
||||
"type": "builder_query",
|
||||
"spec": {
|
||||
"name": "A",
|
||||
"signal": "metrics",
|
||||
"expression": "A",
|
||||
"aggregations": [
|
||||
{
|
||||
"metricName": "redis_keyspace_hits",
|
||||
"timeAggregation": "rate",
|
||||
"spaceAggregation": "sum",
|
||||
"reduceTo": "sum"
|
||||
}
|
||||
],
|
||||
"filter": {
|
||||
"expression": "host_name IN $host_name"
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "builder_query",
|
||||
"spec": {
|
||||
"name": "B",
|
||||
"signal": "metrics",
|
||||
"expression": "B",
|
||||
"aggregations": [
|
||||
{
|
||||
"metricName": "redis_keyspace_misses",
|
||||
"timeAggregation": "rate",
|
||||
"spaceAggregation": "sum",
|
||||
"reduceTo": "sum"
|
||||
}
|
||||
],
|
||||
"filter": {
|
||||
"expression": "host_name IN $host_name"
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "builder_formula",
|
||||
"spec": {
|
||||
"name": "F1",
|
||||
"expression": "A / (A + B) * 100",
|
||||
"legend": "Hit rate %"
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
@@ -1,10 +0,0 @@
|
||||
package model
|
||||
|
||||
import "github.com/signoz/common"
|
||||
|
||||
// defaultValue lives on the Perses ListVariable wrapper (spec level).
|
||||
kind: "SigNozCustomVariable"
|
||||
spec: close({
|
||||
customValue: =~"^[^,]+(,[^,]+)*$"
|
||||
sort?: common.#VariableSortOrder
|
||||
})
|
||||
@@ -1,7 +0,0 @@
|
||||
{
|
||||
"kind": "SigNozCustomVariable",
|
||||
"spec": {
|
||||
"customValue": "production,staging,development",
|
||||
"sort": "disabled"
|
||||
}
|
||||
}
|
||||
@@ -1,9 +0,0 @@
|
||||
package model
|
||||
|
||||
kind: "SigNozDatasource"
|
||||
|
||||
// SigNoz has a single built-in backend — the frontend already knows
|
||||
// the API endpoint, so there is no connection config to validate.
|
||||
// Add fields here if SigNoz ever supports multiple backends or
|
||||
// configurable API versions.
|
||||
spec: close({})
|
||||
@@ -1,4 +0,0 @@
|
||||
{
|
||||
"kind": "SigNozDatasource",
|
||||
"spec": {}
|
||||
}
|
||||
@@ -1,11 +0,0 @@
|
||||
package model
|
||||
|
||||
import "github.com/signoz/common"
|
||||
|
||||
// defaultValue lives on the Perses ListVariable wrapper (spec level).
|
||||
kind: "SigNozDynamicVariable"
|
||||
spec: close({
|
||||
name: string
|
||||
source: string
|
||||
sort?: common.#VariableSortOrder
|
||||
})
|
||||
@@ -1,8 +0,0 @@
|
||||
{
|
||||
"kind": "SigNozDynamicVariable",
|
||||
"spec": {
|
||||
"name": "host_name",
|
||||
"source": "metrics",
|
||||
"sort": "asc"
|
||||
}
|
||||
}
|
||||
@@ -1,25 +0,0 @@
|
||||
package model
|
||||
|
||||
// Fields from IBaseWidget that are NOT in any dedicated panel CUE file.
|
||||
// This file exists as a reference only and will be removed in the end.
|
||||
// Needs to be removed from package.json as well.
|
||||
|
||||
kind: "SigNozIgnoredFieldsChart"
|
||||
spec: close({
|
||||
opacity?: string // not wired to chart rendering
|
||||
nullZeroValues?: string // not wired to chart rendering
|
||||
stepSize?: number
|
||||
columnWidths?: [string]: number // not a config choice — persisted user-resized column widths
|
||||
// "Chart Appearance" section in UI — could not find this section in the app.
|
||||
// These 4 fields are gated behind panelTypeVs* constants (TIME_SERIES only).
|
||||
lineInterpolation?: #LineInterpolation
|
||||
showPoints?: bool
|
||||
lineStyle?: #LineStyle
|
||||
fillMode?: #FillMode
|
||||
})
|
||||
|
||||
#LineInterpolation: "linear" | "spline" | "stepAfter" | "stepBefore"
|
||||
|
||||
#LineStyle: "solid" | "dashed"
|
||||
|
||||
#FillMode: "solid" | "gradient" | "none"
|
||||
@@ -1,17 +0,0 @@
|
||||
package model
|
||||
|
||||
import "github.com/signoz/common"
|
||||
|
||||
// Source: pkg/types/querybuildertypes/querybuildertypesv5/formula.go — QueryBuilderFormula
|
||||
kind: "SigNozFormula"
|
||||
spec: close({
|
||||
name: common.#QueryName
|
||||
expression: string
|
||||
disabled?: bool | *false
|
||||
legend?: string
|
||||
limit?: common.#Limit
|
||||
having?: common.#HavingExpression
|
||||
stepInterval?: number
|
||||
order?: [...common.#OrderByItem]
|
||||
functions?: [...common.#Function]
|
||||
})
|
||||
@@ -1,8 +0,0 @@
|
||||
{
|
||||
"kind": "SigNozFormula",
|
||||
"spec": {
|
||||
"name": "F1",
|
||||
"expression": "A / B * 100",
|
||||
"legend": "Hit rate %"
|
||||
}
|
||||
}
|
||||
@@ -1,21 +0,0 @@
|
||||
{
|
||||
"kind": "SigNozHistogramPanel",
|
||||
"spec": {
|
||||
"histogramBuckets": {
|
||||
"bucketCount": 60,
|
||||
"bucketWidth": 100,
|
||||
"mergeAllActiveQueries": true
|
||||
},
|
||||
"legend": {
|
||||
"customColors": {
|
||||
"series-A": "#9ea5f7"
|
||||
}
|
||||
},
|
||||
"contextLinks": [
|
||||
{
|
||||
"label": "View histogram details",
|
||||
"url": "http://localhost:8080/histogram"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
@@ -1,20 +0,0 @@
|
||||
package model
|
||||
|
||||
import "github.com/signoz/common"
|
||||
|
||||
kind: "SigNozHistogramPanel"
|
||||
spec: close({
|
||||
histogramBuckets?: #HistogramBuckets
|
||||
legend?: #Legend
|
||||
contextLinks?: [...common.#ContextLinkProps]
|
||||
})
|
||||
|
||||
#HistogramBuckets: {
|
||||
bucketCount?: number | *30
|
||||
bucketWidth?: number | *0
|
||||
mergeAllActiveQueries?: bool | *false
|
||||
}
|
||||
|
||||
#Legend: {
|
||||
customColors?: [string]: string
|
||||
}
|
||||
@@ -1,54 +0,0 @@
|
||||
{
|
||||
"kind": "SigNozListPanel",
|
||||
"spec": {
|
||||
"selectedLogFields": [
|
||||
{
|
||||
"name": "timestamp",
|
||||
"type": "log",
|
||||
"dataType": ""
|
||||
},
|
||||
{
|
||||
"name": "body",
|
||||
"type": "log",
|
||||
"dataType": ""
|
||||
},
|
||||
{
|
||||
"name": "error",
|
||||
"type": "",
|
||||
"dataType": "string"
|
||||
}
|
||||
],
|
||||
"selectedTracesFields": [
|
||||
{
|
||||
"name": "service.name",
|
||||
"signal": "traces",
|
||||
"fieldContext": "resource",
|
||||
"fieldDataType": "string"
|
||||
},
|
||||
{
|
||||
"name": "name",
|
||||
"signal": "traces",
|
||||
"fieldContext": "span",
|
||||
"fieldDataType": "string"
|
||||
},
|
||||
{
|
||||
"name": "duration_nano",
|
||||
"signal": "traces",
|
||||
"fieldContext": "span",
|
||||
"fieldDataType": ""
|
||||
},
|
||||
{
|
||||
"name": "http_method",
|
||||
"signal": "traces",
|
||||
"fieldContext": "span",
|
||||
"fieldDataType": ""
|
||||
},
|
||||
{
|
||||
"name": "response_status_code",
|
||||
"signal": "traces",
|
||||
"fieldContext": "span",
|
||||
"fieldDataType": ""
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
@@ -1,15 +0,0 @@
|
||||
package model
|
||||
|
||||
import "github.com/signoz/common"
|
||||
|
||||
kind: "SigNozListPanel"
|
||||
spec: close({
|
||||
selectedLogFields?: [...#LogField]
|
||||
selectedTracesFields?: [...common.#TelemetryFieldKey]
|
||||
})
|
||||
|
||||
#LogField: {
|
||||
name: string
|
||||
type: string
|
||||
dataType: string
|
||||
}
|
||||
@@ -1,34 +0,0 @@
|
||||
{
|
||||
"kind": "SigNozNumberPanel",
|
||||
"spec": {
|
||||
"visualization": {
|
||||
"timePreference": "globalTime"
|
||||
},
|
||||
"formatting": {
|
||||
"unit": "none",
|
||||
"decimalPrecision": 1
|
||||
},
|
||||
"contextLinks": [
|
||||
{
|
||||
"label": "View details",
|
||||
"url": "http://localhost:8080/details"
|
||||
}
|
||||
],
|
||||
"thresholds": [
|
||||
{
|
||||
"value": 1200000,
|
||||
"operator": ">",
|
||||
"unit": "none",
|
||||
"color": "Red",
|
||||
"format": "Text"
|
||||
},
|
||||
{
|
||||
"value": 1200000,
|
||||
"operator": "<=",
|
||||
"unit": "none",
|
||||
"color": "Green",
|
||||
"format": "Text"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
@@ -1,20 +0,0 @@
|
||||
package model
|
||||
|
||||
import "github.com/signoz/common"
|
||||
|
||||
kind: "SigNozNumberPanel"
|
||||
spec: close({
|
||||
visualization?: #Visualization
|
||||
formatting?: #Formatting
|
||||
contextLinks?: [...common.#ContextLinkProps]
|
||||
thresholds?: [...common.#ComparisonThreshold]
|
||||
})
|
||||
|
||||
#Visualization: {
|
||||
timePreference?: common.#TimePreference
|
||||
}
|
||||
|
||||
#Formatting: {
|
||||
unit?: string | *""
|
||||
decimalPrecision?: common.#PrecisionOption
|
||||
}
|
||||
@@ -1,25 +0,0 @@
|
||||
{
|
||||
"kind": "SigNozPieChartPanel",
|
||||
"spec": {
|
||||
"visualization": {
|
||||
"timePreference": "globalTime"
|
||||
},
|
||||
"formatting": {
|
||||
"unit": "none",
|
||||
"decimalPrecision": 1
|
||||
},
|
||||
"legend": {
|
||||
"customColors": {
|
||||
"\"201\"": "#2bc051",
|
||||
"\"400\"": "#cc462e",
|
||||
"\"500\"": "#ff0000"
|
||||
}
|
||||
},
|
||||
"contextLinks": [
|
||||
{
|
||||
"label": "View breakdown",
|
||||
"url": "http://localhost:8080/breakdown"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
@@ -1,24 +0,0 @@
|
||||
package model
|
||||
|
||||
import "github.com/signoz/common"
|
||||
|
||||
kind: "SigNozPieChartPanel"
|
||||
spec: close({
|
||||
visualization?: #Visualization
|
||||
formatting?: #Formatting
|
||||
legend?: #Legend
|
||||
contextLinks?: [...common.#ContextLinkProps]
|
||||
})
|
||||
|
||||
#Visualization: {
|
||||
timePreference?: common.#TimePreference
|
||||
}
|
||||
|
||||
#Formatting: {
|
||||
unit?: string | *""
|
||||
decimalPrecision?: common.#PrecisionOption
|
||||
}
|
||||
|
||||
#Legend: {
|
||||
customColors?: [string]: string
|
||||
}
|
||||
@@ -1,14 +0,0 @@
|
||||
package model
|
||||
|
||||
import "github.com/signoz/common"
|
||||
|
||||
// Source: pkg/types/querybuildertypes/querybuildertypesv5/prom_query.go — PromQuery
|
||||
kind: "SigNozPromQLQuery"
|
||||
spec: close({
|
||||
name: common.#QueryName
|
||||
query: string & !=""
|
||||
disabled?: bool | *false
|
||||
step?: =~"^([0-9]+(\\.[0-9]+)?(ns|us|µs|ms|s|m|h))+$" | number
|
||||
stats?: bool
|
||||
legend?: string
|
||||
})
|
||||
@@ -1,9 +0,0 @@
|
||||
{
|
||||
"kind": "SigNozPromQLQuery",
|
||||
"spec": {
|
||||
"name": "A",
|
||||
"query": "rate(http_requests_total{status=\"200\"}[5m])",
|
||||
"disabled": false,
|
||||
"legend": "{{method}} {{path}}"
|
||||
}
|
||||
}
|
||||
@@ -1,10 +0,0 @@
|
||||
package model
|
||||
|
||||
import "github.com/signoz/common"
|
||||
|
||||
// defaultValue lives on the Perses ListVariable wrapper (spec level).
|
||||
kind: "SigNozQueryVariable"
|
||||
spec: close({
|
||||
queryValue: string
|
||||
sort?: common.#VariableSortOrder
|
||||
})
|
||||
@@ -1,7 +0,0 @@
|
||||
{
|
||||
"kind": "SigNozQueryVariable",
|
||||
"spec": {
|
||||
"queryValue": "SELECT DISTINCT host_name FROM signoz_metrics.distributed_time_series_v4_1day WHERE metric_name = 'redis_cpu_time'",
|
||||
"sort": "asc"
|
||||
}
|
||||
}
|
||||
@@ -1,30 +0,0 @@
|
||||
{
|
||||
"kind": "SigNozTablePanel",
|
||||
"spec": {
|
||||
"visualization": {
|
||||
"timePreference": "globalTime"
|
||||
},
|
||||
"formatting": {
|
||||
"columnUnits": {
|
||||
"A": "s"
|
||||
},
|
||||
"decimalPrecision": 2
|
||||
},
|
||||
"contextLinks": [
|
||||
{
|
||||
"label": "View trace",
|
||||
"url": "http://localhost:8080/trace/{{traceID}}"
|
||||
}
|
||||
],
|
||||
"thresholds": [
|
||||
{
|
||||
"value": 1,
|
||||
"operator": ">",
|
||||
"unit": "min",
|
||||
"color": "Red",
|
||||
"format": "Text",
|
||||
"tableOptions": "A"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
@@ -1,25 +0,0 @@
|
||||
package model
|
||||
|
||||
import "github.com/signoz/common"
|
||||
|
||||
kind: "SigNozTablePanel"
|
||||
spec: close({
|
||||
visualization?: #Visualization
|
||||
formatting?: #Formatting
|
||||
contextLinks?: [...common.#ContextLinkProps]
|
||||
thresholds?: [...#TableThreshold]
|
||||
})
|
||||
|
||||
#Visualization: {
|
||||
timePreference?: common.#TimePreference
|
||||
}
|
||||
|
||||
#Formatting: {
|
||||
columnUnits?: [string]: string
|
||||
decimalPrecision?: common.#PrecisionOption
|
||||
}
|
||||
|
||||
#TableThreshold: {
|
||||
common.#ComparisonThreshold
|
||||
tableOptions: string
|
||||
}
|
||||
@@ -1,46 +0,0 @@
|
||||
{
|
||||
"kind": "SigNozTimeSeriesPanel",
|
||||
"spec": {
|
||||
"visualization": {
|
||||
"timePreference": "globalTime",
|
||||
"fillSpans": true
|
||||
},
|
||||
"formatting": {
|
||||
"unit": "By",
|
||||
"decimalPrecision": 3
|
||||
},
|
||||
"axes": {
|
||||
"softMin": 0,
|
||||
"softMax": 800,
|
||||
"isLogScale": true
|
||||
},
|
||||
"legend": {
|
||||
"position": "right",
|
||||
"customColors": {
|
||||
"{service.name=\"sampleapp-gateway\"}": "#9ea5f7"
|
||||
}
|
||||
},
|
||||
"contextLinks": [
|
||||
{
|
||||
"label": "View service details",
|
||||
"url": "http://localhost:8080/{{_service.name}}?dfddf=%7B%7Blimit%7D%7D"
|
||||
}
|
||||
],
|
||||
"thresholds": [
|
||||
{
|
||||
"value": 1024,
|
||||
"unit": "By",
|
||||
"color": "Red",
|
||||
"format": "Text",
|
||||
"label": "upper limit"
|
||||
},
|
||||
{
|
||||
"value": 100,
|
||||
"unit": "By",
|
||||
"color": "Orange",
|
||||
"format": "Text",
|
||||
"label": "kinda bad"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
@@ -1,28 +0,0 @@
|
||||
package model
|
||||
|
||||
import "github.com/signoz/common"
|
||||
|
||||
kind: "SigNozTimeSeriesPanel"
|
||||
spec: close({
|
||||
visualization?: #Visualization
|
||||
formatting?: #Formatting
|
||||
axes?: common.#Axes
|
||||
legend?: #Legend
|
||||
contextLinks?: [...common.#ContextLinkProps]
|
||||
thresholds?: [...common.#ThresholdWithLabel]
|
||||
})
|
||||
|
||||
#Visualization: {
|
||||
timePreference?: common.#TimePreference
|
||||
fillSpans?: bool | *false
|
||||
}
|
||||
|
||||
#Formatting: {
|
||||
unit?: string | *""
|
||||
decimalPrecision?: common.#PrecisionOption
|
||||
}
|
||||
|
||||
#Legend: {
|
||||
position?: common.#LegendPosition
|
||||
customColors?: [string]: string
|
||||
}
|
||||
@@ -1,31 +0,0 @@
|
||||
package model
|
||||
|
||||
import "github.com/signoz/common"
|
||||
|
||||
// Source: pkg/types/querybuildertypes/querybuildertypesv5/trace_operator.go — QueryBuilderTraceOperator
|
||||
// SigNozTraceOperator composes multiple trace BuilderQueries using
|
||||
// relational operators (=>, ->, &&, ||, NOT) to query trace relationships.
|
||||
// Signal is implicitly "traces" — all referenced queries must be trace queries.
|
||||
kind: "SigNozTraceOperator"
|
||||
spec: close({
|
||||
name: common.#QueryName
|
||||
// Operator expression composing trace queries, e.g. "A => B && C".
|
||||
expression: string & !=""
|
||||
disabled?: bool | *false
|
||||
|
||||
// Which query's spans to return (must be a query referenced in expression).
|
||||
returnSpansFrom?: common.#QueryName
|
||||
|
||||
aggregations?: [...common.#ExpressionAggregation]
|
||||
filter?: common.#FilterExpression
|
||||
groupBy?: [...common.#GroupByItem]
|
||||
order?: [...common.#OrderByItem]
|
||||
limit?: common.#Limit
|
||||
offset?: common.#Offset
|
||||
cursor?: string
|
||||
functions?: [...common.#Function]
|
||||
stepInterval?: number
|
||||
having?: common.#HavingExpression
|
||||
legend?: string
|
||||
selectFields?: [...common.#TelemetryFieldKey]
|
||||
})
|
||||
@@ -1,19 +0,0 @@
|
||||
{
|
||||
"kind": "SigNozTraceOperator",
|
||||
"spec": {
|
||||
"name": "T1",
|
||||
"expression": "A => B",
|
||||
"returnSpansFrom": "A",
|
||||
"aggregations": [
|
||||
{
|
||||
"expression": "count()",
|
||||
"alias": "request_count"
|
||||
}
|
||||
],
|
||||
"filter": {
|
||||
"expression": "service.name = 'frontend'"
|
||||
},
|
||||
"groupBy": [],
|
||||
"order": []
|
||||
}
|
||||
}
|
||||
@@ -1,2 +0,0 @@
|
||||
percli lint -f ./examples/perses.json --plugin.path ./schemas-wrapper
|
||||
rm ./schemas-wrapper/plugin-modules.json
|
||||
@@ -111,7 +111,7 @@ func (provider *provider) addUserRoutes(router *mux.Router) error {
|
||||
return err
|
||||
}
|
||||
|
||||
if err := router.Handle("/api/v1/user", handler.New(provider.authZ.AdminAccess(provider.userHandler.ListUsers), handler.OpenAPIDef{
|
||||
if err := router.Handle("/api/v1/user", handler.New(provider.authZ.AdminAccess(provider.userHandler.ListUsersDeprecated), handler.OpenAPIDef{
|
||||
ID: "ListUsers",
|
||||
Tags: []string{"users"},
|
||||
Summary: "List users",
|
||||
@@ -128,7 +128,24 @@ func (provider *provider) addUserRoutes(router *mux.Router) error {
|
||||
return err
|
||||
}
|
||||
|
||||
if err := router.Handle("/api/v1/user/me", handler.New(provider.authZ.OpenAccess(provider.userHandler.GetMyUser), handler.OpenAPIDef{
|
||||
if err := router.Handle("/api/v2/users", handler.New(provider.authZ.AdminAccess(provider.userHandler.ListUsers), handler.OpenAPIDef{
|
||||
ID: "ListUsersV2",
|
||||
Tags: []string{"users"},
|
||||
Summary: "List users v2",
|
||||
Description: "This endpoint lists all users for the organization",
|
||||
Request: nil,
|
||||
RequestContentType: "",
|
||||
Response: make([]*types.User, 0),
|
||||
ResponseContentType: "application/json",
|
||||
SuccessStatusCode: http.StatusOK,
|
||||
ErrorStatusCodes: []int{},
|
||||
Deprecated: false,
|
||||
SecuritySchemes: newSecuritySchemes(types.RoleAdmin),
|
||||
})).Methods(http.MethodGet).GetError(); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if err := router.Handle("/api/v1/user/me", handler.New(provider.authZ.OpenAccess(provider.userHandler.GetMyUserDeprecated), handler.OpenAPIDef{
|
||||
ID: "GetMyUser",
|
||||
Tags: []string{"users"},
|
||||
Summary: "Get my user",
|
||||
@@ -145,7 +162,41 @@ func (provider *provider) addUserRoutes(router *mux.Router) error {
|
||||
return err
|
||||
}
|
||||
|
||||
if err := router.Handle("/api/v1/user/{id}", handler.New(provider.authZ.SelfAccess(provider.userHandler.GetUser), handler.OpenAPIDef{
|
||||
if err := router.Handle("/api/v2/users/me", handler.New(provider.authZ.OpenAccess(provider.userHandler.GetMyUser), handler.OpenAPIDef{
|
||||
ID: "GetMyUserV2",
|
||||
Tags: []string{"users"},
|
||||
Summary: "Get my user v2",
|
||||
Description: "This endpoint returns the user I belong to",
|
||||
Request: nil,
|
||||
RequestContentType: "",
|
||||
Response: new(authtypes.UserWithRoles),
|
||||
ResponseContentType: "application/json",
|
||||
SuccessStatusCode: http.StatusOK,
|
||||
ErrorStatusCodes: []int{},
|
||||
Deprecated: false,
|
||||
SecuritySchemes: []handler.OpenAPISecurityScheme{{Name: authtypes.IdentNProviderTokenizer.StringValue()}},
|
||||
})).Methods(http.MethodGet).GetError(); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if err := router.Handle("/api/v2/users/me", handler.New(provider.authZ.OpenAccess(provider.userHandler.UpdateMyUser), handler.OpenAPIDef{
|
||||
ID: "UpdateMyUserV2",
|
||||
Tags: []string{"users"},
|
||||
Summary: "Update my user v2",
|
||||
Description: "This endpoint updates the user I belong to",
|
||||
Request: new(types.UpdatableSelfUser),
|
||||
RequestContentType: "application/json",
|
||||
Response: nil,
|
||||
ResponseContentType: "",
|
||||
SuccessStatusCode: http.StatusNoContent,
|
||||
ErrorStatusCodes: []int{},
|
||||
Deprecated: false,
|
||||
SecuritySchemes: []handler.OpenAPISecurityScheme{{Name: authtypes.IdentNProviderTokenizer.StringValue()}},
|
||||
})).Methods(http.MethodPut).GetError(); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if err := router.Handle("/api/v1/user/{id}", handler.New(provider.authZ.SelfAccess(provider.userHandler.GetUserDeprecated), handler.OpenAPIDef{
|
||||
ID: "GetUser",
|
||||
Tags: []string{"users"},
|
||||
Summary: "Get user",
|
||||
@@ -162,7 +213,24 @@ func (provider *provider) addUserRoutes(router *mux.Router) error {
|
||||
return err
|
||||
}
|
||||
|
||||
if err := router.Handle("/api/v1/user/{id}", handler.New(provider.authZ.SelfAccess(provider.userHandler.UpdateUser), handler.OpenAPIDef{
|
||||
if err := router.Handle("/api/v2/users/{id}", handler.New(provider.authZ.AdminAccess(provider.userHandler.GetUser), handler.OpenAPIDef{
|
||||
ID: "GetUserV2",
|
||||
Tags: []string{"users"},
|
||||
Summary: "Get user by user id",
|
||||
Description: "This endpoint returns the user by id",
|
||||
Request: nil,
|
||||
RequestContentType: "",
|
||||
Response: new(types.User),
|
||||
ResponseContentType: "application/json",
|
||||
SuccessStatusCode: http.StatusOK,
|
||||
ErrorStatusCodes: []int{http.StatusNotFound},
|
||||
Deprecated: false,
|
||||
SecuritySchemes: newSecuritySchemes(types.RoleAdmin),
|
||||
})).Methods(http.MethodGet).GetError(); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if err := router.Handle("/api/v1/user/{id}", handler.New(provider.authZ.SelfAccess(provider.userHandler.UpdateUserDeprecated), handler.OpenAPIDef{
|
||||
ID: "UpdateUser",
|
||||
Tags: []string{"users"},
|
||||
Summary: "Update user",
|
||||
@@ -179,6 +247,23 @@ func (provider *provider) addUserRoutes(router *mux.Router) error {
|
||||
return err
|
||||
}
|
||||
|
||||
if err := router.Handle("/api/v2/users/{id}", handler.New(provider.authZ.AdminAccess(provider.userHandler.UpdateUser), handler.OpenAPIDef{
|
||||
ID: "UpdateUserV2",
|
||||
Tags: []string{"users"},
|
||||
Summary: "Update user v2",
|
||||
Description: "This endpoint updates the user by id",
|
||||
Request: new(types.UpdatableUser),
|
||||
RequestContentType: "application/json",
|
||||
Response: nil,
|
||||
ResponseContentType: "",
|
||||
SuccessStatusCode: http.StatusNoContent,
|
||||
ErrorStatusCodes: []int{http.StatusBadRequest, http.StatusNotFound},
|
||||
Deprecated: false,
|
||||
SecuritySchemes: newSecuritySchemes(types.RoleAdmin),
|
||||
})).Methods(http.MethodPut).GetError(); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if err := router.Handle("/api/v1/user/{id}", handler.New(provider.authZ.AdminAccess(provider.userHandler.DeleteUser), handler.OpenAPIDef{
|
||||
ID: "DeleteUser",
|
||||
Tags: []string{"users"},
|
||||
@@ -264,5 +349,39 @@ func (provider *provider) addUserRoutes(router *mux.Router) error {
|
||||
return err
|
||||
}
|
||||
|
||||
if err := router.Handle("/api/v2/users/{id}/roles", handler.New(provider.authZ.AdminAccess(provider.userHandler.GetUserRoles), handler.OpenAPIDef{
|
||||
ID: "GetUserRoles",
|
||||
Tags: []string{"users"},
|
||||
Summary: "Get user roles",
|
||||
Description: "This endpoint returns the user roles by user id",
|
||||
Request: nil,
|
||||
RequestContentType: "",
|
||||
Response: make([]*authtypes.Role, 0),
|
||||
ResponseContentType: "application/json",
|
||||
SuccessStatusCode: http.StatusOK,
|
||||
ErrorStatusCodes: []int{http.StatusNotFound},
|
||||
Deprecated: false,
|
||||
SecuritySchemes: newSecuritySchemes(types.RoleAdmin),
|
||||
})).Methods(http.MethodGet).GetError(); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if err := router.Handle("/api/v2/roles/{id}/users", handler.New(provider.authZ.AdminAccess(provider.userHandler.GetUsersByRoleID), handler.OpenAPIDef{
|
||||
ID: "GetUsersByRoleID",
|
||||
Tags: []string{"users"},
|
||||
Summary: "Get users by role id",
|
||||
Description: "This endpoint returns the users having the role by role id",
|
||||
Request: nil,
|
||||
RequestContentType: "",
|
||||
Response: make([]*types.User, 0),
|
||||
ResponseContentType: "application/json",
|
||||
SuccessStatusCode: http.StatusOK,
|
||||
ErrorStatusCodes: []int{http.StatusNotFound},
|
||||
Deprecated: false,
|
||||
SecuritySchemes: newSecuritySchemes(types.RoleAdmin),
|
||||
})).Methods(http.MethodGet).GetError(); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -37,7 +37,7 @@ func (module *getter) GetRootUserByOrgID(ctx context.Context, orgID valuer.UUID)
|
||||
return rootUser, userRoles, nil
|
||||
}
|
||||
|
||||
func (module *getter) ListByOrgID(ctx context.Context, orgID valuer.UUID) ([]*types.DeprecatedUser, error) {
|
||||
func (module *getter) ListByOrgIDDeprecated(ctx context.Context, orgID valuer.UUID) ([]*types.DeprecatedUser, error) {
|
||||
users, err := module.store.ListUsersByOrgID(ctx, orgID)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
@@ -84,6 +84,23 @@ func (module *getter) ListByOrgID(ctx context.Context, orgID valuer.UUID) ([]*ty
|
||||
return deprecatedUsers, nil
|
||||
}
|
||||
|
||||
func (module *getter) ListByOrgID(ctx context.Context, orgID valuer.UUID) ([]*types.User, error) {
|
||||
users, err := module.store.ListUsersByOrgID(ctx, orgID)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// filter root users if feature flag `hide_root_users` is true
|
||||
evalCtx := featuretypes.NewFlaggerEvaluationContext(orgID)
|
||||
hideRootUsers := module.flagger.BooleanOrEmpty(ctx, flagger.FeatureHideRootUser, evalCtx)
|
||||
|
||||
if hideRootUsers {
|
||||
users = slices.DeleteFunc(users, func(user *types.User) bool { return user.IsRoot })
|
||||
}
|
||||
|
||||
return users, nil
|
||||
}
|
||||
|
||||
func (module *getter) GetDeprecatedUserByOrgIDAndID(ctx context.Context, orgID valuer.UUID, id valuer.UUID) (*types.DeprecatedUser, error) {
|
||||
user, err := module.store.GetByOrgIDAndID(ctx, orgID, id)
|
||||
if err != nil {
|
||||
@@ -99,11 +116,19 @@ func (module *getter) GetDeprecatedUserByOrgIDAndID(ctx context.Context, orgID v
|
||||
return nil, errors.New(errors.TypeUnexpected, authtypes.ErrCodeUserRolesNotFound, "no user roles entries found")
|
||||
}
|
||||
|
||||
if userRoles[0].Role == nil {
|
||||
return nil, errors.New(errors.TypeUnexpected, authtypes.ErrCodeRoleNotFound, "role not found for user role entry")
|
||||
}
|
||||
|
||||
role := authtypes.SigNozManagedRoleToExistingLegacyRole[userRoles[0].Role.Name]
|
||||
|
||||
return types.NewDeprecatedUserFromUserAndRole(user, role), nil
|
||||
}
|
||||
|
||||
func (module *getter) GetUserByOrgIDAndID(ctx context.Context, orgID valuer.UUID, userID valuer.UUID) (*types.User, error) {
|
||||
return module.store.GetByOrgIDAndID(ctx, orgID, userID)
|
||||
}
|
||||
|
||||
func (module *getter) Get(ctx context.Context, id valuer.UUID) (*types.DeprecatedUser, error) {
|
||||
user, err := module.store.GetUser(ctx, id)
|
||||
if err != nil {
|
||||
@@ -119,6 +144,10 @@ func (module *getter) Get(ctx context.Context, id valuer.UUID) (*types.Deprecate
|
||||
return nil, errors.New(errors.TypeUnexpected, authtypes.ErrCodeUserRolesNotFound, "no user roles entries found")
|
||||
}
|
||||
|
||||
if userRoles[0].Role == nil {
|
||||
return nil, errors.New(errors.TypeUnexpected, authtypes.ErrCodeRoleNotFound, "role not found for user role entry")
|
||||
}
|
||||
|
||||
role := authtypes.SigNozManagedRoleToExistingLegacyRole[userRoles[0].Role.Name]
|
||||
|
||||
return types.NewDeprecatedUserFromUserAndRole(user, role), nil
|
||||
@@ -180,5 +209,15 @@ func (module *getter) GetUserRoles(ctx context.Context, userID valuer.UUID) ([]*
|
||||
return nil, err
|
||||
}
|
||||
|
||||
for _, ur := range userRoles {
|
||||
if ur.Role == nil {
|
||||
return nil, errors.New(errors.TypeUnexpected, authtypes.ErrCodeRoleNotFound, "role not found for user role entry")
|
||||
}
|
||||
}
|
||||
|
||||
return userRoles, nil
|
||||
}
|
||||
|
||||
func (module *getter) GetUsersByOrgIDAndRoleID(ctx context.Context, orgID valuer.UUID, roleID valuer.UUID) ([]*types.User, error) {
|
||||
return module.store.GetUsersByOrgIDAndRoleID(ctx, orgID, roleID)
|
||||
}
|
||||
|
||||
@@ -85,7 +85,7 @@ func (h *handler) CreateBulkInvite(rw http.ResponseWriter, r *http.Request) {
|
||||
render.Success(rw, http.StatusCreated, nil)
|
||||
}
|
||||
|
||||
func (h *handler) GetUser(w http.ResponseWriter, r *http.Request) {
|
||||
func (h *handler) GetUserDeprecated(w http.ResponseWriter, r *http.Request) {
|
||||
ctx, cancel := context.WithTimeout(r.Context(), 10*time.Second)
|
||||
defer cancel()
|
||||
|
||||
@@ -106,7 +106,28 @@ func (h *handler) GetUser(w http.ResponseWriter, r *http.Request) {
|
||||
render.Success(w, http.StatusOK, user)
|
||||
}
|
||||
|
||||
func (h *handler) GetMyUser(w http.ResponseWriter, r *http.Request) {
|
||||
func (h *handler) GetUser(w http.ResponseWriter, r *http.Request) {
|
||||
ctx, cancel := context.WithTimeout(r.Context(), 10*time.Second)
|
||||
defer cancel()
|
||||
|
||||
userID := mux.Vars(r)["id"]
|
||||
|
||||
claims, err := authtypes.ClaimsFromContext(ctx)
|
||||
if err != nil {
|
||||
render.Error(w, err)
|
||||
return
|
||||
}
|
||||
|
||||
user, err := h.getter.GetUserByOrgIDAndID(ctx, valuer.MustNewUUID(claims.OrgID), valuer.MustNewUUID(userID))
|
||||
if err != nil {
|
||||
render.Error(w, err)
|
||||
return
|
||||
}
|
||||
|
||||
render.Success(w, http.StatusOK, user)
|
||||
}
|
||||
|
||||
func (h *handler) GetMyUserDeprecated(w http.ResponseWriter, r *http.Request) {
|
||||
ctx, cancel := context.WithTimeout(r.Context(), 10*time.Second)
|
||||
defer cancel()
|
||||
|
||||
@@ -125,6 +146,85 @@ func (h *handler) GetMyUser(w http.ResponseWriter, r *http.Request) {
|
||||
render.Success(w, http.StatusOK, user)
|
||||
}
|
||||
|
||||
func (h *handler) GetMyUser(w http.ResponseWriter, r *http.Request) {
|
||||
ctx, cancel := context.WithTimeout(r.Context(), 10*time.Second)
|
||||
defer cancel()
|
||||
|
||||
claims, err := authtypes.ClaimsFromContext(ctx)
|
||||
if err != nil {
|
||||
render.Error(w, err)
|
||||
return
|
||||
}
|
||||
|
||||
user, err := h.getter.GetUserByOrgIDAndID(ctx, valuer.MustNewUUID(claims.OrgID), valuer.MustNewUUID(claims.UserID))
|
||||
if err != nil {
|
||||
render.Error(w, err)
|
||||
return
|
||||
}
|
||||
|
||||
userRoles, err := h.getter.GetUserRoles(ctx, user.ID)
|
||||
if err != nil {
|
||||
render.Error(w, err)
|
||||
return
|
||||
}
|
||||
|
||||
roles := make([]*authtypes.Role, len(userRoles))
|
||||
for idx, userRole := range userRoles {
|
||||
roles[idx] = authtypes.NewRoleFromStorableRole(userRole.Role)
|
||||
}
|
||||
|
||||
userWithRoles := &authtypes.UserWithRoles{
|
||||
User: user,
|
||||
Roles: roles,
|
||||
}
|
||||
|
||||
render.Success(w, http.StatusOK, userWithRoles)
|
||||
}
|
||||
|
||||
func (h *handler) UpdateMyUser(w http.ResponseWriter, r *http.Request) {
|
||||
ctx, cancel := context.WithTimeout(r.Context(), 10*time.Second)
|
||||
defer cancel()
|
||||
|
||||
claims, err := authtypes.ClaimsFromContext(ctx)
|
||||
if err != nil {
|
||||
render.Error(w, err)
|
||||
return
|
||||
}
|
||||
|
||||
updatableSelfUser := new(types.UpdatableSelfUser)
|
||||
if err := json.NewDecoder(r.Body).Decode(&updatableSelfUser); err != nil {
|
||||
render.Error(w, err)
|
||||
return
|
||||
}
|
||||
|
||||
_, err = h.setter.UpdateMyUser(ctx, valuer.MustNewUUID(claims.OrgID), valuer.MustNewUUID(claims.UserID), updatableSelfUser)
|
||||
if err != nil {
|
||||
render.Error(w, err)
|
||||
return
|
||||
}
|
||||
|
||||
render.Success(w, http.StatusNoContent, nil)
|
||||
}
|
||||
|
||||
func (h *handler) ListUsersDeprecated(w http.ResponseWriter, r *http.Request) {
|
||||
ctx, cancel := context.WithTimeout(r.Context(), 10*time.Second)
|
||||
defer cancel()
|
||||
|
||||
claims, err := authtypes.ClaimsFromContext(ctx)
|
||||
if err != nil {
|
||||
render.Error(w, err)
|
||||
return
|
||||
}
|
||||
|
||||
users, err := h.getter.ListByOrgIDDeprecated(ctx, valuer.MustNewUUID(claims.OrgID))
|
||||
if err != nil {
|
||||
render.Error(w, err)
|
||||
return
|
||||
}
|
||||
|
||||
render.Success(w, http.StatusOK, users)
|
||||
}
|
||||
|
||||
func (h *handler) ListUsers(w http.ResponseWriter, r *http.Request) {
|
||||
ctx, cancel := context.WithTimeout(r.Context(), 10*time.Second)
|
||||
defer cancel()
|
||||
@@ -144,7 +244,7 @@ func (h *handler) ListUsers(w http.ResponseWriter, r *http.Request) {
|
||||
render.Success(w, http.StatusOK, users)
|
||||
}
|
||||
|
||||
func (h *handler) UpdateUser(w http.ResponseWriter, r *http.Request) {
|
||||
func (h *handler) UpdateUserDeprecated(w http.ResponseWriter, r *http.Request) {
|
||||
ctx, cancel := context.WithTimeout(r.Context(), 10*time.Second)
|
||||
defer cancel()
|
||||
|
||||
@@ -162,7 +262,7 @@ func (h *handler) UpdateUser(w http.ResponseWriter, r *http.Request) {
|
||||
return
|
||||
}
|
||||
|
||||
updatedUser, err := h.setter.UpdateUser(ctx, valuer.MustNewUUID(claims.OrgID), id, &user, claims.UserID)
|
||||
updatedUser, err := h.setter.UpdateUserDeprecated(ctx, valuer.MustNewUUID(claims.OrgID), id, &user, claims.UserID)
|
||||
if err != nil {
|
||||
render.Error(w, err)
|
||||
return
|
||||
@@ -171,6 +271,33 @@ func (h *handler) UpdateUser(w http.ResponseWriter, r *http.Request) {
|
||||
render.Success(w, http.StatusOK, updatedUser)
|
||||
}
|
||||
|
||||
func (h *handler) UpdateUser(w http.ResponseWriter, r *http.Request) {
|
||||
ctx, cancel := context.WithTimeout(r.Context(), 10*time.Second)
|
||||
defer cancel()
|
||||
|
||||
userID := mux.Vars(r)["id"]
|
||||
|
||||
claims, err := authtypes.ClaimsFromContext(ctx)
|
||||
if err != nil {
|
||||
render.Error(w, err)
|
||||
return
|
||||
}
|
||||
|
||||
updatableUser := new(types.UpdatableUser)
|
||||
if err := json.NewDecoder(r.Body).Decode(&updatableUser); err != nil {
|
||||
render.Error(w, err)
|
||||
return
|
||||
}
|
||||
|
||||
_, err = h.setter.UpdateUser(ctx, valuer.MustNewUUID(claims.OrgID), valuer.MustNewUUID(userID), updatableUser, valuer.MustNewUUID(claims.UserID))
|
||||
if err != nil {
|
||||
render.Error(w, err)
|
||||
return
|
||||
}
|
||||
|
||||
render.Success(w, http.StatusNoContent, nil)
|
||||
}
|
||||
|
||||
func (h *handler) DeleteUser(w http.ResponseWriter, r *http.Request) {
|
||||
ctx, cancel := context.WithTimeout(r.Context(), 10*time.Second)
|
||||
defer cancel()
|
||||
@@ -443,3 +570,56 @@ func (h *handler) RevokeAPIKey(w http.ResponseWriter, r *http.Request) {
|
||||
|
||||
render.Success(w, http.StatusNoContent, nil)
|
||||
}
|
||||
|
||||
func (h *handler) GetUserRoles(w http.ResponseWriter, r *http.Request) {
|
||||
ctx, cancel := context.WithTimeout(r.Context(), 10*time.Second)
|
||||
defer cancel()
|
||||
|
||||
userID := mux.Vars(r)["id"]
|
||||
|
||||
claims, err := authtypes.ClaimsFromContext(ctx)
|
||||
if err != nil {
|
||||
render.Error(w, err)
|
||||
return
|
||||
}
|
||||
|
||||
user, err := h.getter.GetUserByOrgIDAndID(ctx, valuer.MustNewUUID(claims.OrgID), valuer.MustNewUUID(userID))
|
||||
if err != nil {
|
||||
render.Error(w, err)
|
||||
return
|
||||
}
|
||||
|
||||
userRoles, err := h.getter.GetUserRoles(ctx, user.ID)
|
||||
if err != nil {
|
||||
render.Error(w, err)
|
||||
return
|
||||
}
|
||||
|
||||
roles := make([]*authtypes.Role, len(userRoles))
|
||||
for idx, userRole := range userRoles {
|
||||
roles[idx] = authtypes.NewRoleFromStorableRole(userRole.Role)
|
||||
}
|
||||
|
||||
render.Success(w, http.StatusOK, roles)
|
||||
}
|
||||
|
||||
func (h *handler) GetUsersByRoleID(w http.ResponseWriter, r *http.Request) {
|
||||
ctx, cancel := context.WithTimeout(r.Context(), 10*time.Second)
|
||||
defer cancel()
|
||||
|
||||
roleID := mux.Vars(r)["id"]
|
||||
|
||||
claims, err := authtypes.ClaimsFromContext(ctx)
|
||||
if err != nil {
|
||||
render.Error(w, err)
|
||||
return
|
||||
}
|
||||
|
||||
users, err := h.getter.GetUsersByOrgIDAndRoleID(ctx, valuer.MustNewUUID(claims.OrgID), valuer.MustNewUUID(roleID))
|
||||
if err != nil {
|
||||
render.Error(w, err)
|
||||
return
|
||||
}
|
||||
|
||||
render.Success(w, http.StatusOK, users)
|
||||
}
|
||||
|
||||
@@ -156,9 +156,7 @@ func (s *service) createOrPromoteRootUser(ctx context.Context, orgID valuer.UUID
|
||||
existingUser.PromoteToRoot()
|
||||
|
||||
err = s.store.RunInTx(ctx, func(ctx context.Context) error {
|
||||
// update users table
|
||||
deprecatedUser := types.NewDeprecatedUserFromUserAndRole(existingUser, types.RoleAdmin)
|
||||
if err := s.setter.UpdateAnyUser(ctx, orgID, deprecatedUser); err != nil {
|
||||
if err := s.setter.UpdateAnyUser(ctx, orgID, existingUser); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
@@ -201,8 +199,7 @@ func (s *service) updateExistingRootUser(ctx context.Context, orgID valuer.UUID,
|
||||
|
||||
if existingRoot.Email != s.config.Email {
|
||||
existingRoot.UpdateEmail(s.config.Email)
|
||||
deprecatedUser := types.NewDeprecatedUserFromUserAndRole(existingRoot, types.RoleAdmin)
|
||||
if err := s.setter.UpdateAnyUser(ctx, orgID, deprecatedUser); err != nil {
|
||||
if err := s.setter.UpdateAnyUser(ctx, orgID, existingRoot); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
@@ -220,7 +220,7 @@ func (module *setter) CreateUser(ctx context.Context, user *types.User, opts ...
|
||||
return nil
|
||||
}
|
||||
|
||||
func (module *setter) UpdateUser(ctx context.Context, orgID valuer.UUID, id string, user *types.DeprecatedUser, updatedBy string) (*types.DeprecatedUser, error) {
|
||||
func (module *setter) UpdateUserDeprecated(ctx context.Context, orgID valuer.UUID, id string, user *types.DeprecatedUser, updatedBy string) (*types.DeprecatedUser, error) {
|
||||
existingUser, err := module.getter.GetDeprecatedUserByOrgIDAndID(ctx, orgID, valuer.MustNewUUID(id))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
@@ -265,7 +265,7 @@ func (module *setter) UpdateUser(ctx context.Context, orgID valuer.UUID, id stri
|
||||
existingUser.Update(user.DisplayName, user.Role)
|
||||
|
||||
// update the user - idempotent (this does analytics too so keeping it outside txn)
|
||||
if err := module.UpdateAnyUser(ctx, orgID, existingUser); err != nil {
|
||||
if err := module.UpdateAnyUserDeprecated(ctx, orgID, existingUser); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
@@ -291,7 +291,113 @@ func (module *setter) UpdateUser(ctx context.Context, orgID valuer.UUID, id stri
|
||||
return existingUser, nil
|
||||
}
|
||||
|
||||
func (module *setter) UpdateAnyUser(ctx context.Context, orgID valuer.UUID, deprecateUser *types.DeprecatedUser) error {
|
||||
func (module *setter) UpdateMyUser(ctx context.Context, orgID valuer.UUID, userID valuer.UUID, updatable *types.UpdatableSelfUser) (*types.User, error) {
|
||||
existingUser, err := module.getter.GetUserByOrgIDAndID(ctx, orgID, userID)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if err := existingUser.ErrIfRoot(); err != nil {
|
||||
return nil, errors.WithAdditionalf(err, "cannot update root user")
|
||||
}
|
||||
|
||||
if err := existingUser.ErrIfDeleted(); err != nil {
|
||||
return nil, errors.WithAdditionalf(err, "cannot update deleted user")
|
||||
}
|
||||
|
||||
existingUser.Update(updatable.DisplayName)
|
||||
if err := module.UpdateAnyUser(ctx, orgID, existingUser); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return existingUser, nil
|
||||
}
|
||||
|
||||
func (module *setter) UpdateUser(ctx context.Context, orgID valuer.UUID, userID valuer.UUID, updatable *types.UpdatableUser, updatedBy valuer.UUID) (*types.User, error) {
|
||||
existingUser, err := module.getter.GetUserByOrgIDAndID(ctx, orgID, userID)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if err := existingUser.ErrIfRoot(); err != nil {
|
||||
return nil, errors.WithAdditionalf(err, "cannot update root user")
|
||||
}
|
||||
|
||||
if err := existingUser.ErrIfDeleted(); err != nil {
|
||||
return nil, errors.WithAdditionalf(err, "cannot update deleted user")
|
||||
}
|
||||
|
||||
existingUserRoles, err := module.getter.GetUserRoles(ctx, existingUser.ID)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
existingUserRoleNames := roleNamesFromUserRoles(existingUserRoles)
|
||||
|
||||
var grants, revokes []string
|
||||
var rolesChanged bool
|
||||
if len(updatable.RoleNames) > 0 {
|
||||
// validate that all requested role names exist before making any changes
|
||||
_, err := module.authz.ListByOrgIDAndNames(ctx, orgID, updatable.RoleNames)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
grants, revokes = module.patchRolesNames(existingUserRoleNames, updatable.RoleNames)
|
||||
rolesChanged = (len(grants) > 0) || (len(revokes) > 0)
|
||||
|
||||
if rolesChanged && existingUser.ID == updatedBy {
|
||||
return nil, errors.New(errors.TypeForbidden, errors.CodeForbidden, "cannot change self roles")
|
||||
}
|
||||
|
||||
if rolesChanged {
|
||||
err = module.authz.ModifyGrant(
|
||||
ctx,
|
||||
orgID,
|
||||
revokes,
|
||||
grants,
|
||||
authtypes.MustNewSubject(authtypes.TypeableUser, userID.String(), orgID, nil),
|
||||
)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
existingUser.Update(updatable.DisplayName)
|
||||
|
||||
if err := module.UpdateAnyUser(ctx, existingUser.OrgID, existingUser); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if rolesChanged {
|
||||
// this by default runs in txn
|
||||
if err := module.UpdateUserRoles(ctx, existingUser.OrgID, existingUser.ID, updatable.RoleNames); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
return existingUser, nil
|
||||
}
|
||||
|
||||
func (module *setter) UpdateAnyUser(ctx context.Context, orgID valuer.UUID, user *types.User) error {
|
||||
if err := module.store.UpdateUser(ctx, orgID, user); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if err := module.tokenizer.DeleteIdentity(ctx, user.ID); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// stats collector things
|
||||
traits := types.NewTraitsFromUser(user)
|
||||
module.analytics.IdentifyUser(ctx, user.OrgID.String(), user.ID.String(), traits)
|
||||
module.analytics.TrackUser(ctx, user.OrgID.String(), user.ID.String(), "User Updated", traits)
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (module *setter) UpdateAnyUserDeprecated(ctx context.Context, orgID valuer.UUID, deprecateUser *types.DeprecatedUser) error {
|
||||
user := types.NewUserFromDeprecatedUser(deprecateUser)
|
||||
if err := module.store.UpdateUser(ctx, orgID, user); err != nil {
|
||||
return err
|
||||
@@ -801,13 +907,17 @@ func (module *setter) activatePendingUser(ctx context.Context, user *types.User,
|
||||
|
||||
func (module *setter) UpdateUserRoles(ctx context.Context, orgID, userID valuer.UUID, finalRoleNames []string) error {
|
||||
return module.store.RunInTx(ctx, func(ctx context.Context) error {
|
||||
// delete old user_role entries and create new ones from SSO
|
||||
// delete old user_role entries
|
||||
if err := module.userRoleStore.DeleteUserRoles(ctx, userID); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// create fresh ones
|
||||
return module.createUserRoleEntries(ctx, orgID, userID, finalRoleNames)
|
||||
// create fresh ones only if there are roles to assign
|
||||
if len(finalRoleNames) > 0 {
|
||||
return module.createUserRoleEntries(ctx, orgID, userID, finalRoleNames)
|
||||
}
|
||||
|
||||
return nil
|
||||
})
|
||||
}
|
||||
|
||||
@@ -820,3 +930,33 @@ func roleNamesFromUserRoles(userRoles []*authtypes.UserRole) []string {
|
||||
}
|
||||
return names
|
||||
}
|
||||
|
||||
func (module *setter) patchRolesNames(currentRolesNames, targetRoleNames []string) ([]string, []string) {
|
||||
currentRolesSet := make(map[string]struct{}, len(currentRolesNames))
|
||||
targetRolesSet := make(map[string]struct{}, len(targetRoleNames))
|
||||
|
||||
for _, role := range currentRolesNames {
|
||||
currentRolesSet[role] = struct{}{}
|
||||
}
|
||||
for _, role := range targetRoleNames {
|
||||
targetRolesSet[role] = struct{}{}
|
||||
}
|
||||
|
||||
// additions: roles present in input but not in current
|
||||
additions := []string{}
|
||||
for _, role := range targetRoleNames {
|
||||
if _, exists := currentRolesSet[role]; !exists {
|
||||
additions = append(additions, role)
|
||||
}
|
||||
}
|
||||
|
||||
// deletions: roles present in current but not in input
|
||||
deletions := []string{}
|
||||
for _, role := range currentRolesNames {
|
||||
if _, exists := targetRolesSet[role]; !exists {
|
||||
deletions = append(deletions, role)
|
||||
}
|
||||
}
|
||||
|
||||
return additions, deletions
|
||||
}
|
||||
|
||||
@@ -667,3 +667,22 @@ func (store *store) GetUsersByEmailsOrgIDAndStatuses(ctx context.Context, orgID
|
||||
|
||||
return users, nil
|
||||
}
|
||||
|
||||
func (store *store) GetUsersByOrgIDAndRoleID(ctx context.Context, orgID valuer.UUID, roleID valuer.UUID) ([]*types.User, error) {
|
||||
users := []*types.User{}
|
||||
|
||||
err := store.
|
||||
sqlstore.
|
||||
BunDBCtx(ctx).
|
||||
NewSelect().
|
||||
Model(&users).
|
||||
Join(`JOIN user_role ON user_role.user_id = "users".id`).
|
||||
Where(`"users".org_id = ?`, orgID).
|
||||
Where("user_role.role_id = ?", roleID).
|
||||
Scan(ctx)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return users, nil
|
||||
}
|
||||
|
||||
@@ -34,10 +34,13 @@ type Setter interface {
|
||||
// Initiate forgot password flow for a user
|
||||
ForgotPassword(ctx context.Context, orgID valuer.UUID, email valuer.Email, frontendBaseURL string) error
|
||||
|
||||
UpdateUser(ctx context.Context, orgID valuer.UUID, id string, user *types.DeprecatedUser, updatedBy string) (*types.DeprecatedUser, error)
|
||||
UpdateUserDeprecated(ctx context.Context, orgID valuer.UUID, id string, user *types.DeprecatedUser, updatedBy string) (*types.DeprecatedUser, error)
|
||||
UpdateMyUser(ctx context.Context, orgID valuer.UUID, userID valuer.UUID, updatable *types.UpdatableSelfUser) (*types.User, error)
|
||||
UpdateUser(ctx context.Context, orgID valuer.UUID, userID valuer.UUID, updatable *types.UpdatableUser, updatedBy valuer.UUID) (*types.User, error)
|
||||
|
||||
// UpdateAnyUser updates a user and persists the changes to the database along with the analytics and identity deletion.
|
||||
UpdateAnyUser(ctx context.Context, orgID valuer.UUID, user *types.DeprecatedUser) error
|
||||
UpdateAnyUserDeprecated(ctx context.Context, orgID valuer.UUID, deprecateUser *types.DeprecatedUser) error
|
||||
UpdateAnyUser(ctx context.Context, orgID valuer.UUID, user *types.User) error
|
||||
DeleteUser(ctx context.Context, orgID valuer.UUID, id string, deletedBy string) error
|
||||
|
||||
// invite
|
||||
@@ -60,11 +63,13 @@ type Getter interface {
|
||||
// Get root user by org id.
|
||||
GetRootUserByOrgID(context.Context, valuer.UUID) (*types.User, []*authtypes.UserRole, error)
|
||||
|
||||
// Get gets the users based on the given id
|
||||
ListByOrgID(context.Context, valuer.UUID) ([]*types.DeprecatedUser, error)
|
||||
// Get gets the users based on the given org id
|
||||
ListByOrgIDDeprecated(context.Context, valuer.UUID) ([]*types.DeprecatedUser, error)
|
||||
ListByOrgID(ctx context.Context, orgID valuer.UUID) ([]*types.User, error)
|
||||
|
||||
// Get deprecated user object by orgID and id.
|
||||
GetDeprecatedUserByOrgIDAndID(context.Context, valuer.UUID, valuer.UUID) (*types.DeprecatedUser, error)
|
||||
GetUserByOrgIDAndID(ctx context.Context, orgID valuer.UUID, userID valuer.UUID) (*types.User, error)
|
||||
|
||||
// Get user by id.
|
||||
Get(context.Context, valuer.UUID) (*types.DeprecatedUser, error)
|
||||
@@ -86,6 +91,9 @@ type Getter interface {
|
||||
|
||||
// Gets user_role with roles entries from db
|
||||
GetUserRoles(ctx context.Context, userID valuer.UUID) ([]*authtypes.UserRole, error)
|
||||
|
||||
// Gets all the user with role using role id in an org id
|
||||
GetUsersByOrgIDAndRoleID(ctx context.Context, orgID valuer.UUID, roleID valuer.UUID) ([]*types.User, error)
|
||||
}
|
||||
|
||||
type Handler interface {
|
||||
@@ -93,11 +101,19 @@ type Handler interface {
|
||||
CreateInvite(http.ResponseWriter, *http.Request)
|
||||
CreateBulkInvite(http.ResponseWriter, *http.Request)
|
||||
|
||||
// users
|
||||
ListUsersDeprecated(http.ResponseWriter, *http.Request)
|
||||
ListUsers(http.ResponseWriter, *http.Request)
|
||||
UpdateUserDeprecated(http.ResponseWriter, *http.Request)
|
||||
UpdateUser(http.ResponseWriter, *http.Request)
|
||||
DeleteUser(http.ResponseWriter, *http.Request)
|
||||
GetUserDeprecated(http.ResponseWriter, *http.Request)
|
||||
GetUser(http.ResponseWriter, *http.Request)
|
||||
GetMyUserDeprecated(http.ResponseWriter, *http.Request)
|
||||
GetMyUser(http.ResponseWriter, *http.Request)
|
||||
UpdateMyUser(http.ResponseWriter, *http.Request)
|
||||
GetUserRoles(http.ResponseWriter, *http.Request)
|
||||
GetUsersByRoleID(http.ResponseWriter, *http.Request)
|
||||
|
||||
// Reset Password
|
||||
GetResetPasswordToken(http.ResponseWriter, *http.Request)
|
||||
|
||||
@@ -178,7 +178,7 @@ func (provider *provider) Report(ctx context.Context) error {
|
||||
}
|
||||
|
||||
for _, user := range users {
|
||||
traits := types.NewTraitsFromDeprecatedUser(user)
|
||||
traits := types.NewTraitsFromUser(user)
|
||||
if maxLastObservedAt, ok := maxLastObservedAtPerUserID[user.ID]; ok {
|
||||
traits["auth_token.last_observed_at.max.time"] = maxLastObservedAt.UTC()
|
||||
traits["auth_token.last_observed_at.max.time_unix"] = maxLastObservedAt.Unix()
|
||||
|
||||
@@ -5,13 +5,14 @@ import (
|
||||
"time"
|
||||
|
||||
"github.com/SigNoz/signoz/pkg/errors"
|
||||
"github.com/SigNoz/signoz/pkg/types"
|
||||
"github.com/SigNoz/signoz/pkg/valuer"
|
||||
"github.com/uptrace/bun"
|
||||
)
|
||||
|
||||
var (
|
||||
ErrCodeUserRoleAlreadyExists = errors.MustNewCode("user_role_already_exists")
|
||||
ErrCodeUserRolesNotFound = errors.MustNewCode("user_roles_not_found")
|
||||
ErrCodeUserRolesNotFound = errors.MustNewCode("user_roles_not_found")
|
||||
)
|
||||
|
||||
type UserRole struct {
|
||||
@@ -47,6 +48,11 @@ func NewUserRoles(userID valuer.UUID, roles []*Role) []*UserRole {
|
||||
return userRoles
|
||||
}
|
||||
|
||||
type UserWithRoles struct {
|
||||
*types.User
|
||||
Roles []*Role `json:"roles"`
|
||||
}
|
||||
|
||||
type UserRoleStore interface {
|
||||
// create user roles in bulk
|
||||
CreateUserRoles(ctx context.Context, userRoles []*UserRole) error
|
||||
|
||||
@@ -51,6 +51,15 @@ type DeprecatedUser struct {
|
||||
Role Role `json:"role"`
|
||||
}
|
||||
|
||||
type UpdatableSelfUser struct {
|
||||
DisplayName string `json:"displayName" required:"true"`
|
||||
}
|
||||
|
||||
type UpdatableUser struct {
|
||||
DisplayName string `json:"displayName" required:"true"`
|
||||
RoleNames []string `json:"roleNames" required:"true" nullable:"false"`
|
||||
}
|
||||
|
||||
type PostableRegisterOrgAndAdmin struct {
|
||||
Name string `json:"name"`
|
||||
Email valuer.Email `json:"email"`
|
||||
@@ -298,6 +307,9 @@ type UserStore interface {
|
||||
// Get user by reset password token
|
||||
GetUserByResetPasswordToken(ctx context.Context, token string) (*User, error)
|
||||
|
||||
// Get users having role by org id and role id
|
||||
GetUsersByOrgIDAndRoleID(ctx context.Context, orgID valuer.UUID, roleID valuer.UUID) ([]*User, error)
|
||||
|
||||
// Transaction
|
||||
RunInTx(ctx context.Context, cb func(ctx context.Context) error) error
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user