Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
95 changes: 95 additions & 0 deletions src/lib/api-v1.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import { Props } from "@/lib/base-command";
import { InputError } from "@/lib/helpers/error";
import { prune } from "@/lib/helpers/object.isomorphic";
import { PaginatedResp, toPageParams } from "@/lib/helpers/page";
import * as Audience from "@/lib/marshal/audience";
import * as EmailLayout from "@/lib/marshal/email-layout";
import * as Guide from "@/lib/marshal/guide";
import * as MessageType from "@/lib/marshal/message-type";
Expand Down Expand Up @@ -550,6 +551,79 @@ export default class ApiV1 {
return this.put(`/guides/${args.guideKey}/activate`, {}, { params });
}

// By resources: Audiences

async listAudiences<A extends MaybeWithAnnotation>({
flags,
}: Props): Promise<AxiosResponse<ListAudienceResp<A>>> {
const params = prune({
environment: flags.environment,
branch: flags.branch,
hide_uncommitted_changes: flags["hide-uncommitted-changes"],
annotate: flags.annotate,
...toPageParams(flags),
});

return this.get("/audiences", { params });
}

async getAudience<A extends MaybeWithAnnotation>({
args,
flags,
}: Props): Promise<AxiosResponse<GetAudienceResp<A>>> {
const params = prune({
environment: flags.environment,
branch: flags.branch,
annotate: flags.annotate,
hide_uncommitted_changes: flags["hide-uncommitted-changes"],
});

return this.get(`/audiences/${args.audienceKey}`, { params });
}

async upsertAudience<A extends MaybeWithAnnotation>(
{ flags }: Props,
audience: Audience.AudienceInput,
): Promise<AxiosResponse<UpsertAudienceResp<A>>> {
const params = prune({
environment: flags.environment,
branch: flags.branch,
annotate: flags.annotate,
commit: flags.commit,
commit_message: flags["commit-message"],
});
const data = { audience };

return this.put(`/audiences/${audience.key}`, data, { params });
}

async validateAudience(
{ flags }: Props,
audience: Audience.AudienceInput,
): Promise<AxiosResponse<ValidateAudienceResp>> {
const params = prune({
environment: flags.environment,
branch: flags.branch,
});
const data = { audience };

return this.put(`/audiences/${audience.key}/validate`, data, {
params,
});
}

async archiveAudience({
args,
flags,
}: Props): Promise<AxiosResponse<ArchiveAudienceResp>> {
const params = prune({
environment: flags.environment,
branch: flags.branch,
});

return this.put(`/audiences/${args.audienceKey}/archive`, {}, { params });
}

async listAllChannels(): Promise<Channel[]> {
const channels: Channel[] = [];
for await (const channel of this.mgmtClient.channels.list()) {
Expand Down Expand Up @@ -732,3 +806,24 @@ export type ActivateGuideResp = {
};

export type ListBranchResp = PaginatedResp<Branch>;

export type ListAudienceResp<A extends MaybeWithAnnotation = unknown> =
PaginatedResp<Audience.AudienceData<A>>;

export type GetAudienceResp<A extends MaybeWithAnnotation = unknown> =
Audience.AudienceData<A>;

export type UpsertAudienceResp<A extends MaybeWithAnnotation = unknown> = {
audience?: Audience.AudienceData<A>;
errors?: InputError[];
};

export type ValidateAudienceResp = {
audience?: Audience.AudienceData;
errors?: InputError[];
};

export type ArchiveAudienceResp = {
audience?: Audience.AudienceData;
errors?: InputError[];
};
5 changes: 3 additions & 2 deletions src/lib/helpers/project-config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -113,8 +113,9 @@ export const findAndReadProjectConfig = async (): Promise<
* Resource subdirectory names as they appear in the knock directory.
*/

// Note: "audience" is excluded until audience pull/push commands are implemented
export const ResourceDirectoriesByType: Record<
Exclude<ResourceType, "reusable_step">,
Exclude<ResourceType, "reusable_step" | "audience">,
string
> = {
workflow: "workflows",
Expand All @@ -125,7 +126,7 @@ export const ResourceDirectoriesByType: Record<
translation: "translations",
} as const;

type ValidResourceType = Exclude<ResourceType, "reusable_step">;
type ValidResourceType = Exclude<ResourceType, "reusable_step" | "audience">;

/**
* Resolves the full path to a resource directory within the knock directory.
Expand Down
1 change: 1 addition & 0 deletions src/lib/marshal/audience/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export * from "./types";
35 changes: 35 additions & 0 deletions src/lib/marshal/audience/types.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
import { AnyObj } from "@/lib/helpers/object.isomorphic";

import { MaybeWithAnnotation } from "../shared/types";

export enum AudienceType {
Static = "static",
Dynamic = "dynamic",
}

export type AudienceCondition = {
property: string;
operator: string;
argument?: string;
};

export type AudienceSegment = {
conditions: AudienceCondition[];
};

// Audience payload data from the API.
export type AudienceData<A extends MaybeWithAnnotation = unknown> = A & {
key: string;
type: AudienceType;
name: string;
description?: string;
segments?: AudienceSegment[];
environment: string;
created_at: string;
updated_at: string;
sha: string;
};

export type AudienceInput = AnyObj & {
key: string;
};
6 changes: 5 additions & 1 deletion src/lib/resources.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,11 @@
import type { ResourceType } from "./run-context";

// TODO Remove this once hidden option is removed from message types / guides
export type NonHiddenResourceType = Exclude<ResourceType, "reusable_step">;
// Note: "audience" is excluded until audience pull/push commands are implemented
export type NonHiddenResourceType = Exclude<
ResourceType,
"reusable_step" | "audience"
>;

/**
* An ordered array of all resource types.
Expand Down
6 changes: 6 additions & 0 deletions src/lib/run-context/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ export type T = RunContext;
*/

export type ResourceType =
| "audience"
| "workflow"
| "email_layout"
| "translation"
Expand All @@ -30,6 +31,10 @@ type ResourceDirContextBase = DirContext & {
key: string;
};

export type AudienceDirContext = ResourceDirContextBase & {
type: "audience";
};

export type WorkflowDirContext = ResourceDirContextBase & {
type: "workflow";
};
Expand Down Expand Up @@ -59,6 +64,7 @@ export type ReusableStepDirContext = ResourceDirContextBase & {
};

export type ResourceDirContext =
| AudienceDirContext
| WorkflowDirContext
| EmailLayoutDirContext
| TranslationDirContext
Expand Down
8 changes: 8 additions & 0 deletions src/lib/urls.ts
Original file line number Diff line number Diff line change
Expand Up @@ -47,3 +47,11 @@ export const viewPartialUrl = (
partialKey: string,
): string =>
`${dashboardUrl}/${accountSlug}/${envOrBranchSlug.toLowerCase()}/partials/${partialKey}`;

export const viewAudienceUrl = (
dashboardUrl: string,
accountSlug: string,
envOrBranchSlug: string,
audienceKey: string,
): string =>
`${dashboardUrl}/${accountSlug}/${envOrBranchSlug.toLowerCase()}/audiences/${audienceKey}`;
Loading