Skip to content

Commit

Permalink
feat: in-platform notification channels
Browse files Browse the repository at this point in the history
- Add new feature flag for in-platform notification channels.
- Hide in-platform notification channels behind the feature flag.
- Add `assertNever` utility type for safe exhaustiveness checks.
- Align notification channels with our model/spi conventions.
- Add possibility to query / filter notification channels.
- Make convertors safer (when converting unknown notification channel,
it's filtered now - before it thrown error).
- Adjust all usages of notification channels to new model.

risk: low
JIRA: F1-928
  • Loading branch information
kandl committed Nov 27, 2024
1 parent 24ead1c commit 9174a82
Show file tree
Hide file tree
Showing 40 changed files with 1,268 additions and 899 deletions.
2 changes: 1 addition & 1 deletion libs/api-client-tiger/api/api-client-tiger.api.md
Original file line number Diff line number Diff line change
Expand Up @@ -14881,7 +14881,7 @@ export type MetadataGetEntitiesOptions = {
export type MetadataGetEntitiesParams = MetadataGetEntitiesWorkspaceParams | MetadataGetEntitiesUserParams | MetadataGetEntitiesThemeParams | MetadataGetEntitiesColorPaletteParams;

// @internal
export type MetadataGetEntitiesResult = JsonApiVisualizationObjectOutList | JsonApiAnalyticalDashboardOutList | JsonApiDashboardPluginOutList | JsonApiDatasetOutList | JsonApiAttributeOutList | JsonApiLabelOutList | JsonApiMetricOutList | JsonApiFactOutList | JsonApiFilterContextOutList | JsonApiApiTokenOutList | JsonApiThemeOutList | JsonApiColorPaletteOutList | JsonApiExportDefinitionOutList | JsonApiAutomationOutList | JsonApiUserOutList;
export type MetadataGetEntitiesResult = JsonApiVisualizationObjectOutList | JsonApiAnalyticalDashboardOutList | JsonApiDashboardPluginOutList | JsonApiDatasetOutList | JsonApiAttributeOutList | JsonApiLabelOutList | JsonApiMetricOutList | JsonApiFactOutList | JsonApiFilterContextOutList | JsonApiApiTokenOutList | JsonApiThemeOutList | JsonApiColorPaletteOutList | JsonApiExportDefinitionOutList | JsonApiAutomationOutList | JsonApiUserOutList | JsonApiNotificationChannelOutList;

// @internal
export type MetadataGetEntitiesThemeParams = {
Expand Down
4 changes: 3 additions & 1 deletion libs/api-client-tiger/src/metadataUtilities.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ import {
JsonApiExportDefinitionOutList,
JsonApiAutomationOutList,
JsonApiUserOutList,
JsonApiNotificationChannelOutList,
} from "./generated/metadata-json-api/index.js";

const DefaultPageSize = 250;
Expand Down Expand Up @@ -124,7 +125,8 @@ export type MetadataGetEntitiesResult =
| JsonApiColorPaletteOutList
| JsonApiExportDefinitionOutList
| JsonApiAutomationOutList
| JsonApiUserOutList;
| JsonApiUserOutList
| JsonApiNotificationChannelOutList;

/**
* All API client getEntities* functions follow this signature.
Expand Down
63 changes: 9 additions & 54 deletions libs/sdk-backend-base/src/dummyBackend/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -123,14 +123,11 @@ import {
defWithBuckets,
IRelativeDateFilter,
IAbsoluteDateFilter,
IWebhookDefinitionObject,
IWebhookDefinition,
ISmtpDefinitionObject,
ISmtpDefinition,
IAutomationMetadataObjectDefinition,
IAutomationMetadataObject,
ILlmEndpointOpenAI,
ISeparators,
INotificationChannelMetadataObject,
} from "@gooddata/sdk-model";
import isEqual from "lodash/isEqual.js";
import isEmpty from "lodash/isEmpty.js";
Expand Down Expand Up @@ -883,59 +880,17 @@ class DummyOrganization implements IOrganization {

notificationChannels(): IOrganizationNotificationChannelService {
return {
getCount: () => Promise.resolve(0),
getAll: () => Promise.resolve([]),
deleteChannel: () => Promise.resolve(),
testChannel: () =>
testNotificationChannel: () =>
Promise.resolve({
successful: true,
}),
//emails
createEmail: (webhook: ISmtpDefinition) =>
Promise.resolve({
...(webhook as ISmtpDefinitionObject),
id: "dummySmtp",
}),
deleteEmail: () => Promise.resolve(),
getEmail: () =>
Promise.resolve({
id: "dummySmtp",
type: "smtp",
triggers: [],
destination: {
type: "custom",
name: "",
address: "",
login: "",
password: "",
person: "",
from: "",
hasPassword: true,
port: 25,
},
}),
getEmails: () => Promise.resolve([]),
updateEmail: (smtp) => Promise.resolve(smtp),
//webhooks
createWebhook: (webhook: IWebhookDefinition) =>
Promise.resolve({
...(webhook as IWebhookDefinitionObject),
id: "dummyWebhook",
}),
deleteWebhook: () => Promise.resolve(),
getWebhook: () =>
Promise.resolve({
id: "dummyWebhook",
type: "webhook",
destination: {
name: "Dummy webhook",
endpoint: "https://dummy.webhook",
token: "dummyToken",
},
triggers: [],
}),
getWebhooks: () => Promise.resolve([]),
updateWebhook: (webhook) => Promise.resolve(webhook),
getNotificationChannel: () => Promise.resolve({} as INotificationChannelMetadataObject),
createNotificationChannel: () => Promise.resolve({} as INotificationChannelMetadataObject),
updateNotificationChannel: () => Promise.resolve({} as INotificationChannelMetadataObject),
deleteNotificationChannel: () => Promise.resolve(),
getNotificationChannelsQuery: () => {
throw new NotSupported("not supported");
},
};
}

Expand Down
97 changes: 0 additions & 97 deletions libs/sdk-backend-base/src/dummyBackend/tests/index.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,103 +6,6 @@ import { dummyBackend } from "../index.js";
import { idRef } from "@gooddata/sdk-model";

describe("dummyBackend", () => {
describe("organization", () => {
describe("notificationChannels", () => {
const ORGANIZATION_ID = "myOrganizationId";

it("empty list of webhooks", async () => {
const data = await dummyBackend()
.organization(ORGANIZATION_ID)
.notificationChannels()
.getWebhooks();

expect(data).toEqual([]);
});

it("create webhook", async () => {
const data = await dummyBackend()
.organization(ORGANIZATION_ID)
.notificationChannels()
.createWebhook({
name: "name",
endpoint: "endpoint",
token: "token",
triggers: [
{
type: "SCHEDULE",
allowOn: ["dashboard", "visualization"],
},
{
type: "ALERT",
},
],
});

expect(data).toEqual({
endpoint: "endpoint",
id: "dummyWebhook",
name: "name",
token: "token",
triggers: [
{
allowOn: ["dashboard", "visualization"],
type: "SCHEDULE",
},
{
type: "ALERT",
},
],
});
});

it("update webhook", async () => {
const data = await dummyBackend()
.organization(ORGANIZATION_ID)
.notificationChannels()
.updateWebhook({
id: "webhook-id",
name: "name",
endpoint: "endpoint",
token: "token",
triggers: [
{
type: "SCHEDULE",
allowOn: ["dashboard", "visualization"],
},
{
type: "ALERT",
},
],
});

expect(data).toEqual({
endpoint: "endpoint",
id: "webhook-id",
name: "name",
token: "token",
triggers: [
{
allowOn: ["dashboard", "visualization"],
type: "SCHEDULE",
},
{
type: "ALERT",
},
],
});
});

it("delete webhook", async () => {
const data = await dummyBackend()
.organization(ORGANIZATION_ID)
.notificationChannels()
.deleteWebhook("webhook-id");

expect(data).toBeUndefined();
});
});
});

describe("workspace", () => {
const WORKSPACE_ID = "workspaceId";

Expand Down
63 changes: 9 additions & 54 deletions libs/sdk-backend-mockingbird/src/recordedBackend/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -65,13 +65,10 @@ import {
IThemeMetadataObject,
IUser,
IWorkspacePermissions,
IWebhookDefinition,
IWebhookDefinitionObject,
ISmtpDefinition,
ISmtpDefinitionObject,
idRef,
ObjRef,
ILlmEndpointOpenAI,
INotificationChannelMetadataObject,
} from "@gooddata/sdk-model";
import RecordedAttributeHierarchiesService from "./attributeHierarchies.js";
import { RecordedAttributes } from "./attributes.js";
Expand Down Expand Up @@ -460,59 +457,17 @@ function recordedOrganization(organizationId: string, implConfig: RecordedBacken
},
notificationChannels(): IOrganizationNotificationChannelService {
return {
getCount: () => Promise.resolve(0),
getAll: () => Promise.resolve([]),
deleteChannel: () => Promise.resolve(),
testChannel: () =>
testNotificationChannel: () =>
Promise.resolve({
successful: true,
}),
//emails
createEmail: (webhook: ISmtpDefinition) =>
Promise.resolve({
...(webhook as ISmtpDefinitionObject),
id: "dummySmtp",
}),
deleteEmail: () => Promise.resolve(),
getEmail: () =>
Promise.resolve({
id: "dummySmtp",
type: "smtp",
triggers: [],
destination: {
type: "custom",
name: "",
address: "",
person: "",
login: "",
password: "",
from: "",
hasPassword: true,
port: 25,
},
}),
getEmails: () => Promise.resolve([]),
updateEmail: (smtp) => Promise.resolve(smtp),
//webhooks
createWebhook: (webhook: IWebhookDefinition) =>
Promise.resolve({
...(webhook as IWebhookDefinitionObject),
id: "dummyWebhook",
}),
deleteWebhook: () => Promise.resolve(),
getWebhook: () =>
Promise.resolve({
id: "dummyWebhook",
type: "webhook",
destination: {
name: "Dummy webhook",
endpoint: "https://dummy.webhook",
token: "dummyToken",
},
triggers: [],
}),
getWebhooks: () => Promise.resolve([]),
updateWebhook: (webhook) => Promise.resolve(webhook),
getNotificationChannel: () => Promise.resolve({} as INotificationChannelMetadataObject),
createNotificationChannel: () => Promise.resolve({} as INotificationChannelMetadataObject),
updateNotificationChannel: () => Promise.resolve({} as INotificationChannelMetadataObject),
deleteNotificationChannel: () => Promise.resolve(),
getNotificationChannelsQuery: () => {
throw new NotSupported("not supported");
},
};
},
permissions(): IOrganizationPermissionService {
Expand Down
45 changes: 25 additions & 20 deletions libs/sdk-backend-spi/api/sdk-backend-spi.api.md
Original file line number Diff line number Diff line change
Expand Up @@ -75,7 +75,8 @@ import { IMeasure } from '@gooddata/sdk-model';
import { IMeasureMetadataObject } from '@gooddata/sdk-model';
import { IMeasureMetadataObjectDefinition } from '@gooddata/sdk-model';
import { IMetadataObject } from '@gooddata/sdk-model';
import { INotificationChannelDefinitionObject } from '@gooddata/sdk-model';
import { INotificationChannelMetadataObject } from '@gooddata/sdk-model';
import { INotificationChannelMetadataObjectDefinition } from '@gooddata/sdk-model';
import { INotificationChannelTestResponse } from '@gooddata/sdk-model';
import { INullableFilter } from '@gooddata/sdk-model';
import { IOpenAiConfig } from '@gooddata/sdk-model';
Expand All @@ -94,17 +95,13 @@ import { ISemanticSearchRelationship } from '@gooddata/sdk-model';
import { ISemanticSearchResultItem } from '@gooddata/sdk-model';
import { ISeparators } from '@gooddata/sdk-model';
import { ISettings } from '@gooddata/sdk-model';
import { ISmtpDefinition } from '@gooddata/sdk-model';
import { ISmtpDefinitionObject } from '@gooddata/sdk-model';
import { ISortItem } from '@gooddata/sdk-model';
import { ITheme } from '@gooddata/sdk-model';
import { IThemeDefinition } from '@gooddata/sdk-model';
import { IThemeMetadataObject } from '@gooddata/sdk-model';
import { IUser } from '@gooddata/sdk-model';
import { IUserGroup } from '@gooddata/sdk-model';
import { IVisualizationClass } from '@gooddata/sdk-model';
import { IWebhookDefinition } from '@gooddata/sdk-model';
import { IWebhookDefinitionObject } from '@gooddata/sdk-model';
import { IWhiteLabeling } from '@gooddata/sdk-model';
import { IWidget } from '@gooddata/sdk-model';
import { IWidgetAlert } from '@gooddata/sdk-model';
Expand All @@ -117,6 +114,7 @@ import { IWorkspacePermissions } from '@gooddata/sdk-model';
import { IWorkspaceUser } from '@gooddata/sdk-model';
import { IWorkspaceUserGroup } from '@gooddata/sdk-model';
import { LlmEndpointOpenAIPatch } from '@gooddata/sdk-model';
import { NotificationChannelDestinationType } from '@gooddata/sdk-model';
import { ObjectType } from '@gooddata/sdk-model';
import { ObjRef } from '@gooddata/sdk-model';
import { OrganizationPermissionAssignment } from '@gooddata/sdk-model';
Expand Down Expand Up @@ -872,6 +870,19 @@ export interface IMeasureReferencing {
measures?: IMetadataObject[];
}

// @beta
export interface INotificationChannelsQuery {
query(): Promise<INotificationChannelsQueryResult>;
queryAll(): Promise<INotificationChannelMetadataObject[]>;
withPage(page: number): INotificationChannelsQuery;
withSize(size: number): INotificationChannelsQuery;
withSorting(sort: string[]): INotificationChannelsQuery;
withTypes(type: NotificationChannelDestinationType[]): INotificationChannelsQuery;
}

// @beta
export type INotificationChannelsQueryResult = IPagedResource<INotificationChannelMetadataObject>;

// @public
export type InsightOrdering = "id" | "title" | "updated";

Expand Down Expand Up @@ -911,22 +922,16 @@ export interface IOrganizationLlmEndpointsService {
updateLlmEndpoint(endpoint: ILlmEndpointOpenAI, token?: string): Promise<ILlmEndpointOpenAI>;
}

// @alpha
// @beta
export interface IOrganizationNotificationChannelService {
createEmail(smtp: ISmtpDefinition): Promise<ISmtpDefinitionObject>;
createWebhook(webhook: IWebhookDefinition): Promise<IWebhookDefinitionObject>;
deleteChannel(id: string): Promise<void>;
deleteEmail(id: string): Promise<void>;
deleteWebhook(id: string): Promise<void>;
getAll(): Promise<INotificationChannelDefinitionObject[]>;
getCount(): Promise<number>;
getEmail(id: string): Promise<ISmtpDefinitionObject>;
getEmails(): Promise<ISmtpDefinitionObject[]>;
getWebhook(id: string): Promise<IWebhookDefinitionObject>;
getWebhooks(): Promise<IWebhookDefinitionObject[]>;
testChannel(channel: Partial<IWebhookDefinition> | Partial<ISmtpDefinition>, notificationId?: string): Promise<INotificationChannelTestResponse>;
updateEmail(smtp: ISmtpDefinitionObject): Promise<ISmtpDefinitionObject>;
updateWebhook(webhook: IWebhookDefinitionObject): Promise<IWebhookDefinitionObject>;
// (undocumented)
createNotificationChannel(notificationChannel: INotificationChannelMetadataObjectDefinition): Promise<INotificationChannelMetadataObject>;
deleteNotificationChannel(id: string): Promise<void>;
// (undocumented)
getNotificationChannel(id: string): Promise<INotificationChannelMetadataObject>;
getNotificationChannelsQuery(): INotificationChannelsQuery;
testNotificationChannel(channel: INotificationChannelMetadataObjectDefinition): Promise<INotificationChannelTestResponse>;
updateNotificationChannel(notificationChannel: INotificationChannelMetadataObject): Promise<INotificationChannelMetadataObject>;
}

// @alpha
Expand Down
4 changes: 4 additions & 0 deletions libs/sdk-backend-spi/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -241,6 +241,10 @@ export type {
IPermissionsAssignment,
} from "./organization/permissions/index.js";
export type { IOrganizationNotificationChannelService } from "./organization/notificationChannels/index.js";
export type {
INotificationChannelsQuery,
INotificationChannelsQueryResult,
} from "./organization/notificationChannels/query.js";
export type { IDataFiltersService } from "./workspace/dataFilter/index.js";

export type { IWorkspaceLogicalModelService, IDateDataset } from "./workspace/ldm/model.js";
Expand Down
Loading

0 comments on commit 9174a82

Please sign in to comment.