Compare commits
1 Commits
957c3782dc
...
63d265bac9
| Author | SHA1 | Date | |
|---|---|---|---|
|
63d265bac9
|
18
CHANGELOG.md
18
CHANGELOG.md
@@ -2,23 +2,7 @@
|
|||||||
|
|
||||||
## [Unreleased]
|
## [Unreleased]
|
||||||
|
|
||||||
## [0.1.2] - 2024-02-01
|
## [Initial Version] - 2024-01-29
|
||||||
|
|
||||||
### Added
|
|
||||||
|
|
||||||
- Add "Plan task" action for notification created from task
|
|
||||||
|
|
||||||
### Fixed
|
|
||||||
|
|
||||||
- Fix "Complete task" action
|
|
||||||
|
|
||||||
## [0.1.1] - 2024-02-01
|
|
||||||
|
|
||||||
### Added
|
|
||||||
|
|
||||||
- Add filter per notification kind
|
|
||||||
|
|
||||||
## [0.1.0] - 2024-01-29
|
|
||||||
|
|
||||||
### Added
|
### Added
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
# Universal Inbox
|
# Universal Inbox
|
||||||
|
|
||||||
Manage your notifications in a single [Universal Inbox](https://www.universal-inbox.com)
|
Manage your notifications in a single Universal Inbox
|
||||||
|
|
||||||
## Setup
|
## Setup
|
||||||
|
|
||||||
@@ -15,4 +15,3 @@ Get the URL from the Universal Inbox instance you are usually connecting to.
|
|||||||
|
|
||||||
You can get an API Key from your Universal Inbox user profile page:
|
You can get an API Key from your Universal Inbox user profile page:
|
||||||
|
|
||||||

|
|
||||||
|
|||||||
Binary file not shown.
|
Before Width: | Height: | Size: 51 KiB After Width: | Height: | Size: 11 KiB |
Binary file not shown.
|
Before Width: | Height: | Size: 140 KiB |
2
package-lock.json
generated
2
package-lock.json
generated
@@ -1,12 +1,10 @@
|
|||||||
{
|
{
|
||||||
"name": "universal-inbox",
|
"name": "universal-inbox",
|
||||||
"version": "0.1.0",
|
|
||||||
"lockfileVersion": 3,
|
"lockfileVersion": 3,
|
||||||
"requires": true,
|
"requires": true,
|
||||||
"packages": {
|
"packages": {
|
||||||
"": {
|
"": {
|
||||||
"name": "universal-inbox",
|
"name": "universal-inbox",
|
||||||
"version": "0.1.0",
|
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@raycast/api": "^1.65.1",
|
"@raycast/api": "^1.65.1",
|
||||||
|
|||||||
@@ -4,8 +4,8 @@
|
|||||||
"title": "Universal Inbox",
|
"title": "Universal Inbox",
|
||||||
"description": "Manage your notifications in a single Universal Inbox",
|
"description": "Manage your notifications in a single Universal Inbox",
|
||||||
"icon": "ui-logo-transparent.png",
|
"icon": "ui-logo-transparent.png",
|
||||||
"author": "dax42",
|
"author": "dax",
|
||||||
"version": "0.1.1",
|
"owner": "universal-inbox",
|
||||||
"categories": [
|
"categories": [
|
||||||
"Productivity"
|
"Productivity"
|
||||||
],
|
],
|
||||||
|
|||||||
@@ -62,16 +62,12 @@ export function NotificationActions({ notification, detailsTarget, mutate }: Not
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function deleteNotification(
|
async function deleteNotification(notification: Notification, mutate: MutatePromise<Page<Notification> | undefined>) {
|
||||||
notification: Notification,
|
|
||||||
mutate: MutatePromise<Page<Notification> | undefined>,
|
|
||||||
) {
|
|
||||||
const preferences = getPreferenceValues<UniversalInboxPreferences>();
|
const preferences = getPreferenceValues<UniversalInboxPreferences>();
|
||||||
const toast = await showToast({ style: Toast.Style.Animated, title: "Deleting notification" });
|
const toast = await showToast({ style: Toast.Style.Animated, title: "Deleting notification" });
|
||||||
try {
|
try {
|
||||||
if (isNotificationBuiltFromTask(notification) && notification.task) {
|
if (isNotificationBuiltFromTask(notification) && notification.task) {
|
||||||
await mutate(
|
await mutate(
|
||||||
handleErrors(
|
|
||||||
fetch(`${preferences.universalInboxBaseUrl}/api/tasks/${notification.task.id}`, {
|
fetch(`${preferences.universalInboxBaseUrl}/api/tasks/${notification.task.id}`, {
|
||||||
method: "PATCH",
|
method: "PATCH",
|
||||||
body: JSON.stringify({ status: TaskStatus.Deleted }),
|
body: JSON.stringify({ status: TaskStatus.Deleted }),
|
||||||
@@ -88,7 +84,6 @@ export async function deleteNotification(
|
|||||||
return page;
|
return page;
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
),
|
|
||||||
);
|
);
|
||||||
} else {
|
} else {
|
||||||
await mutate(
|
await mutate(
|
||||||
@@ -123,7 +118,7 @@ export async function deleteNotification(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function unsubscribeFromNotification(
|
async function unsubscribeFromNotification(
|
||||||
notification: Notification,
|
notification: Notification,
|
||||||
mutate: MutatePromise<Page<Notification> | undefined>,
|
mutate: MutatePromise<Page<Notification> | undefined>,
|
||||||
) {
|
) {
|
||||||
@@ -161,10 +156,7 @@ export async function unsubscribeFromNotification(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function snoozeNotification(
|
async function snoozeNotification(notification: Notification, mutate: MutatePromise<Page<Notification> | undefined>) {
|
||||||
notification: Notification,
|
|
||||||
mutate: MutatePromise<Page<Notification> | undefined>,
|
|
||||||
) {
|
|
||||||
const preferences = getPreferenceValues<UniversalInboxPreferences>();
|
const preferences = getPreferenceValues<UniversalInboxPreferences>();
|
||||||
const toast = await showToast({ style: Toast.Style.Animated, title: "Snoozing notification" });
|
const toast = await showToast({ style: Toast.Style.Animated, title: "Snoozing notification" });
|
||||||
try {
|
try {
|
||||||
|
|||||||
@@ -1,13 +1,24 @@
|
|||||||
import { deleteNotification, snoozeNotification, unsubscribeFromNotification } from "./NotificationActions";
|
import { Notification, getNotificationHtmlUrl } from "../notification";
|
||||||
import { Notification, getNotificationHtmlUrl, isNotificationBuiltFromTask } from "../notification";
|
import { Action, ActionPanel, Icon } from "@raycast/api";
|
||||||
import { Action, ActionPanel, Icon, Toast, getPreferenceValues, showToast } from "@raycast/api";
|
|
||||||
import { MutatePromise } from "@raycast/utils";
|
import { MutatePromise } from "@raycast/utils";
|
||||||
import { useMemo, ReactElement } from "react";
|
import { useMemo, ReactElement } from "react";
|
||||||
import { PlanTask } from "./PlanTask";
|
|
||||||
import { handleErrors } from "../api";
|
|
||||||
import { TaskStatus } from "../task";
|
|
||||||
import { Page } from "../types";
|
import { Page } from "../types";
|
||||||
import fetch from "node-fetch";
|
|
||||||
|
function deleteNotification(notification: Notification) {
|
||||||
|
console.log(`Deleting notification ${notification.id}`);
|
||||||
|
}
|
||||||
|
|
||||||
|
function unsubscribeFromNotification(notification: Notification) {
|
||||||
|
console.log(`Unsubcribing from notification ${notification.id}`);
|
||||||
|
}
|
||||||
|
|
||||||
|
function snoozeNotification(notification: Notification) {
|
||||||
|
console.log(`Snoozing notification ${notification.id}`);
|
||||||
|
}
|
||||||
|
|
||||||
|
function completeTask(notification: Notification) {
|
||||||
|
console.log(`Completing task ${notification.id}`);
|
||||||
|
}
|
||||||
|
|
||||||
interface NotificationTaskActionsProps {
|
interface NotificationTaskActionsProps {
|
||||||
notification: Notification;
|
notification: Notification;
|
||||||
@@ -15,7 +26,7 @@ interface NotificationTaskActionsProps {
|
|||||||
mutate: MutatePromise<Page<Notification> | undefined>;
|
mutate: MutatePromise<Page<Notification> | undefined>;
|
||||||
}
|
}
|
||||||
|
|
||||||
export function NotificationTaskActions({ notification, detailsTarget, mutate }: NotificationTaskActionsProps) {
|
export function NotificationTaskActions({ notification, detailsTarget }: NotificationTaskActionsProps) {
|
||||||
const notificationHtmlUrl = useMemo(() => {
|
const notificationHtmlUrl = useMemo(() => {
|
||||||
return getNotificationHtmlUrl(notification);
|
return getNotificationHtmlUrl(notification);
|
||||||
}, [notification]);
|
}, [notification]);
|
||||||
@@ -28,71 +39,26 @@ export function NotificationTaskActions({ notification, detailsTarget, mutate }:
|
|||||||
title="Delete Notification"
|
title="Delete Notification"
|
||||||
icon={Icon.Trash}
|
icon={Icon.Trash}
|
||||||
shortcut={{ modifiers: ["ctrl"], key: "d" }}
|
shortcut={{ modifiers: ["ctrl"], key: "d" }}
|
||||||
onAction={() => deleteNotification(notification, mutate)}
|
onAction={() => deleteNotification(notification)}
|
||||||
/>
|
/>
|
||||||
<Action
|
<Action
|
||||||
title="Unsubscribe From Notification"
|
title="Unsubscribe From Notification"
|
||||||
icon={Icon.BellDisabled}
|
icon={Icon.BellDisabled}
|
||||||
shortcut={{ modifiers: ["ctrl"], key: "u" }}
|
shortcut={{ modifiers: ["ctrl"], key: "u" }}
|
||||||
onAction={() => unsubscribeFromNotification(notification, mutate)}
|
onAction={() => unsubscribeFromNotification(notification)}
|
||||||
/>
|
/>
|
||||||
<Action
|
<Action
|
||||||
title="Snooze"
|
title="Snooze"
|
||||||
icon={Icon.Clock}
|
icon={Icon.Clock}
|
||||||
shortcut={{ modifiers: ["ctrl"], key: "s" }}
|
shortcut={{ modifiers: ["ctrl"], key: "s" }}
|
||||||
onAction={() => snoozeNotification(notification, mutate)}
|
onAction={() => snoozeNotification(notification)}
|
||||||
/>
|
/>
|
||||||
<Action
|
<Action
|
||||||
title="Complete Task"
|
title="Complete Task"
|
||||||
icon={Icon.Calendar}
|
icon={Icon.Calendar}
|
||||||
shortcut={{ modifiers: ["ctrl"], key: "c" }}
|
shortcut={{ modifiers: ["ctrl"], key: "c" }}
|
||||||
onAction={() => completeTask(notification, mutate)}
|
onAction={() => completeTask(notification)}
|
||||||
/>
|
|
||||||
<Action.Push
|
|
||||||
title="Plan Task..."
|
|
||||||
icon={Icon.Calendar}
|
|
||||||
shortcut={{ modifiers: ["ctrl"], key: "t" }}
|
|
||||||
target={<PlanTask notification={notification} mutate={mutate} />}
|
|
||||||
/>
|
/>
|
||||||
</ActionPanel>
|
</ActionPanel>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
async function completeTask(notification: Notification, mutate: MutatePromise<Page<Notification> | undefined>) {
|
|
||||||
if (!isNotificationBuiltFromTask(notification) || !notification.task) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
const preferences = getPreferenceValues<UniversalInboxPreferences>();
|
|
||||||
const toast = await showToast({ style: Toast.Style.Animated, title: "Marking task as Done" });
|
|
||||||
try {
|
|
||||||
await mutate(
|
|
||||||
handleErrors(
|
|
||||||
fetch(`${preferences.universalInboxBaseUrl}/api/tasks/${notification.task.id}`, {
|
|
||||||
method: "PATCH",
|
|
||||||
body: JSON.stringify({ status: TaskStatus.Done }),
|
|
||||||
headers: {
|
|
||||||
"Content-Type": "application/json",
|
|
||||||
Authorization: `Bearer ${preferences.apiKey}`,
|
|
||||||
},
|
|
||||||
}),
|
|
||||||
),
|
|
||||||
{
|
|
||||||
optimisticUpdate(page) {
|
|
||||||
if (page) {
|
|
||||||
page.content = page.content.filter((n) => n.id !== notification.id);
|
|
||||||
}
|
|
||||||
return page;
|
|
||||||
},
|
|
||||||
},
|
|
||||||
);
|
|
||||||
|
|
||||||
toast.style = Toast.Style.Success;
|
|
||||||
toast.title = "Task successfully marked as Done";
|
|
||||||
} catch (error) {
|
|
||||||
toast.style = Toast.Style.Failure;
|
|
||||||
toast.title = "Failed to mark task as Done";
|
|
||||||
toast.message = (error as Error).message;
|
|
||||||
throw error;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -1,155 +0,0 @@
|
|||||||
import { Action, useNavigation, ActionPanel, Form, Icon, getPreferenceValues, showToast, Toast } from "@raycast/api";
|
|
||||||
import { MutatePromise, useForm, FormValidation, useFetch } from "@raycast/utils";
|
|
||||||
import { Notification, isNotificationBuiltFromTask } from "../notification";
|
|
||||||
import { Page, UniversalInboxPreferences } from "../types";
|
|
||||||
import { default as dayjs, extend } from "dayjs";
|
|
||||||
import { TaskPriority } from "../task";
|
|
||||||
import { handleErrors } from "../api";
|
|
||||||
import utc from "dayjs/plugin/utc";
|
|
||||||
import { useState } from "react";
|
|
||||||
import fetch from "node-fetch";
|
|
||||||
|
|
||||||
extend(utc);
|
|
||||||
|
|
||||||
interface PlanTaskProps {
|
|
||||||
notification: Notification;
|
|
||||||
mutate: MutatePromise<Page<Notification> | undefined>;
|
|
||||||
}
|
|
||||||
|
|
||||||
interface TaskPlanningFormValues {
|
|
||||||
project: string;
|
|
||||||
dueAt: Date | null;
|
|
||||||
priority: string;
|
|
||||||
}
|
|
||||||
|
|
||||||
interface ProjectSummary {
|
|
||||||
name: string;
|
|
||||||
source_id: string;
|
|
||||||
}
|
|
||||||
|
|
||||||
interface TaskPlanning {
|
|
||||||
project: ProjectSummary;
|
|
||||||
due_at?: { type: "DateTimeWithTz"; content: string };
|
|
||||||
priority: TaskPriority;
|
|
||||||
}
|
|
||||||
|
|
||||||
export function PlanTask({ notification, mutate }: PlanTaskProps) {
|
|
||||||
const preferences = getPreferenceValues<UniversalInboxPreferences>();
|
|
||||||
const { pop } = useNavigation();
|
|
||||||
const [searchText, setSearchText] = useState("");
|
|
||||||
|
|
||||||
const { isLoading, data: projects } = useFetch<Array<ProjectSummary>>(
|
|
||||||
`${preferences.universalInboxBaseUrl}/api/tasks/projects/search?matches=${searchText}`,
|
|
||||||
{
|
|
||||||
keepPreviousData: true,
|
|
||||||
headers: {
|
|
||||||
Authorization: `Bearer ${preferences.apiKey}`,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
);
|
|
||||||
|
|
||||||
const { handleSubmit, itemProps } = useForm<TaskPlanningFormValues>({
|
|
||||||
initialValues: {
|
|
||||||
dueAt: new Date(),
|
|
||||||
priority: `${TaskPriority.P4 as number}`,
|
|
||||||
},
|
|
||||||
async onSubmit(values) {
|
|
||||||
const project = projects?.find((p) => p.source_id === values.project);
|
|
||||||
if (!project) {
|
|
||||||
throw new Error("Project not found");
|
|
||||||
}
|
|
||||||
const taskPlanning: TaskPlanning = {
|
|
||||||
project: project,
|
|
||||||
due_at: values.dueAt ? { type: "DateTimeWithTz", content: dayjs(values.dueAt).utc().format() } : undefined,
|
|
||||||
priority: parseInt(values.priority) as TaskPriority,
|
|
||||||
};
|
|
||||||
await planTask(taskPlanning, notification, mutate);
|
|
||||||
pop();
|
|
||||||
},
|
|
||||||
validation: {
|
|
||||||
project: FormValidation.Required,
|
|
||||||
priority: FormValidation.Required,
|
|
||||||
},
|
|
||||||
});
|
|
||||||
|
|
||||||
return (
|
|
||||||
<Form
|
|
||||||
navigationTitle="Plan task"
|
|
||||||
actions={
|
|
||||||
<ActionPanel>
|
|
||||||
<Action.SubmitForm title="Plan Task" icon={Icon.Calendar} onSubmit={handleSubmit} />
|
|
||||||
</ActionPanel>
|
|
||||||
}
|
|
||||||
>
|
|
||||||
<Form.Description title="Task title" text={notification.title} />
|
|
||||||
<Form.Dropdown
|
|
||||||
title="Project"
|
|
||||||
placeholder="Search project..."
|
|
||||||
filtering={true}
|
|
||||||
throttle={true}
|
|
||||||
isLoading={isLoading}
|
|
||||||
onSearchTextChange={setSearchText}
|
|
||||||
{...itemProps.project}
|
|
||||||
>
|
|
||||||
<Form.Dropdown.Item value="" title="" key={0} />
|
|
||||||
{projects?.map((project) => {
|
|
||||||
return <Form.Dropdown.Item title={project.name} value={project.source_id} key={project.source_id} />;
|
|
||||||
})}
|
|
||||||
</Form.Dropdown>
|
|
||||||
<Form.DatePicker title="Due at" min={new Date()} type={Form.DatePicker.Type.Date} {...itemProps.dueAt} />
|
|
||||||
<Form.Dropdown title="Priority" {...itemProps.priority}>
|
|
||||||
<Form.Dropdown.Item title="Priority 1" value={`${TaskPriority.P1 as number}`} key={TaskPriority.P1} />
|
|
||||||
<Form.Dropdown.Item title="Priority 2" value={`${TaskPriority.P2 as number}`} key={TaskPriority.P2} />
|
|
||||||
<Form.Dropdown.Item title="Priority 3" value={`${TaskPriority.P3 as number}`} key={TaskPriority.P3} />
|
|
||||||
<Form.Dropdown.Item title="Priority 4" value={`${TaskPriority.P4 as number}`} key={TaskPriority.P4} />
|
|
||||||
</Form.Dropdown>
|
|
||||||
</Form>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
async function planTask(
|
|
||||||
taskPlanning: TaskPlanning,
|
|
||||||
notification: Notification,
|
|
||||||
mutate: MutatePromise<Page<Notification> | undefined>,
|
|
||||||
) {
|
|
||||||
if (!isNotificationBuiltFromTask(notification) || !notification.task) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
const preferences = getPreferenceValues<UniversalInboxPreferences>();
|
|
||||||
const toast = await showToast({ style: Toast.Style.Animated, title: "Planning task" });
|
|
||||||
try {
|
|
||||||
await mutate(
|
|
||||||
handleErrors(
|
|
||||||
fetch(`${preferences.universalInboxBaseUrl}/api/tasks/${notification.task.id}`, {
|
|
||||||
method: "PATCH",
|
|
||||||
body: JSON.stringify({
|
|
||||||
project: taskPlanning.project.name,
|
|
||||||
due_at: taskPlanning.due_at,
|
|
||||||
priority: taskPlanning.priority,
|
|
||||||
}),
|
|
||||||
headers: {
|
|
||||||
"Content-Type": "application/json",
|
|
||||||
Authorization: `Bearer ${preferences.apiKey}`,
|
|
||||||
},
|
|
||||||
}),
|
|
||||||
),
|
|
||||||
{
|
|
||||||
optimisticUpdate(page) {
|
|
||||||
if (page) {
|
|
||||||
page.content = page.content.filter((n) => n.id !== notification.id);
|
|
||||||
}
|
|
||||||
return page;
|
|
||||||
},
|
|
||||||
},
|
|
||||||
);
|
|
||||||
|
|
||||||
toast.style = Toast.Style.Success;
|
|
||||||
toast.title = "Task successfully planned";
|
|
||||||
} catch (error) {
|
|
||||||
toast.style = Toast.Style.Failure;
|
|
||||||
toast.title = "Failed to plan task";
|
|
||||||
toast.message = (error as Error).message;
|
|
||||||
throw error;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -7,7 +7,6 @@ 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";
|
||||||
import { useFetch } from "@raycast/utils";
|
import { useFetch } from "@raycast/utils";
|
||||||
import { useState } from "react";
|
|
||||||
|
|
||||||
export default function Command() {
|
export default function Command() {
|
||||||
const preferences = getPreferenceValues<UniversalInboxPreferences>();
|
const preferences = getPreferenceValues<UniversalInboxPreferences>();
|
||||||
@@ -30,11 +29,8 @@ export default function Command() {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
const [notificationKind, setNotificationKind] = useState("");
|
|
||||||
const { isLoading, data, mutate } = useFetch<Page<Notification>>(
|
const { isLoading, data, mutate } = useFetch<Page<Notification>>(
|
||||||
`${preferences.universalInboxBaseUrl}/api/notifications?status=Unread,Read&with_tasks=true${
|
`${preferences.universalInboxBaseUrl}/api/notifications?status=Unread,Read&with_tasks=true`,
|
||||||
notificationKind ? "¬ification_kind=" + notificationKind : ""
|
|
||||||
}`,
|
|
||||||
{
|
{
|
||||||
headers: {
|
headers: {
|
||||||
Authorization: `Bearer ${preferences.apiKey}`,
|
Authorization: `Bearer ${preferences.apiKey}`,
|
||||||
@@ -43,24 +39,10 @@ export default function Command() {
|
|||||||
);
|
);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<List
|
<List isLoading={isLoading}>
|
||||||
isLoading={isLoading}
|
{data?.content.map((notification: Notification) => {
|
||||||
searchBarPlaceholder="Filter notifications..."
|
|
||||||
searchBarAccessory={
|
|
||||||
<NotificationKindDropdown value={notificationKind} onNotificationKindChange={setNotificationKind} />
|
|
||||||
}
|
|
||||||
>
|
|
||||||
{data?.content.length === 0 ? (
|
|
||||||
<List.EmptyView
|
|
||||||
icon={{ source: "ui-logo-transparent.png" }}
|
|
||||||
title="Congrats! You have reach zero inbox 🎉"
|
|
||||||
description="You don't have any new notifications."
|
|
||||||
/>
|
|
||||||
) : (
|
|
||||||
data?.content.map((notification: Notification) => {
|
|
||||||
return <NotificationListItem key={notification.id} notification={notification} mutate={mutate} />;
|
return <NotificationListItem key={notification.id} notification={notification} mutate={mutate} />;
|
||||||
})
|
})}
|
||||||
)}
|
|
||||||
</List>
|
</List>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@@ -96,22 +78,3 @@ function DefaultNotificationListItem({ notification, mutate }: NotificationListI
|
|||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
interface NotificationKindDropdownProps {
|
|
||||||
value: string;
|
|
||||||
onNotificationKindChange: (newValue: string) => void;
|
|
||||||
}
|
|
||||||
|
|
||||||
function NotificationKindDropdown({ value, onNotificationKindChange }: NotificationKindDropdownProps) {
|
|
||||||
return (
|
|
||||||
<List.Dropdown tooltip="Select Notification Kind" value={value} onChange={onNotificationKindChange}>
|
|
||||||
<List.Dropdown.Section title="Notification kind">
|
|
||||||
<List.Dropdown.Item key="0" title="" value="" />
|
|
||||||
<List.Dropdown.Item key="Github" title="Github" value="Github" />
|
|
||||||
<List.Dropdown.Item key="Linear" title="Linear" value="Linear" />
|
|
||||||
<List.Dropdown.Item key="GoogleMail" title="Google Mail" value="GoogleMail" />
|
|
||||||
<List.Dropdown.Item key="Todoist" title="Todoist" value="Todoist" />
|
|
||||||
</List.Dropdown.Section>
|
|
||||||
</List.Dropdown>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|||||||
Reference in New Issue
Block a user