fix(slack): channel is not supported in combination with webhooks (#770)
#766
This commit is contained in:
parent
4872029b87
commit
595a29056d
14 changed files with 21 additions and 44 deletions
|
|
@ -32,7 +32,14 @@ export const createClient = (config: Config = {}): Client => {
|
||||||
|
|
||||||
const interceptors = createInterceptors<Request, Response, unknown, ResolvedRequestOptions>();
|
const interceptors = createInterceptors<Request, Response, unknown, ResolvedRequestOptions>();
|
||||||
|
|
||||||
const beforeRequest = async (options: RequestOptions) => {
|
const beforeRequest = async <
|
||||||
|
TData = unknown,
|
||||||
|
TResponseStyle extends 'data' | 'fields' = 'fields',
|
||||||
|
ThrowOnError extends boolean = boolean,
|
||||||
|
Url extends string = string,
|
||||||
|
>(
|
||||||
|
options: RequestOptions<TData, TResponseStyle, ThrowOnError, Url>,
|
||||||
|
) => {
|
||||||
const opts = {
|
const opts = {
|
||||||
..._config,
|
..._config,
|
||||||
...options,
|
...options,
|
||||||
|
|
@ -61,13 +68,14 @@ export const createClient = (config: Config = {}): Client => {
|
||||||
opts.headers.delete('Content-Type');
|
opts.headers.delete('Content-Type');
|
||||||
}
|
}
|
||||||
|
|
||||||
const url = buildUrl(opts);
|
const resolvedOpts = opts as typeof opts &
|
||||||
|
ResolvedRequestOptions<TResponseStyle, ThrowOnError, Url>;
|
||||||
|
const url = buildUrl(resolvedOpts);
|
||||||
|
|
||||||
return { opts, url };
|
return { opts: resolvedOpts, url };
|
||||||
};
|
};
|
||||||
|
|
||||||
const request: Client['request'] = async (options) => {
|
const request: Client['request'] = async (options) => {
|
||||||
// @ts-expect-error
|
|
||||||
const { opts, url } = await beforeRequest(options);
|
const { opts, url } = await beforeRequest(options);
|
||||||
const requestInit: ReqInit = {
|
const requestInit: ReqInit = {
|
||||||
redirect: 'follow',
|
redirect: 'follow',
|
||||||
|
|
|
||||||
|
|
@ -153,7 +153,7 @@ type SseFn = <
|
||||||
ThrowOnError extends boolean = false,
|
ThrowOnError extends boolean = false,
|
||||||
TResponseStyle extends ResponseStyle = 'fields',
|
TResponseStyle extends ResponseStyle = 'fields',
|
||||||
>(
|
>(
|
||||||
options: Omit<RequestOptions<TData, TResponseStyle, ThrowOnError>, 'method'>,
|
options: Omit<RequestOptions<never, TResponseStyle, ThrowOnError>, 'method'>,
|
||||||
) => Promise<ServerSentEventsResult<TData, TError>>;
|
) => Promise<ServerSentEventsResult<TData, TError>>;
|
||||||
|
|
||||||
type RequestFn = <
|
type RequestFn = <
|
||||||
|
|
|
||||||
|
|
@ -205,7 +205,7 @@ export const mergeHeaders = (
|
||||||
mergedHeaders.append(key, v as string);
|
mergedHeaders.append(key, v as string);
|
||||||
}
|
}
|
||||||
} else if (value !== undefined) {
|
} else if (value !== undefined) {
|
||||||
// assume object headers are meant to be JSON stringified, i.e. their
|
// assume object headers are meant to be JSON stringified, i.e., their
|
||||||
// content value in OpenAPI specification is 'application/json'
|
// content value in OpenAPI specification is 'application/json'
|
||||||
mergedHeaders.set(
|
mergedHeaders.set(
|
||||||
key,
|
key,
|
||||||
|
|
|
||||||
|
|
@ -81,7 +81,7 @@ export interface Config {
|
||||||
requestValidator?: (data: unknown) => Promise<unknown>;
|
requestValidator?: (data: unknown) => Promise<unknown>;
|
||||||
/**
|
/**
|
||||||
* A function transforming response data before it's returned. This is useful
|
* A function transforming response data before it's returned. This is useful
|
||||||
* for post-processing data, e.g. converting ISO strings into Date objects.
|
* for post-processing data, e.g., converting ISO strings into Date objects.
|
||||||
*/
|
*/
|
||||||
responseTransformer?: (data: unknown) => Promise<unknown>;
|
responseTransformer?: (data: unknown) => Promise<unknown>;
|
||||||
/**
|
/**
|
||||||
|
|
|
||||||
|
|
@ -127,7 +127,7 @@ export function getValidRequestBody(options: {
|
||||||
return hasSerializedBody ? options.serializedBody : null;
|
return hasSerializedBody ? options.serializedBody : null;
|
||||||
}
|
}
|
||||||
|
|
||||||
// not all clients implement a serializedBody property (i.e. client-axios)
|
// not all clients implement a serializedBody property (i.e., client-axios)
|
||||||
return options.body !== '' ? options.body : null;
|
return options.body !== '' ? options.body : null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -3,9 +3,9 @@
|
||||||
|
|
||||||
import type { Client, Options as Options2, TDataShape } from './client';
|
import type { Client, Options as Options2, TDataShape } from './client';
|
||||||
import { client } from './client.gen';
|
import { client } from './client.gen';
|
||||||
import type { BrowseFilesystemData, BrowseFilesystemResponses, CancelDoctorData, CancelDoctorErrors, CancelDoctorResponses, CreateBackupScheduleData, CreateBackupScheduleResponses, CreateNotificationDestinationData, CreateNotificationDestinationResponses, CreateRepositoryData, CreateRepositoryResponses, CreateVolumeData, CreateVolumeResponses, DeleteBackupScheduleData, DeleteBackupScheduleResponses, DeleteNotificationDestinationData, DeleteNotificationDestinationErrors, DeleteNotificationDestinationResponses, DeleteRepositoryData, DeleteRepositoryResponses, DeleteSnapshotData, DeleteSnapshotResponses, DeleteSnapshotsData, DeleteSnapshotsResponses, DeleteSsoInvitationData, DeleteSsoInvitationErrors, DeleteSsoInvitationResponses, DeleteSsoProviderData, DeleteSsoProviderErrors, DeleteSsoProviderResponses, DeleteUserAccountData, DeleteUserAccountErrors, DeleteUserAccountResponses, DeleteVolumeData, DeleteVolumeResponses, DevPanelExecData, DevPanelExecErrors, DevPanelExecResponses, DownloadResticPasswordData, DownloadResticPasswordResponses, DumpSnapshotData, DumpSnapshotResponses, GetAdminUsersData, GetAdminUsersResponses, GetBackupProgressData, GetBackupProgressResponses, GetBackupScheduleData, GetBackupScheduleForVolumeData, GetBackupScheduleForVolumeResponses, GetBackupScheduleResponses, GetDevPanelData, GetDevPanelResponses, GetMirrorCompatibilityData, GetMirrorCompatibilityResponses, GetNotificationDestinationData, GetNotificationDestinationErrors, GetNotificationDestinationResponses, GetOrgMembersData, GetOrgMembersResponses, GetPublicSsoProvidersData, GetPublicSsoProvidersResponses, GetRegistrationStatusData, GetRegistrationStatusResponses, GetRepositoryData, GetRepositoryResponses, GetRepositoryStatsData, GetRepositoryStatsResponses, GetScheduleMirrorsData, GetScheduleMirrorsResponses, GetScheduleNotificationsData, GetScheduleNotificationsResponses, GetSnapshotDetailsData, GetSnapshotDetailsResponses, GetSsoSettingsData, GetSsoSettingsResponses, GetStatusData, GetStatusResponses, GetSystemInfoData, GetSystemInfoResponses, GetUpdatesData, GetUpdatesResponses, GetUserDeletionImpactData, GetUserDeletionImpactResponses, GetVolumeData, GetVolumeErrors, GetVolumeResponses, HealthCheckVolumeData, HealthCheckVolumeErrors, HealthCheckVolumeResponses, ListBackupSchedulesData, ListBackupSchedulesResponses, ListFilesData, ListFilesResponses, ListNotificationDestinationsData, ListNotificationDestinationsResponses, ListRcloneRemotesData, ListRcloneRemotesResponses, ListRepositoriesData, ListRepositoriesResponses, ListSnapshotFilesData, ListSnapshotFilesResponses, ListSnapshotsData, ListSnapshotsResponses, ListVolumesData, ListVolumesResponses, MountVolumeData, MountVolumeResponses, RefreshRepositoryStatsData, RefreshRepositoryStatsResponses, RefreshSnapshotsData, RefreshSnapshotsResponses, RemoveOrgMemberData, RemoveOrgMemberErrors, RemoveOrgMemberResponses, ReorderBackupSchedulesData, ReorderBackupSchedulesResponses, RestoreSnapshotData, RestoreSnapshotResponses, RunBackupNowData, RunBackupNowResponses, RunForgetData, RunForgetResponses, SetRegistrationStatusData, SetRegistrationStatusResponses, StartDoctorData, StartDoctorErrors, StartDoctorResponses, StopBackupData, StopBackupErrors, StopBackupResponses, TagSnapshotsData, TagSnapshotsResponses, TestConnectionData, TestConnectionResponses, TestNotificationDestinationData, TestNotificationDestinationErrors, TestNotificationDestinationResponses, UnlockRepositoryData, UnlockRepositoryResponses, UnmountVolumeData, UnmountVolumeResponses, UpdateBackupScheduleData, UpdateBackupScheduleResponses, UpdateMemberRoleData, UpdateMemberRoleErrors, UpdateMemberRoleResponses, UpdateNotificationDestinationData, UpdateNotificationDestinationErrors, UpdateNotificationDestinationResponses, UpdateRepositoryData, UpdateRepositoryErrors, UpdateRepositoryResponses, UpdateScheduleMirrorsData, UpdateScheduleMirrorsResponses, UpdateScheduleNotificationsData, UpdateScheduleNotificationsResponses, UpdateSsoProviderAutoLinkingData, UpdateSsoProviderAutoLinkingErrors, UpdateSsoProviderAutoLinkingResponses, UpdateVolumeData, UpdateVolumeErrors, UpdateVolumeResponses } from './types.gen';
|
import type { BrowseFilesystemData, BrowseFilesystemResponses, CancelDoctorData, CancelDoctorErrors, CancelDoctorResponses, CreateBackupScheduleData, CreateBackupScheduleResponses, CreateNotificationDestinationData, CreateNotificationDestinationResponses, CreateRepositoryData, CreateRepositoryResponses, CreateVolumeData, CreateVolumeResponses, DeleteBackupScheduleData, DeleteBackupScheduleResponses, DeleteNotificationDestinationData, DeleteNotificationDestinationErrors, DeleteNotificationDestinationResponses, DeleteRepositoryData, DeleteRepositoryResponses, DeleteSnapshotData, DeleteSnapshotResponses, DeleteSnapshotsData, DeleteSnapshotsResponses, DeleteSsoInvitationData, DeleteSsoInvitationErrors, DeleteSsoInvitationResponses, DeleteSsoProviderData, DeleteSsoProviderErrors, DeleteSsoProviderResponses, DeleteUserAccountData, DeleteUserAccountErrors, DeleteUserAccountResponses, DeleteVolumeData, DeleteVolumeResponses, DevPanelExecData, DevPanelExecErrors, DevPanelExecResponse, DevPanelExecResponses, DownloadResticPasswordData, DownloadResticPasswordResponses, DumpSnapshotData, DumpSnapshotResponses, GetAdminUsersData, GetAdminUsersResponses, GetBackupProgressData, GetBackupProgressResponses, GetBackupScheduleData, GetBackupScheduleForVolumeData, GetBackupScheduleForVolumeResponses, GetBackupScheduleResponses, GetDevPanelData, GetDevPanelResponses, GetMirrorCompatibilityData, GetMirrorCompatibilityResponses, GetNotificationDestinationData, GetNotificationDestinationErrors, GetNotificationDestinationResponses, GetOrgMembersData, GetOrgMembersResponses, GetPublicSsoProvidersData, GetPublicSsoProvidersResponses, GetRegistrationStatusData, GetRegistrationStatusResponses, GetRepositoryData, GetRepositoryResponses, GetRepositoryStatsData, GetRepositoryStatsResponses, GetScheduleMirrorsData, GetScheduleMirrorsResponses, GetScheduleNotificationsData, GetScheduleNotificationsResponses, GetSnapshotDetailsData, GetSnapshotDetailsResponses, GetSsoSettingsData, GetSsoSettingsResponses, GetStatusData, GetStatusResponses, GetSystemInfoData, GetSystemInfoResponses, GetUpdatesData, GetUpdatesResponses, GetUserDeletionImpactData, GetUserDeletionImpactResponses, GetVolumeData, GetVolumeErrors, GetVolumeResponses, HealthCheckVolumeData, HealthCheckVolumeErrors, HealthCheckVolumeResponses, ListBackupSchedulesData, ListBackupSchedulesResponses, ListFilesData, ListFilesResponses, ListNotificationDestinationsData, ListNotificationDestinationsResponses, ListRcloneRemotesData, ListRcloneRemotesResponses, ListRepositoriesData, ListRepositoriesResponses, ListSnapshotFilesData, ListSnapshotFilesResponses, ListSnapshotsData, ListSnapshotsResponses, ListVolumesData, ListVolumesResponses, MountVolumeData, MountVolumeResponses, RefreshRepositoryStatsData, RefreshRepositoryStatsResponses, RefreshSnapshotsData, RefreshSnapshotsResponses, RemoveOrgMemberData, RemoveOrgMemberErrors, RemoveOrgMemberResponses, ReorderBackupSchedulesData, ReorderBackupSchedulesResponses, RestoreSnapshotData, RestoreSnapshotResponses, RunBackupNowData, RunBackupNowResponses, RunForgetData, RunForgetResponses, SetRegistrationStatusData, SetRegistrationStatusResponses, StartDoctorData, StartDoctorErrors, StartDoctorResponses, StopBackupData, StopBackupErrors, StopBackupResponses, TagSnapshotsData, TagSnapshotsResponses, TestConnectionData, TestConnectionResponses, TestNotificationDestinationData, TestNotificationDestinationErrors, TestNotificationDestinationResponses, UnlockRepositoryData, UnlockRepositoryResponses, UnmountVolumeData, UnmountVolumeResponses, UpdateBackupScheduleData, UpdateBackupScheduleResponses, UpdateMemberRoleData, UpdateMemberRoleErrors, UpdateMemberRoleResponses, UpdateNotificationDestinationData, UpdateNotificationDestinationErrors, UpdateNotificationDestinationResponses, UpdateRepositoryData, UpdateRepositoryErrors, UpdateRepositoryResponses, UpdateScheduleMirrorsData, UpdateScheduleMirrorsResponses, UpdateScheduleNotificationsData, UpdateScheduleNotificationsResponses, UpdateSsoProviderAutoLinkingData, UpdateSsoProviderAutoLinkingErrors, UpdateSsoProviderAutoLinkingResponses, UpdateVolumeData, UpdateVolumeErrors, UpdateVolumeResponses } from './types.gen';
|
||||||
|
|
||||||
export type Options<TData extends TDataShape = TDataShape, ThrowOnError extends boolean = boolean> = Options2<TData, ThrowOnError> & {
|
export type Options<TData extends TDataShape = TDataShape, ThrowOnError extends boolean = boolean, TResponse = unknown> = Options2<TData, ThrowOnError, TResponse> & {
|
||||||
/**
|
/**
|
||||||
* You can provide a client instance returned by `createClient()` instead of
|
* You can provide a client instance returned by `createClient()` instead of
|
||||||
* individual options. This might be also useful if you want to implement a
|
* individual options. This might be also useful if you want to implement a
|
||||||
|
|
@ -307,7 +307,7 @@ export const tagSnapshots = <ThrowOnError extends boolean = false>(options: Opti
|
||||||
/**
|
/**
|
||||||
* Execute a restic command against a repository (dev panel only)
|
* Execute a restic command against a repository (dev panel only)
|
||||||
*/
|
*/
|
||||||
export const devPanelExec = <ThrowOnError extends boolean = false>(options: Options<DevPanelExecData, ThrowOnError>) => (options.client ?? client).sse.post<DevPanelExecResponses, DevPanelExecErrors, ThrowOnError>({
|
export const devPanelExec = <ThrowOnError extends boolean = false>(options: Options<DevPanelExecData, ThrowOnError, DevPanelExecResponse>) => (options.client ?? client).sse.post<DevPanelExecResponses, DevPanelExecErrors, ThrowOnError>({
|
||||||
url: '/api/v1/repositories/{shortId}/exec',
|
url: '/api/v1/repositories/{shortId}/exec',
|
||||||
...options,
|
...options,
|
||||||
headers: {
|
headers: {
|
||||||
|
|
|
||||||
|
|
@ -3526,7 +3526,6 @@ export type GetScheduleNotificationsResponses = {
|
||||||
} | {
|
} | {
|
||||||
type: 'slack';
|
type: 'slack';
|
||||||
webhookUrl: string;
|
webhookUrl: string;
|
||||||
channel?: string;
|
|
||||||
username?: string;
|
username?: string;
|
||||||
iconEmoji?: string;
|
iconEmoji?: string;
|
||||||
} | {
|
} | {
|
||||||
|
|
@ -3628,7 +3627,6 @@ export type UpdateScheduleNotificationsResponses = {
|
||||||
} | {
|
} | {
|
||||||
type: 'slack';
|
type: 'slack';
|
||||||
webhookUrl: string;
|
webhookUrl: string;
|
||||||
channel?: string;
|
|
||||||
username?: string;
|
username?: string;
|
||||||
iconEmoji?: string;
|
iconEmoji?: string;
|
||||||
} | {
|
} | {
|
||||||
|
|
@ -4203,7 +4201,6 @@ export type ListNotificationDestinationsResponses = {
|
||||||
} | {
|
} | {
|
||||||
type: 'slack';
|
type: 'slack';
|
||||||
webhookUrl: string;
|
webhookUrl: string;
|
||||||
channel?: string;
|
|
||||||
username?: string;
|
username?: string;
|
||||||
iconEmoji?: string;
|
iconEmoji?: string;
|
||||||
} | {
|
} | {
|
||||||
|
|
@ -4273,7 +4270,6 @@ export type CreateNotificationDestinationData = {
|
||||||
} | {
|
} | {
|
||||||
type: 'slack';
|
type: 'slack';
|
||||||
webhookUrl: string;
|
webhookUrl: string;
|
||||||
channel?: string;
|
|
||||||
username?: string;
|
username?: string;
|
||||||
iconEmoji?: string;
|
iconEmoji?: string;
|
||||||
} | {
|
} | {
|
||||||
|
|
@ -4348,7 +4344,6 @@ export type CreateNotificationDestinationResponses = {
|
||||||
} | {
|
} | {
|
||||||
type: 'slack';
|
type: 'slack';
|
||||||
webhookUrl: string;
|
webhookUrl: string;
|
||||||
channel?: string;
|
|
||||||
username?: string;
|
username?: string;
|
||||||
iconEmoji?: string;
|
iconEmoji?: string;
|
||||||
} | {
|
} | {
|
||||||
|
|
@ -4467,7 +4462,6 @@ export type GetNotificationDestinationResponses = {
|
||||||
} | {
|
} | {
|
||||||
type: 'slack';
|
type: 'slack';
|
||||||
webhookUrl: string;
|
webhookUrl: string;
|
||||||
channel?: string;
|
|
||||||
username?: string;
|
username?: string;
|
||||||
iconEmoji?: string;
|
iconEmoji?: string;
|
||||||
} | {
|
} | {
|
||||||
|
|
@ -4538,7 +4532,6 @@ export type UpdateNotificationDestinationData = {
|
||||||
} | {
|
} | {
|
||||||
type: 'slack';
|
type: 'slack';
|
||||||
webhookUrl: string;
|
webhookUrl: string;
|
||||||
channel?: string;
|
|
||||||
username?: string;
|
username?: string;
|
||||||
iconEmoji?: string;
|
iconEmoji?: string;
|
||||||
} | {
|
} | {
|
||||||
|
|
@ -4622,7 +4615,6 @@ export type UpdateNotificationDestinationResponses = {
|
||||||
} | {
|
} | {
|
||||||
type: 'slack';
|
type: 'slack';
|
||||||
webhookUrl: string;
|
webhookUrl: string;
|
||||||
channel?: string;
|
|
||||||
username?: string;
|
username?: string;
|
||||||
iconEmoji?: string;
|
iconEmoji?: string;
|
||||||
} | {
|
} | {
|
||||||
|
|
|
||||||
|
|
@ -75,7 +75,6 @@ const defaultValuesForType = {
|
||||||
slack: {
|
slack: {
|
||||||
type: "slack" as const,
|
type: "slack" as const,
|
||||||
webhookUrl: "",
|
webhookUrl: "",
|
||||||
channel: "",
|
|
||||||
username: "",
|
username: "",
|
||||||
iconEmoji: "",
|
iconEmoji: "",
|
||||||
},
|
},
|
||||||
|
|
|
||||||
|
|
@ -27,20 +27,6 @@ export const SlackForm = ({ form }: Props) => {
|
||||||
</FormItem>
|
</FormItem>
|
||||||
)}
|
)}
|
||||||
/>
|
/>
|
||||||
<FormField
|
|
||||||
control={form.control}
|
|
||||||
name="channel"
|
|
||||||
render={({ field }) => (
|
|
||||||
<FormItem>
|
|
||||||
<FormLabel>Channel (Optional)</FormLabel>
|
|
||||||
<FormControl>
|
|
||||||
<Input {...field} placeholder="#backups" />
|
|
||||||
</FormControl>
|
|
||||||
<FormDescription>Override the default channel (use # for channels, @ for users).</FormDescription>
|
|
||||||
<FormMessage />
|
|
||||||
</FormItem>
|
|
||||||
)}
|
|
||||||
/>
|
|
||||||
<FormField
|
<FormField
|
||||||
control={form.control}
|
control={form.control}
|
||||||
name="username"
|
name="username"
|
||||||
|
|
|
||||||
|
|
@ -78,7 +78,6 @@ function NotificationConfigRows({ config }: { config: NotificationConfig }) {
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<ConfigRow icon={<Globe className="h-4 w-4" />} label="Webhook URL" value={config.webhookUrl} mono />
|
<ConfigRow icon={<Globe className="h-4 w-4" />} label="Webhook URL" value={config.webhookUrl} mono />
|
||||||
<ConfigRow icon={<Hash className="h-4 w-4" />} label="Channel" value={config.channel || "—"} />
|
|
||||||
<ConfigRow icon={<Bot className="h-4 w-4" />} label="Bot Username" value={config.username || "—"} />
|
<ConfigRow icon={<Bot className="h-4 w-4" />} label="Bot Username" value={config.username || "—"} />
|
||||||
<ConfigRow icon={<Smile className="h-4 w-4" />} label="Icon Emoji" value={config.iconEmoji || "—"} />
|
<ConfigRow icon={<Smile className="h-4 w-4" />} label="Icon Emoji" value={config.iconEmoji || "—"} />
|
||||||
</>
|
</>
|
||||||
|
|
|
||||||
|
|
@ -29,7 +29,6 @@ export const emailNotificationConfigSchema = z.object({
|
||||||
export const slackNotificationConfigSchema = z.object({
|
export const slackNotificationConfigSchema = z.object({
|
||||||
type: z.literal("slack"),
|
type: z.literal("slack"),
|
||||||
webhookUrl: z.string().min(1),
|
webhookUrl: z.string().min(1),
|
||||||
channel: z.string().optional(),
|
|
||||||
username: z.string().optional(),
|
username: z.string().optional(),
|
||||||
iconEmoji: z.string().optional(),
|
iconEmoji: z.string().optional(),
|
||||||
});
|
});
|
||||||
|
|
|
||||||
|
|
@ -152,7 +152,7 @@ describe("notification shoutrrr URL builders", () => {
|
||||||
).toBe("pushover://shoutrrr:api-token@user-key/?devices=iphone%2Cipad&priority=1");
|
).toBe("pushover://shoutrrr:api-token@user-key/?devices=iphone%2Cipad&priority=1");
|
||||||
});
|
});
|
||||||
|
|
||||||
test("builds slack URLs and rejects invalid webhook formats", () => {
|
test("builds upstream-compatible slack webhook URLs and rejects invalid webhook formats", () => {
|
||||||
expect(
|
expect(
|
||||||
buildSlackShoutrrrUrl({
|
buildSlackShoutrrrUrl({
|
||||||
type: "slack",
|
type: "slack",
|
||||||
|
|
@ -164,11 +164,10 @@ describe("notification shoutrrr URL builders", () => {
|
||||||
buildSlackShoutrrrUrl({
|
buildSlackShoutrrrUrl({
|
||||||
type: "slack",
|
type: "slack",
|
||||||
webhookUrl: "https://hooks.slack.com/services/T000/B000/XXX",
|
webhookUrl: "https://hooks.slack.com/services/T000/B000/XXX",
|
||||||
channel: "#alerts",
|
|
||||||
username: "Alert Bot",
|
username: "Alert Bot",
|
||||||
iconEmoji: ":robot_face:",
|
iconEmoji: ":robot_face:",
|
||||||
}),
|
}),
|
||||||
).toBe("slack://hook:T000-B000-XXX@webhook?channel=%23alerts&username=Alert+Bot&icon_emoji=%3Arobot_face%3A");
|
).toBe("slack://hook:T000-B000-XXX@webhook?username=Alert+Bot&icon_emoji=%3Arobot_face%3A");
|
||||||
|
|
||||||
expect(() =>
|
expect(() =>
|
||||||
buildSlackShoutrrrUrl({
|
buildSlackShoutrrrUrl({
|
||||||
|
|
|
||||||
|
|
@ -7,7 +7,6 @@ describe("mapNotificationConfigSecrets", () => {
|
||||||
{
|
{
|
||||||
type: "slack",
|
type: "slack",
|
||||||
webhookUrl: "https://hooks.slack.test/services/a/b/c",
|
webhookUrl: "https://hooks.slack.test/services/a/b/c",
|
||||||
channel: "#alerts",
|
|
||||||
username: "zerobyte",
|
username: "zerobyte",
|
||||||
iconEmoji: ":wave:",
|
iconEmoji: ":wave:",
|
||||||
},
|
},
|
||||||
|
|
@ -17,7 +16,6 @@ describe("mapNotificationConfigSecrets", () => {
|
||||||
expect(transformed).toEqual({
|
expect(transformed).toEqual({
|
||||||
type: "slack",
|
type: "slack",
|
||||||
webhookUrl: "sealed:https://hooks.slack.test/services/a/b/c",
|
webhookUrl: "sealed:https://hooks.slack.test/services/a/b/c",
|
||||||
channel: "#alerts",
|
|
||||||
username: "zerobyte",
|
username: "zerobyte",
|
||||||
iconEmoji: ":wave:",
|
iconEmoji: ":wave:",
|
||||||
});
|
});
|
||||||
|
|
|
||||||
|
|
@ -14,9 +14,6 @@ export const buildSlackShoutrrrUrl = (config: Extract<NotificationConfig, { type
|
||||||
shoutrrrUrl.password = `${tokenA}-${tokenB}-${tokenC}`;
|
shoutrrrUrl.password = `${tokenA}-${tokenB}-${tokenC}`;
|
||||||
shoutrrrUrl.hostname = "webhook";
|
shoutrrrUrl.hostname = "webhook";
|
||||||
|
|
||||||
if (config.channel) {
|
|
||||||
shoutrrrUrl.searchParams.append("channel", config.channel);
|
|
||||||
}
|
|
||||||
if (config.username) {
|
if (config.username) {
|
||||||
shoutrrrUrl.searchParams.append("username", config.username);
|
shoutrrrUrl.searchParams.append("username", config.username);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue