feat: Add Slack notifications (save for later) support
This commit is contained in:
@@ -5,6 +5,7 @@
|
|||||||
### Added
|
### Added
|
||||||
|
|
||||||
- Add Linear Project and Team icons
|
- Add Linear Project and Team icons
|
||||||
|
- Add Slack notifications (ie. save for later) support
|
||||||
|
|
||||||
## [0.1.3] - 2024-02-05
|
## [0.1.3] - 2024-02-05
|
||||||
|
|
||||||
|
|||||||
@@ -92,7 +92,6 @@ async function linkNotificationToTask(
|
|||||||
if (page) {
|
if (page) {
|
||||||
page.content = page.content.filter((n) => n.id !== notification.id);
|
page.content = page.content.filter((n) => n.id !== notification.id);
|
||||||
}
|
}
|
||||||
console.log(`page(link): ${notification.id}`, page);
|
|
||||||
return page;
|
return page;
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ import { GoogleMailNotificationListItem } from "./integrations/google-mail/listi
|
|||||||
import { TodoistNotificationListItem } from "./integrations/todoist/listitem/TodoistNotificationListItem";
|
import { TodoistNotificationListItem } from "./integrations/todoist/listitem/TodoistNotificationListItem";
|
||||||
import { GithubNotificationListItem } from "./integrations/github/listitem/GithubNotificationListItem";
|
import { GithubNotificationListItem } from "./integrations/github/listitem/GithubNotificationListItem";
|
||||||
import { LinearNotificationListItem } from "./integrations/linear/listitem/LinearNotificationListItem";
|
import { LinearNotificationListItem } from "./integrations/linear/listitem/LinearNotificationListItem";
|
||||||
|
import { SlackNotificationListItem } from "./integrations/slack/listitem/SlackNotificationListItem";
|
||||||
import { Notification, NotificationListItemProps } from "./notification";
|
import { Notification, NotificationListItemProps } from "./notification";
|
||||||
import { NotificationActions } from "./action/NotificationActions";
|
import { NotificationActions } from "./action/NotificationActions";
|
||||||
import { Page, UniversalInboxPreferences } from "./types";
|
import { Page, UniversalInboxPreferences } from "./types";
|
||||||
@@ -73,6 +74,8 @@ function NotificationListItem({ notification, mutate }: NotificationListItemProp
|
|||||||
return <LinearNotificationListItem notification={notification} mutate={mutate} />;
|
return <LinearNotificationListItem notification={notification} mutate={mutate} />;
|
||||||
case "GoogleMail":
|
case "GoogleMail":
|
||||||
return <GoogleMailNotificationListItem notification={notification} mutate={mutate} />;
|
return <GoogleMailNotificationListItem notification={notification} mutate={mutate} />;
|
||||||
|
case "Slack":
|
||||||
|
return <SlackNotificationListItem notification={notification} mutate={mutate} />;
|
||||||
case "Todoist":
|
case "Todoist":
|
||||||
return <TodoistNotificationListItem notification={notification} mutate={mutate} />;
|
return <TodoistNotificationListItem notification={notification} mutate={mutate} />;
|
||||||
default:
|
default:
|
||||||
@@ -110,6 +113,7 @@ function NotificationKindDropdown({ value, onNotificationKindChange }: Notificat
|
|||||||
<List.Dropdown.Item key="Github" title="Github" value="Github" />
|
<List.Dropdown.Item key="Github" title="Github" value="Github" />
|
||||||
<List.Dropdown.Item key="Linear" title="Linear" value="Linear" />
|
<List.Dropdown.Item key="Linear" title="Linear" value="Linear" />
|
||||||
<List.Dropdown.Item key="GoogleMail" title="Google Mail" value="GoogleMail" />
|
<List.Dropdown.Item key="GoogleMail" title="Google Mail" value="GoogleMail" />
|
||||||
|
<List.Dropdown.Item key="Slack" title="Slack" value="Slack" />
|
||||||
<List.Dropdown.Item key="Todoist" title="Todoist" value="Todoist" />
|
<List.Dropdown.Item key="Todoist" title="Todoist" value="Todoist" />
|
||||||
</List.Dropdown.Section>
|
</List.Dropdown.Section>
|
||||||
</List.Dropdown>
|
</List.Dropdown>
|
||||||
|
|||||||
147
src/integrations/slack/listitem/SlackNotificationListItem.tsx
Normal file
147
src/integrations/slack/listitem/SlackNotificationListItem.tsx
Normal file
@@ -0,0 +1,147 @@
|
|||||||
|
import { NotificationDetails, NotificationListItemProps } from "../../../notification";
|
||||||
|
import { NotificationActions } from "../../../action/NotificationActions";
|
||||||
|
import { SlackStarPreview } from "../preview/SlackStarPreview";
|
||||||
|
import { SlackBotInfo, SlackIcon, SlackUser } from "../types";
|
||||||
|
/* import { NotificationActions } from "../../../action/NotificationActions"; */
|
||||||
|
import { Icon, Image, List } from "@raycast/api";
|
||||||
|
import { getAvatarIcon } from "@raycast/utils";
|
||||||
|
import { match, P } from "ts-pattern";
|
||||||
|
|
||||||
|
export function SlackNotificationListItem({ notification, mutate }: NotificationListItemProps) {
|
||||||
|
const subtitle = getSlackNotificationSubtitle(notification.details);
|
||||||
|
|
||||||
|
const author = getSlackAuthorAccessory(notification.details);
|
||||||
|
const team = getSlackTeamAccessory(notification.details);
|
||||||
|
const updated_at = "2023-01-01"; // TODO
|
||||||
|
|
||||||
|
const accessories: List.Item.Accessory[] = [{ date: new Date(updated_at), tooltip: `Updated at ${updated_at}` }];
|
||||||
|
|
||||||
|
if (author) {
|
||||||
|
accessories.unshift(author);
|
||||||
|
}
|
||||||
|
if (team) {
|
||||||
|
accessories.unshift(team);
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<List.Item
|
||||||
|
key={notification.id}
|
||||||
|
title={notification.title}
|
||||||
|
icon={{ source: { light: "github-logo-dark.svg", dark: "github-logo-light.svg" } }}
|
||||||
|
subtitle={subtitle}
|
||||||
|
accessories={accessories}
|
||||||
|
actions={
|
||||||
|
<NotificationActions
|
||||||
|
notification={notification}
|
||||||
|
detailsTarget={<SlackStarPreview notification={notification} />}
|
||||||
|
mutate={mutate}
|
||||||
|
/>
|
||||||
|
}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
function getSlackNotificationSubtitle(notificationDetails?: NotificationDetails): string {
|
||||||
|
return match(notificationDetails)
|
||||||
|
.with(
|
||||||
|
{
|
||||||
|
type: P.union("SlackMessage", "SlackFile", "SlackFileComment", "SlackChannel", "SlackIm", "SlackGroup"),
|
||||||
|
content: P.select(),
|
||||||
|
},
|
||||||
|
(slackNotificationDetails) => {
|
||||||
|
const channelName = slackNotificationDetails.channel?.name;
|
||||||
|
return channelName ? `#${channelName}` : "";
|
||||||
|
},
|
||||||
|
)
|
||||||
|
.otherwise(() => "");
|
||||||
|
}
|
||||||
|
|
||||||
|
function getSlackAuthorAccessory(notificationDetails?: NotificationDetails): List.Item.Accessory | null {
|
||||||
|
return match(notificationDetails)
|
||||||
|
.with(
|
||||||
|
{
|
||||||
|
type: "SlackMessage",
|
||||||
|
content: P.select(),
|
||||||
|
},
|
||||||
|
(slackNotificationDetails) => {
|
||||||
|
return match(slackNotificationDetails.sender)
|
||||||
|
.with({ type: "User", content: P.select() }, (slackUser: SlackUser) => {
|
||||||
|
const userAvatarUrl = getSlackUserAvatarUrl(slackUser);
|
||||||
|
const userName = slackUser.real_name || "Unknown";
|
||||||
|
return {
|
||||||
|
icon: userAvatarUrl ? { source: userAvatarUrl, mask: Image.Mask.Circle } : getAvatarIcon(userName),
|
||||||
|
tooltip: userName,
|
||||||
|
};
|
||||||
|
})
|
||||||
|
.with({ type: "Bot", content: P.select() }, (slackBot: SlackBotInfo) => {
|
||||||
|
const botAvatarUrl = getSlackIconUrl(slackBot.icons);
|
||||||
|
return {
|
||||||
|
icon: botAvatarUrl ? { source: botAvatarUrl, mask: Image.Mask.Circle } : getAvatarIcon(slackBot.name),
|
||||||
|
tooltip: slackBot.name,
|
||||||
|
};
|
||||||
|
})
|
||||||
|
.otherwise(() => ({ icon: Icon.Person, tooltip: "Unknown" }));
|
||||||
|
},
|
||||||
|
)
|
||||||
|
.otherwise(() => null);
|
||||||
|
}
|
||||||
|
|
||||||
|
function getSlackTeamAccessory(notificationDetails?: NotificationDetails): List.Item.Accessory | null {
|
||||||
|
return match(notificationDetails)
|
||||||
|
.with(
|
||||||
|
{
|
||||||
|
type: P.union("SlackMessage", "SlackFile", "SlackFileComment", "SlackChannel", "SlackIm", "SlackGroup"),
|
||||||
|
content: P.select(),
|
||||||
|
},
|
||||||
|
(slackNotificationDetails) => {
|
||||||
|
const teamName = slackNotificationDetails.team.name;
|
||||||
|
const teamIconUrl = getSlackIconUrl(slackNotificationDetails.team.icon);
|
||||||
|
if (!teamName || !teamIconUrl) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
return { icon: { source: teamIconUrl, mask: Image.Mask.Circle }, tooltip: teamName };
|
||||||
|
},
|
||||||
|
)
|
||||||
|
.otherwise(() => null);
|
||||||
|
}
|
||||||
|
|
||||||
|
function getSlackUserAvatarUrl(slackUser: SlackUser): string | null {
|
||||||
|
if (!slackUser.profile) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
if (slackUser.profile.image_24) {
|
||||||
|
return slackUser.profile.image_24;
|
||||||
|
}
|
||||||
|
if (slackUser.profile.image_32) {
|
||||||
|
return slackUser.profile.image_32;
|
||||||
|
}
|
||||||
|
if (slackUser.profile.image_34) {
|
||||||
|
return slackUser.profile.image_34;
|
||||||
|
}
|
||||||
|
if (slackUser.profile.image_44) {
|
||||||
|
return slackUser.profile.image_44;
|
||||||
|
}
|
||||||
|
if (slackUser.profile.image_48) {
|
||||||
|
return slackUser.profile.image_48;
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
function getSlackIconUrl(slackIcon?: SlackIcon): string | null {
|
||||||
|
if (slackIcon?.image_24) {
|
||||||
|
return slackIcon.image_24;
|
||||||
|
}
|
||||||
|
if (slackIcon?.image_32) {
|
||||||
|
return slackIcon.image_32;
|
||||||
|
}
|
||||||
|
if (slackIcon?.image_34) {
|
||||||
|
return slackIcon.image_34;
|
||||||
|
}
|
||||||
|
if (slackIcon?.image_44) {
|
||||||
|
return slackIcon.image_44;
|
||||||
|
}
|
||||||
|
if (slackIcon?.image_48) {
|
||||||
|
return slackIcon.image_48;
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
24
src/integrations/slack/preview/SlackStarPreview.tsx
Normal file
24
src/integrations/slack/preview/SlackStarPreview.tsx
Normal file
@@ -0,0 +1,24 @@
|
|||||||
|
import { Notification, getNotificationHtmlUrl } from "../../../notification";
|
||||||
|
import { Detail, ActionPanel, Action } from "@raycast/api";
|
||||||
|
import { useMemo } from "react";
|
||||||
|
|
||||||
|
interface SlackStarPreviewProps {
|
||||||
|
notification: Notification;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function SlackStarPreview({ notification }: SlackStarPreviewProps) {
|
||||||
|
const notificationHtmlUrl = useMemo(() => {
|
||||||
|
return getNotificationHtmlUrl(notification);
|
||||||
|
}, [notification]);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Detail
|
||||||
|
markdown={`# ${notification.title}`}
|
||||||
|
actions={
|
||||||
|
<ActionPanel>
|
||||||
|
<Action.OpenInBrowser url={notificationHtmlUrl} />
|
||||||
|
</ActionPanel>
|
||||||
|
}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
}
|
||||||
400
src/integrations/slack/types.ts
Normal file
400
src/integrations/slack/types.ts
Normal file
@@ -0,0 +1,400 @@
|
|||||||
|
export interface SlackPushEventCallback {
|
||||||
|
team_id: string;
|
||||||
|
api_app_id: string;
|
||||||
|
event: SlackEventCallbackBody;
|
||||||
|
event_id: string;
|
||||||
|
event_time: Date;
|
||||||
|
event_context?: string;
|
||||||
|
authed_users?: Array<string>;
|
||||||
|
authorizations?: Array<SlackEventAuthorization>;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface SlackEventAuthorization {
|
||||||
|
team_id: string;
|
||||||
|
user_id: string;
|
||||||
|
is_bot: boolean;
|
||||||
|
}
|
||||||
|
|
||||||
|
export type SlackEventCallbackBody =
|
||||||
|
| { type: "SarAdded"; content: SlackStarAddedEvent }
|
||||||
|
| { type: "StarRemoved"; content: SlackStarRemovedEvent };
|
||||||
|
|
||||||
|
export interface SlackStarAddedEvent {
|
||||||
|
user: string;
|
||||||
|
item: SlackStarsItem;
|
||||||
|
event_ts: Date;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface SlackStarRemovedEvent {
|
||||||
|
user: string;
|
||||||
|
item: SlackStarsItem;
|
||||||
|
event_ts: Date;
|
||||||
|
}
|
||||||
|
|
||||||
|
export type SlackStarsItem =
|
||||||
|
| { type: "Message"; content: SlackStarsItemMessage }
|
||||||
|
| { type: "File"; content: SlackStarsItemFile }
|
||||||
|
| { type: "FileComment"; content: SlackStarsItemFileComment }
|
||||||
|
| { type: "Channel"; content: SlackStarsItemChannel }
|
||||||
|
| { type: "Im"; content: SlackStarsItemIm }
|
||||||
|
| { type: "Group"; content: SlackStarsItemGroup };
|
||||||
|
|
||||||
|
export interface SlackStarsItemMessage {
|
||||||
|
message: SlackHistoryMessage;
|
||||||
|
channel: string;
|
||||||
|
date_create: Date;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface SlackHistoryMessage {
|
||||||
|
ts: string;
|
||||||
|
channel?: string;
|
||||||
|
channel_type?: string;
|
||||||
|
thread_ts?: string;
|
||||||
|
client_msg_id?: string;
|
||||||
|
|
||||||
|
text?: string;
|
||||||
|
blocks?: Array<SlackBlock>;
|
||||||
|
attachments?: Array<SlackMessageAttachment>;
|
||||||
|
upload?: boolean;
|
||||||
|
files?: Array<SlackFile>;
|
||||||
|
reactions?: Array<SlackReaction>;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface SlackReaction {
|
||||||
|
name: string;
|
||||||
|
count: number;
|
||||||
|
users: Array<string>;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface SlackMessageAttachment {
|
||||||
|
id?: number;
|
||||||
|
color?: string;
|
||||||
|
fallback?: string;
|
||||||
|
title?: string;
|
||||||
|
fields?: Array<SlackMessageAttachmentFieldObject>;
|
||||||
|
mrkdwn_in?: Array<string>;
|
||||||
|
text?: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface SlackMessageAttachmentFieldObject {
|
||||||
|
title?: string;
|
||||||
|
value?: string;
|
||||||
|
short?: boolean;
|
||||||
|
}
|
||||||
|
|
||||||
|
export type SlackBlock =
|
||||||
|
| SlackSectionBlock
|
||||||
|
| SlackHeaderBlock
|
||||||
|
| SlackDividerBlock
|
||||||
|
| SlackImageBlock
|
||||||
|
| SlackActionsBlock
|
||||||
|
| SlackContextBlock
|
||||||
|
| SlackInputBlock
|
||||||
|
| SlackFileBlock
|
||||||
|
| { type: "rich_text" }
|
||||||
|
| { type: "event" };
|
||||||
|
|
||||||
|
export interface SlackSectionBlock {
|
||||||
|
type: "section";
|
||||||
|
block_id?: string;
|
||||||
|
text?: SlackBlockText;
|
||||||
|
fields?: Array<SlackBlockText>;
|
||||||
|
// To be specified
|
||||||
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||||
|
accessory?: any;
|
||||||
|
}
|
||||||
|
|
||||||
|
export type SlackBlockText =
|
||||||
|
| { type: "plain_text"; value: string }
|
||||||
|
| { type: "mrkdwn"; text: string; verbatim?: boolean };
|
||||||
|
|
||||||
|
export interface SlackHeaderBlock {
|
||||||
|
type: "header";
|
||||||
|
block_id?: string;
|
||||||
|
text: SlackBlockText;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface SlackDividerBlock {
|
||||||
|
type: "divider";
|
||||||
|
block_id?: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface SlackImageBlock {
|
||||||
|
type: "image";
|
||||||
|
block_id?: string;
|
||||||
|
image_url: string;
|
||||||
|
alt_text: string;
|
||||||
|
title?: SlackBlockText;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface SlackActionsBlock {
|
||||||
|
type: "actions";
|
||||||
|
block_id?: string;
|
||||||
|
// To be specified
|
||||||
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||||
|
elements: Array<any>;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface SlackContextBlock {
|
||||||
|
type: "context";
|
||||||
|
block_id?: string;
|
||||||
|
// To be specified
|
||||||
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||||
|
elements: Array<any>;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface SlackInputBlock {
|
||||||
|
type: "input";
|
||||||
|
block_id?: string;
|
||||||
|
label: SlackBlockText;
|
||||||
|
// To be specified
|
||||||
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||||
|
element: any;
|
||||||
|
hint?: SlackBlockText;
|
||||||
|
optional?: boolean;
|
||||||
|
dispatch_action?: boolean;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface SlackFileBlock {
|
||||||
|
type: "file";
|
||||||
|
block_id?: string;
|
||||||
|
external_id: string;
|
||||||
|
source: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface SlackStarsItemFile {
|
||||||
|
file: SlackFile;
|
||||||
|
channel: string;
|
||||||
|
date_create: Date;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface SlackFile {
|
||||||
|
id: string;
|
||||||
|
created?: Date;
|
||||||
|
timestamp?: Date;
|
||||||
|
name?: string;
|
||||||
|
title?: string;
|
||||||
|
mimetype?: string;
|
||||||
|
filetype?: string;
|
||||||
|
pretty_type?: string;
|
||||||
|
external_type?: string;
|
||||||
|
user?: string;
|
||||||
|
username?: string;
|
||||||
|
url_private?: string;
|
||||||
|
url_private_download?: string;
|
||||||
|
permalink?: string;
|
||||||
|
permalink_public?: string;
|
||||||
|
reactions?: Array<SlackReaction>;
|
||||||
|
editable?: boolean;
|
||||||
|
is_external?: boolean;
|
||||||
|
is_public?: boolean;
|
||||||
|
public_url_shared?: boolean;
|
||||||
|
display_as_bot?: boolean;
|
||||||
|
is_starred?: boolean;
|
||||||
|
has_rich_preview?: boolean;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface SlackStarsItemFileComment {
|
||||||
|
file: SlackFile;
|
||||||
|
file_comment: string;
|
||||||
|
channel: string;
|
||||||
|
date_create: Date;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface SlackStarsItemChannel {
|
||||||
|
channel: string;
|
||||||
|
date_create: Date;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface SlackStarsItemIm {
|
||||||
|
channel: string;
|
||||||
|
date_create: Date;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface SlackStarsItemGroup {
|
||||||
|
group: string;
|
||||||
|
date_create: Date;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface SlackMessageDetails {
|
||||||
|
url: string;
|
||||||
|
message: SlackHistoryMessage;
|
||||||
|
channel: SlackChannelInfo;
|
||||||
|
sender: SlackMessageSenderDetails;
|
||||||
|
team: SlackTeamInfo;
|
||||||
|
}
|
||||||
|
|
||||||
|
export type SlackMessageSenderDetails = { type: "User"; content: SlackUser } | { type: "Bot"; content: SlackBotInfo };
|
||||||
|
|
||||||
|
export interface SlackUser {
|
||||||
|
id: string;
|
||||||
|
team_id?: string;
|
||||||
|
name?: string;
|
||||||
|
locale?: string;
|
||||||
|
profile?: SlackUserProfile;
|
||||||
|
is_admin?: boolean;
|
||||||
|
is_app_user?: boolean;
|
||||||
|
is_bot?: boolean;
|
||||||
|
is_invited_user?: boolean;
|
||||||
|
is_owner?: boolean;
|
||||||
|
is_primary_owner?: boolean;
|
||||||
|
is_restricted?: boolean;
|
||||||
|
is_stranger?: boolean;
|
||||||
|
is_ultra_restricted?: boolean;
|
||||||
|
has_2fa?: boolean;
|
||||||
|
tz?: string;
|
||||||
|
tz_label?: string;
|
||||||
|
tz_offset?: number;
|
||||||
|
updated?: Date;
|
||||||
|
deleted?: boolean;
|
||||||
|
color?: string;
|
||||||
|
real_name?: string;
|
||||||
|
enterprise_user?: SlackEnterpriseUser;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface SlackUserProfile {
|
||||||
|
id?: string;
|
||||||
|
display_name?: string;
|
||||||
|
real_name?: string;
|
||||||
|
real_name_normalized?: string;
|
||||||
|
avatar_hash?: string;
|
||||||
|
status_text?: string;
|
||||||
|
status_expiration?: Date;
|
||||||
|
status_emoji?: string;
|
||||||
|
display_name_normalized?: string;
|
||||||
|
email?: string;
|
||||||
|
team?: string;
|
||||||
|
image_original?: string;
|
||||||
|
image_default?: boolean;
|
||||||
|
image_24?: string;
|
||||||
|
image_32?: string;
|
||||||
|
image_34?: string;
|
||||||
|
image_44?: string;
|
||||||
|
image_48?: string;
|
||||||
|
image_68?: string;
|
||||||
|
image_72?: string;
|
||||||
|
image_88?: string;
|
||||||
|
image_102?: string;
|
||||||
|
image_132?: string;
|
||||||
|
image_192?: string;
|
||||||
|
image_230?: string;
|
||||||
|
image_512?: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface SlackEnterpriseUser {
|
||||||
|
id: string;
|
||||||
|
enterprise_id: string;
|
||||||
|
enterprise_name?: string;
|
||||||
|
teams?: Array<string>;
|
||||||
|
is_admin?: boolean;
|
||||||
|
is_app_user?: boolean;
|
||||||
|
is_bot?: boolean;
|
||||||
|
is_invited_user?: boolean;
|
||||||
|
is_owner?: boolean;
|
||||||
|
is_primary_owner?: boolean;
|
||||||
|
is_restricted?: boolean;
|
||||||
|
is_stranger?: boolean;
|
||||||
|
is_ultra_restricted?: boolean;
|
||||||
|
has_2fa?: boolean;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface SlackBotInfo {
|
||||||
|
id?: string;
|
||||||
|
name: string;
|
||||||
|
updated?: Date;
|
||||||
|
app_id: string;
|
||||||
|
user_id: string;
|
||||||
|
icons?: SlackIcon;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface SlackTeamInfo {
|
||||||
|
id: string;
|
||||||
|
name?: string;
|
||||||
|
domain?: string;
|
||||||
|
email_domain?: string;
|
||||||
|
icon?: SlackIcon;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface SlackIcon {
|
||||||
|
image_original?: string;
|
||||||
|
image_default?: boolean;
|
||||||
|
image_24?: string;
|
||||||
|
image_32?: string;
|
||||||
|
image_34?: string;
|
||||||
|
image_44?: string;
|
||||||
|
image_48?: string;
|
||||||
|
image_68?: string;
|
||||||
|
image_72?: string;
|
||||||
|
image_88?: string;
|
||||||
|
image_102?: string;
|
||||||
|
image_132?: string;
|
||||||
|
image_192?: string;
|
||||||
|
image_230?: string;
|
||||||
|
image_512?: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface SlackChannelInfo {
|
||||||
|
id: string;
|
||||||
|
created: Date;
|
||||||
|
creator?: string;
|
||||||
|
name?: string;
|
||||||
|
name_normalized?: string;
|
||||||
|
topic?: SlackChannelTopicInfo;
|
||||||
|
purpose?: SlackChannelPurposeInfo;
|
||||||
|
previous_names?: Array<string>;
|
||||||
|
priority?: number;
|
||||||
|
num_members?: number;
|
||||||
|
locale?: string;
|
||||||
|
is_channel?: boolean;
|
||||||
|
is_group?: boolean;
|
||||||
|
is_im?: boolean;
|
||||||
|
is_archived?: boolean;
|
||||||
|
is_general?: boolean;
|
||||||
|
is_shared?: boolean;
|
||||||
|
is_org_shared?: boolean;
|
||||||
|
is_member?: boolean;
|
||||||
|
is_private?: boolean;
|
||||||
|
is_mpim?: boolean;
|
||||||
|
is_user_deleted?: boolean;
|
||||||
|
last_read?: string;
|
||||||
|
unread_count?: number;
|
||||||
|
unread_count_display?: number;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface SlackChannelTopicInfo {
|
||||||
|
value: string;
|
||||||
|
creator?: string;
|
||||||
|
last_set?: Date;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface SlackChannelPurposeInfo {
|
||||||
|
value: string;
|
||||||
|
creator?: string;
|
||||||
|
last_set?: Date;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface SlackChannelDetails {
|
||||||
|
channel: SlackChannelInfo;
|
||||||
|
team: SlackTeamInfo;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface SlackFileDetails {
|
||||||
|
channel: SlackChannelInfo;
|
||||||
|
sender?: SlackUser;
|
||||||
|
team: SlackTeamInfo;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface SlackFileCommentDetails {
|
||||||
|
channel: SlackChannelInfo;
|
||||||
|
team: SlackTeamInfo;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface SlackImDetails {
|
||||||
|
channel: SlackChannelInfo;
|
||||||
|
team: SlackTeamInfo;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface SlackGroupDetails {
|
||||||
|
channel: SlackChannelInfo;
|
||||||
|
team: SlackTeamInfo;
|
||||||
|
}
|
||||||
@@ -1,3 +1,12 @@
|
|||||||
|
import {
|
||||||
|
SlackChannelDetails,
|
||||||
|
SlackFileCommentDetails,
|
||||||
|
SlackFileDetails,
|
||||||
|
SlackGroupDetails,
|
||||||
|
SlackImDetails,
|
||||||
|
SlackMessageDetails,
|
||||||
|
SlackPushEventCallback,
|
||||||
|
} from "./integrations/slack/types";
|
||||||
import { GithubDiscussion, GithubPullRequest } from "./integrations/github/types";
|
import { GithubDiscussion, GithubPullRequest } from "./integrations/github/types";
|
||||||
import { GoogleMailThread } from "./integrations/google-mail/types";
|
import { GoogleMailThread } from "./integrations/google-mail/types";
|
||||||
import { LinearNotification } from "./integrations/linear/types";
|
import { LinearNotification } from "./integrations/linear/types";
|
||||||
@@ -27,11 +36,18 @@ export type NotificationMetadata =
|
|||||||
content: any;
|
content: any;
|
||||||
}
|
}
|
||||||
| { type: "Linear"; content: LinearNotification }
|
| { type: "Linear"; content: LinearNotification }
|
||||||
| { type: "GoogleMail"; content: GoogleMailThread };
|
| { type: "GoogleMail"; content: GoogleMailThread }
|
||||||
|
| { type: "Slack"; content: SlackPushEventCallback };
|
||||||
|
|
||||||
export type NotificationDetails =
|
export type NotificationDetails =
|
||||||
| { type: "GithubPullRequest"; content: GithubPullRequest }
|
| { type: "GithubPullRequest"; content: GithubPullRequest }
|
||||||
| { type: "GithubDiscussion"; content: GithubDiscussion };
|
| { type: "GithubDiscussion"; content: GithubDiscussion }
|
||||||
|
| { type: "SlackMessage"; content: SlackMessageDetails }
|
||||||
|
| { type: "SlackFile"; content: SlackFileDetails }
|
||||||
|
| { type: "SlackFileComment"; content: SlackFileCommentDetails }
|
||||||
|
| { type: "SlackChannel"; content: SlackChannelDetails }
|
||||||
|
| { type: "SlackIm"; content: SlackImDetails }
|
||||||
|
| { type: "SlackGroup"; content: SlackGroupDetails };
|
||||||
|
|
||||||
export enum NotificationStatus {
|
export enum NotificationStatus {
|
||||||
Unread = "Unread",
|
Unread = "Unread",
|
||||||
@@ -47,6 +63,17 @@ export type NotificationListItemProps = {
|
|||||||
|
|
||||||
export function getNotificationHtmlUrl(notification: Notification) {
|
export function getNotificationHtmlUrl(notification: Notification) {
|
||||||
return match(notification)
|
return match(notification)
|
||||||
|
.with({ details: { type: "SlackMessage", content: P.select() } }, (notificationDetails) => notificationDetails.url)
|
||||||
|
.with(
|
||||||
|
{
|
||||||
|
details: {
|
||||||
|
type: P.union("SlackChannel", "SlackFile", "SlackFileComment", "SlackGroup", "SlackIm"),
|
||||||
|
content: P.select(),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
(notificationDetails) =>
|
||||||
|
`https://app.slack.com/client/${notificationDetails.team.id}/${notificationDetails.channel.id}`,
|
||||||
|
)
|
||||||
.with(
|
.with(
|
||||||
{ details: { type: P.union("GithubPullRequest", "GithubDiscussion"), content: P.select() } },
|
{ details: { type: P.union("GithubPullRequest", "GithubDiscussion"), content: P.select() } },
|
||||||
(notificationDetails) => notificationDetails.url,
|
(notificationDetails) => notificationDetails.url,
|
||||||
@@ -66,6 +93,7 @@ export function getNotificationHtmlUrl(notification: Notification) {
|
|||||||
)
|
)
|
||||||
.with({ metadata: { type: "Todoist" } }, () => `https://todoist.com/showTask?id=${notification.source_id}`)
|
.with({ metadata: { type: "Todoist" } }, () => `https://todoist.com/showTask?id=${notification.source_id}`)
|
||||||
.with({ metadata: { type: "Github" } }, () => "https://github.com")
|
.with({ metadata: { type: "Github" } }, () => "https://github.com")
|
||||||
|
.with({ metadata: { type: "Slack" } }, () => "https://app.slack.com")
|
||||||
.exhaustive();
|
.exhaustive();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user