2025-04-01 10:38:02 +09:00

138 lines
3.8 KiB
TypeScript

import { SelectableValue } from '@grafana/data';
import { fieldMap, sectionFields } from '../fields';
import { FieldData, SSOProvider, SSOProviderDTO } from '../types';
import { isSelectableValue } from './guards';
export const emptySettings: SSOProviderDTO = {
allowAssignGrafanaAdmin: false,
allowSignUp: false,
allowedDomains: [],
allowedGroups: [],
allowedOrganizations: [],
apiUrl: '',
authStyle: '',
authUrl: '',
autoLogin: false,
clientAuthentication: '',
clientId: '',
clientSecret: '',
managedIdentityClientId: '',
federatedCredentialAudience: '',
emailAttributeName: '',
emailAttributePath: '',
emptyScopes: false,
enabled: false,
extra: {},
groupsAttributePath: '',
hostedDomain: '',
icon: 'shield',
name: '',
roleAttributePath: '',
roleAttributeStrict: false,
scopes: [],
signoutRedirectUrl: '',
skipOrgRoleSync: false,
teamIds: [],
teamIdsAttributePath: '',
teamsUrl: '',
tlsClientCa: '',
tlsClientCert: '',
tlsClientKey: '',
tlsSkipVerify: false,
tokenUrl: '',
type: '',
usePkce: false,
useRefreshToken: false,
};
const strToValue = (val: string | string[]): SelectableValue[] => {
if (!val?.length) {
return [];
}
if (Array.isArray(val)) {
return val.map((v) => ({ label: v, value: v }));
}
// Stored as JSON Array
if (val.startsWith('[') && val.endsWith(']')) {
// Fallback to parsing it like a non-json string if it is not valid json, instead of crashing.
try {
return JSON.parse(val).map((v: string) => ({ label: v, value: v }));
} catch {}
}
return val.split(/[\s,]/).map((s) => ({ label: s, value: s }));
};
export function dataToDTO(data?: SSOProvider): SSOProviderDTO {
if (!data) {
return emptySettings;
}
const providerFields = getFieldsForProvider(data.provider);
const arrayFields = getArrayFields(fieldMap(data.provider), providerFields);
const settings = { ...data.settings };
for (const field of arrayFields) {
//@ts-expect-error
settings[field] = strToValue(settings[field]);
}
//@ts-expect-error
return settings;
}
const valuesToString = (values: Array<SelectableValue<string>>) => {
// Store arrays as JSON array
return JSON.stringify(values.map(({ value }) => value));
};
const getFieldsForProvider = (provider: string) => {
const sections = sectionFields[provider];
// include the enabled field because it is not part of the fields defined for providers
const fields = ['enabled'];
return Object.values(sections).reduce(
(result, section) => [
...result,
...section.fields.map((field) => (typeof field === 'string' ? field : field.name)),
],
fields
);
};
// Convert the DTO to the data format used by the API
export function dtoToData(dto: SSOProviderDTO, provider: string) {
let current: Partial<SSOProviderDTO> = dto;
const providerFields = getFieldsForProvider(provider);
const arrayFields = getArrayFields(fieldMap(provider), providerFields);
// filter out the fields that are not defined on the provider
const settings: Partial<SSOProviderDTO> = Object.keys(current)
.filter((key) => providerFields.includes(key))
.reduce((obj, key) => {
//@ts-expect-error
return { ...obj, [key]: current[key] };
}, {});
for (const field of arrayFields) {
const value = current[field];
if (value) {
if (isSelectableValue(value)) {
//@ts-expect-error
settings[field] = valuesToString(value);
} else if (isSelectableValue([value])) {
//@ts-expect-error
settings[field] = value.value;
}
}
}
return settings;
}
export function getArrayFields(obj: Record<string, FieldData>, providerFields: string[]): Array<keyof SSOProviderDTO> {
return Object.entries(obj)
.filter(([key, value]) => providerFields.includes(key) && value.type === 'select')
.map(([key]) => key as keyof SSOProviderDTO);
}