Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Update: Slack: Adding more info to Slack Open Channel command #13343

Open
wants to merge 18 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 17 commits
Commits
Show all changes
18 commits
Select commit Hold shift + click to select a range
d34ba4a
Update: Slack: Adding more info to Slack Search
RobErskine Jul 5, 2024
c02cb5b
Add: Slack: Adds Emojify to Unread Messages command
RobErskine Jul 5, 2024
6188715
Add: Slack: Adds Emojify to Unread Messages command
RobErskine Jul 5, 2024
a469cbc
Merge branch 'feature/slack-search-update' of github.com:RobErskine/r…
RobErskine Jul 5, 2024
b76c636
Add: Slack: Update emojify helper function to unread message detail
RobErskine Jul 5, 2024
86dbe6a
Add: Slack: Adding optional preferences to allow flexibility in searc…
RobErskine Jul 7, 2024
155f797
Slack: Linting fix
RobErskine Jul 7, 2024
7c83f90
Update extensions/slack/src/search.tsx
RobErskine Jul 8, 2024
2f6cdae
Slack: Addressing minor feedback
RobErskine Jul 8, 2024
90fc50f
Slack search: type casting preferences from raycast-env.d.ts
RobErskine Jul 8, 2024
bdcc780
Update: Slack: Adding more info to Slack Search
RobErskine Jul 5, 2024
71576c4
Add: Slack: Adds Emojify to Unread Messages command
RobErskine Jul 5, 2024
a0aa7d4
Add: Slack: Adding optional preferences to allow flexibility in searc…
RobErskine Jul 7, 2024
578efea
Slack: Addressing minor feedback
RobErskine Jul 8, 2024
c6d8ca4
Slack search: type casting preferences from raycast-env.d.ts
RobErskine Jul 8, 2024
9bf1c4b
Merge branch 'feature/slack-search-update' of github.com:RobErskine/r…
RobErskine Jul 8, 2024
1138934
Merge branch 'raycast:main' into feature/slack-search-update
RobErskine Jul 15, 2024
fee8e4b
slack open channel: destructuring time format
RobErskine Jul 16, 2024
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
5 changes: 5 additions & 0 deletions extensions/slack/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,10 @@
# Slack Changelog

## [Adds optional metadata to Open Channel Command ] - {PR_MERGE_DATE}
- Adds job title, timezone, current time, and slack status to the List that gets returned as part of the Open Channel command.
- Adds preferences to show this metadata, as well as time format preferences throughout the extension.
- Adds Emojify to unread messages command to convert :fireworks: to 🎆, for example.

## [Search Messages command] - 2024-07-08

- Add a new command to search through your Slack's workspace messages.
Expand Down
10 changes: 10 additions & 0 deletions extensions/slack/package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

36 changes: 34 additions & 2 deletions extensions/slack/package.json
RobErskine marked this conversation as resolved.
Show resolved Hide resolved
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,8 @@
"contributors": [
"Elliot67",
"stelo",
"thomaslombart"
"thomaslombart",
"Rob"
],
"categories": [
"Communication",
Expand All @@ -24,7 +25,18 @@
"search"
],
"description": "Search for all workspace members, group chats, and channels and open them directly in your Slack app.",
"mode": "view"
"mode": "view",
"preferences": [
{
"title": "Channel Metadata",
"label": "Display extra metadata in Open Channel results",
"description": "Show team member's titles, time zone, and current time in Open Channel results",
"name": "displayExtraMetadata",
"type": "checkbox",
"required": false,
"default": false
}
]
},
{
"name": "search-messages",
Expand Down Expand Up @@ -79,6 +91,25 @@
"type": "checkbox",
"required": false,
"default": true
},
{
"title": "Time Format",
"label": "Time Format",
"description": "Determines how time is formatted in the extension",
"name": "timeFormat",
"type": "dropdown",
"required": false,
"data": [
{
"value": "hour12",
"title": "12-hour format (AM/PM)"
},
{
"value": "hour24",
"title": "24-hour format"
}
],
"default": "hour12"
}
],
"dependencies": {
Expand All @@ -93,6 +124,7 @@
"@raycast/eslint-config": "^1.0.8",
"@types/lodash": "^4.17.5",
"@types/node": "^20.8.10",
"@types/node-emoji": "^2.1.0",
"@types/react": "^18.2.27",
"eslint": "^8.57.0",
"prettier": "^3.3.2",
Expand Down
54 changes: 51 additions & 3 deletions extensions/slack/src/search.tsx
Original file line number Diff line number Diff line change
@@ -1,11 +1,46 @@
// This filename should be named `switch-to-channel.tsx` or something similar
// but it's kept as `search.tsx` as changing the command's name will cause users to lose their keywords and aliases
import { ActionPanel, Action, Icon, List } from "@raycast/api";

import { ActionPanel, Action, Icon, List, getPreferenceValues } from "@raycast/api";
import { User, useChannels } from "./shared/client";
import { withSlackClient } from "./shared/withSlackClient";
import { useFrecencySorting } from "@raycast/utils";
import { OpenChannelInSlack, OpenChatInSlack, useSlackApp } from "./shared/OpenInSlack";
import { convertSlackEmojiToUnicode, getTimeLocale } from "./shared/utils";

const { displayExtraMetadata } = getPreferenceValues<Preferences.Search>();

function getCoworkerTime(coworkerTimeZone: string): string {
const time = new Date();
return new Intl.DateTimeFormat(getTimeLocale(), {
timeZone: coworkerTimeZone,
hour: "2-digit",
minute: "2-digit",
}).format(time);
}

function searchItemAccessories(
statusEmoji: string | undefined,
statusText: string | undefined,
statusExpiration: string | null,
timezone: string,
) {
const searchMetadata: Array<{ icon: string | Icon; text: string; tooltip?: string | null | undefined }> = [
{
icon: convertSlackEmojiToUnicode(statusEmoji ?? ""),
text: statusText ?? "",
tooltip: statusExpiration ? String(statusExpiration) : undefined,
},
];

if (displayExtraMetadata) {
searchMetadata.push(
{ icon: Icon.Globe, text: timezone.split("/")[1].replace(/_/g, " ") },
{ icon: Icon.Clock, text: getCoworkerTime(timezone) },
);
}

return searchMetadata;
}

function Search() {
const { isAppInstalled, isLoading } = useSlackApp();
Expand All @@ -21,12 +56,25 @@ function Search() {
const isUser = item.id.startsWith("U");

if (isUser) {
const { id: userId, name, icon, teamId: workspaceId, conversationId } = item as User;
const {
id: userId,
name,
icon,
title,
statusEmoji,
statusText,
statusExpiration,
teamId: workspaceId,
conversationId,
timezone,
} = item as User;
return (
<List.Item
key={userId}
title={name}
subtitle={displayExtraMetadata ? title : undefined}
icon={icon}
accessories={searchItemAccessories(statusEmoji, statusText, statusExpiration, timezone)}
actions={
<ActionPanel>
<OpenChatInSlack
Expand Down
34 changes: 33 additions & 1 deletion extensions/slack/src/shared/client/SlackClient.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import { Icon, Image } from "@raycast/api";
import { SlackConversation, SlackMember, getSlackWebClient } from "./WebClient";
import { getTimeLocale } from "../utils";

interface Item {
id: string;
Expand All @@ -11,6 +12,11 @@ interface Item {
export interface User extends Item {
username: string;
conversationId: string | undefined;
title: string;
statusEmoji: string | undefined;
statusText: string | undefined;
statusExpiration: string;
timezone: string;
}

export type Channel = Item;
Expand Down Expand Up @@ -56,10 +62,31 @@ export class SlackClient {
.filter(
({ is_bot, is_workflow_bot, deleted, id }) => !is_bot && !is_workflow_bot && !deleted && id !== "USLACKBOT",
)
.map(({ id, name: username, profile, team_id }) => {
.map(({ id, name: username, profile, team_id, tz }) => {
const firstName = profile?.first_name ?? "";
const lastName = profile?.last_name ?? "";
const name = `${firstName} ${lastName}`;
const jobTitle = profile?.title ?? "";
const statusEmoji = profile?.status_emoji ?? undefined;
const statusText = profile?.status_text?.replace(/&amp;/g, "&") ?? undefined;
const statusExpiration = profile?.status_expiration ?? undefined;
const timezone = tz ?? "";

let statusExpirationDate = "";
let statusExpirationTime = "";

if (statusExpiration) {
const date = new Date(statusExpiration * 1000);
if (!isNaN(date.getTime())) {
statusExpirationDate = date.toISOString().split("T")[0];
statusExpirationTime = date.toLocaleTimeString(getTimeLocale(), {
hour: "2-digit",
minute: "2-digit",
});

statusExpirationDate = `Back on ${statusExpirationDate} at ${statusExpirationTime}`;
}
}

const displayName = [name, profile?.display_name, profile?.real_name].find((x): x is string => !!x?.trim());

Expand All @@ -71,7 +98,12 @@ export class SlackClient {
icon: profile?.image_24 ? { source: profile?.image_24, mask: Image.Mask.Circle } : Icon.Person,
teamId: team_id,
username,
title: jobTitle,
statusEmoji,
statusText,
statusExpiration: statusExpirationDate,
conversationId: conversation?.id,
timezone,
} as User;
})
.filter((i) => !!(i.id?.trim() && i.name?.trim() && i.teamId?.trim()))
Expand Down
7 changes: 6 additions & 1 deletion extensions/slack/src/shared/client/WebClient.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,8 +22,13 @@ export interface SlackMember {
first_name?: string;
last_name?: string;
image_24?: string;
title?: string;
phone?: string;
status_text?: string;
status_emoji?: string;
status_expiration?: number;
};

tz?: string;
deleted?: boolean;
is_bot?: boolean;
is_workflow_bot?: boolean;
Expand Down
21 changes: 19 additions & 2 deletions extensions/slack/src/shared/utils.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,18 @@
import { open } from "@raycast/api";
import { open, getPreferenceValues } from "@raycast/api";
import { showFailureToast } from "@raycast/utils";
import { CodedError, ErrorCode } from "@slack/web-api";
import { formatDistance } from "date-fns";
import { slack } from "./client/WebClient";
import * as emoji from "node-emoji";

function getTimeLocale(): string {
const timeFormat = getPreferenceValues<Preferences>().timeFormat;
return timeFormat === "hour24" ? "en-GB" : "en-US";
RobErskine marked this conversation as resolved.
Show resolved Hide resolved
}

function convertSlackEmojiToUnicode(text: string): string {
return emoji.emojify(text);
}

const timeDifference = (date: Date): string => {
const now = new Date();
Expand Down Expand Up @@ -87,4 +97,11 @@ const handleError = async (error: CodedError | Error | unknown, title?: string)
return showFailureToast(error, { title: title ?? "Something unexpected happened" });
};

export { timeDifference, convertTimestampToDate, buildScriptEnsuringSlackIsRunning, handleError };
export {
timeDifference,
convertTimestampToDate,
buildScriptEnsuringSlackIsRunning,
handleError,
convertSlackEmojiToUnicode,
getTimeLocale,
};
6 changes: 3 additions & 3 deletions extensions/slack/src/unread-messages.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { Action, ActionPanel, Color, Icon, List, LocalStorage, showToast, Toast } from "@raycast/api";
import { isEqual } from "lodash";
import { useEffect, useState } from "react";
import * as emoji from "node-emoji";
import { convertSlackEmojiToUnicode } from "./shared/utils";

import { Message, SlackClient, useChannels, User, useUnreadConversations } from "./shared/client";
import { withSlackClient } from "./shared/withSlackClient";
Expand Down Expand Up @@ -124,7 +124,7 @@ function UnreadMessages() {
<List.Item
key={unreadConversation.conversationId}
title={conversation?.name ?? ""}
subtitle={unreadConversation.messageHistory[0].message}
subtitle={convertSlackEmojiToUnicode(unreadConversation.messageHistory[0].message)}
icon={conversation?.icon}
accessories={[
{ text: timeDifference(new Date(unreadConversation.messageHistory[0].receivedAt)) },
Expand Down Expand Up @@ -196,7 +196,7 @@ function UnreadMessagesConversation({
icon={user?.icon}
title={user?.name ?? ""}
subtitle={timeDifference(new Date(message.receivedAt))}
detail={<List.Item.Detail markdown={emoji.emojify(message.message)} />}
detail={<List.Item.Detail markdown={convertSlackEmojiToUnicode(message.message)} />}
/>
);
})}
Expand Down
4 changes: 2 additions & 2 deletions extensions/slack/tsconfig.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"$schema": "https://json.schemastore.org/tsconfig",
"display": "Node 16",
"include": ["src/**/*"],
"include": ["src/**/*", "raycast-env.d.ts"],
"compilerOptions": {
"lib": ["es2021"],
"module": "commonjs",
Expand All @@ -14,4 +14,4 @@
"jsx": "react-jsx",
"resolveJsonModule": true
}
}
}
Loading