From 53cf083fe534c87aaa0a6adae26c1cb1a03c88f2 Mon Sep 17 00:00:00 2001 From: Nemanja Glumac <31325167+nemanjaglumac@users.noreply.github.com> Date: Thu, 25 Apr 2024 12:54:45 +0200 Subject: [PATCH] Re-wire the `Pulses` entity to use RTK Query under the hood (#41775) * Throw on `Pulse.api.delete` * Add boilerplate `subscriptionApi` * Add `unsubscribe` endpoint * Add types * Delete unused `Pulses.objectActions` * Re-wire `Pulses` entity to use RTK Query for `objectActions` * Re-wire `Pulses.api` to use RTK Query under the hood * Add cache invalidation * Fix `setArchived` objectAction * Update DELETE response type * Fix `params` --- frontend/src/metabase-types/api/index.ts | 1 + .../src/metabase-types/api/subscription.ts | 55 ++++++++++++ frontend/src/metabase/api/index.ts | 1 + frontend/src/metabase/api/subscription.ts | 86 +++++++++++++++++++ frontend/src/metabase/api/tags/constants.ts | 3 +- frontend/src/metabase/api/tags/utils.ts | 16 ++++ frontend/src/metabase/entities/pulses.js | 72 +++++++++------- 7 files changed, 202 insertions(+), 32 deletions(-) create mode 100644 frontend/src/metabase-types/api/subscription.ts create mode 100644 frontend/src/metabase/api/subscription.ts diff --git a/frontend/src/metabase-types/api/index.ts b/frontend/src/metabase-types/api/index.ts index b3e231edee4..d28fa6a5d78 100644 --- a/frontend/src/metabase-types/api/index.ts +++ b/frontend/src/metabase-types/api/index.ts @@ -33,6 +33,7 @@ export * from "./setup"; export * from "./slack"; export * from "./snippets"; export * from "./store"; +export * from "./subscription"; export * from "./table"; export * from "./task"; export * from "./timeline"; diff --git a/frontend/src/metabase-types/api/subscription.ts b/frontend/src/metabase-types/api/subscription.ts new file mode 100644 index 00000000000..07d44c6ec1e --- /dev/null +++ b/frontend/src/metabase-types/api/subscription.ts @@ -0,0 +1,55 @@ +import type { Card } from "./card"; +import type { RegularCollectionId } from "./collection"; +import type { DashboardId } from "./dashboard"; +import type { Channel } from "./notifications"; +import type { Parameter } from "./parameters"; +import type { User } from "./user"; + +export interface ListSubscriptionsRequest { + archived?: boolean; + dashboard_id?: DashboardId; + creator_or_recipient?: boolean; +} + +export interface DashboardSubscription { + archived: boolean; + cards: Card[]; + channels: Channel[]; + collection_id: RegularCollectionId | null; + collection_position: number | null; + created_at: string; + creator: User; + creator_id: number; + dashboard_id: DashboardId; + entity_id: string; + id: number; + name: string; + parameters: Parameter[]; + skip_if_empty: boolean; + updated_at: string; +} + +export interface CreateSubscriptionRequest { + name: string; + cards: Card[]; + channels: Channel[]; + skip_if_empty?: boolean; + collection_id?: RegularCollectionId | null; + collection_position?: number | null; + dashboard_id?: DashboardId; + parameters?: Parameter[]; +} + +export interface UpdateSubscriptionRequest { + id: number; + name?: string; + cards?: Card[]; + channels?: Channel[]; + skip_if_empty?: boolean; + collection_id?: RegularCollectionId | null; + collection_position?: number | null; + dashboard_id?: DashboardId; + parameters?: Parameter[]; + archived?: boolean; + can_write?: boolean; +} diff --git a/frontend/src/metabase/api/index.ts b/frontend/src/metabase/api/index.ts index ea7e0c5b1c2..09bed25e514 100644 --- a/frontend/src/metabase/api/index.ts +++ b/frontend/src/metabase/api/index.ts @@ -19,6 +19,7 @@ export * from "./search"; export * from "./segment"; export * from "./session"; export * from "./snippet"; +export * from "./subscription"; export * from "./table"; export * from "./task"; export * from "./timeline"; diff --git a/frontend/src/metabase/api/subscription.ts b/frontend/src/metabase/api/subscription.ts new file mode 100644 index 00000000000..35f4b48ec73 --- /dev/null +++ b/frontend/src/metabase/api/subscription.ts @@ -0,0 +1,86 @@ +import type { + ListSubscriptionsRequest, + DashboardSubscription, + CreateSubscriptionRequest, + UpdateSubscriptionRequest, +} from "metabase-types/api"; + +import { Api } from "./api"; +import { + idTag, + invalidateTags, + listTag, + provideSubscriptionListTags, + provideSubscriptionTags, +} from "./tags"; + +export const subscriptionApi = Api.injectEndpoints({ + endpoints: builder => ({ + listSubscriptions: builder.query< + DashboardSubscription[], + ListSubscriptionsRequest + >({ + query: params => ({ + method: "GET", + url: "/api/pulse", + params, + }), + providesTags: (subscriptions = []) => + provideSubscriptionListTags(subscriptions), + }), + getSubscription: builder.query<DashboardSubscription, number>({ + query: id => ({ + method: "GET", + url: `/api/pulse/${id}`, + }), + providesTags: subscription => + subscription ? provideSubscriptionTags(subscription) : [], + }), + createSubscription: builder.mutation< + DashboardSubscription, + CreateSubscriptionRequest + >({ + query: body => ({ + method: "POST", + url: "/api/pulse", + body, + }), + invalidatesTags: (_, error) => + invalidateTags(error, [listTag("subscription")]), + }), + updateSubscription: builder.mutation< + DashboardSubscription, + UpdateSubscriptionRequest + >({ + query: ({ id, ...body }) => ({ + method: "PUT", + url: `/api/pulse/${id}`, + body, + }), + invalidatesTags: (_, error, { id }) => + invalidateTags(error, [ + listTag("subscription"), + idTag("subscription", id), + ]), + }), + unsubscribe: builder.mutation<void, number>({ + query: id => ({ + method: "DELETE", + url: `/api/pulse/${id}/subscription`, + }), + invalidatesTags: (_, error, id) => + invalidateTags(error, [ + listTag("subscription"), + idTag("subscription", id), + ]), + }), + }), +}); + +export const { + useListSubscriptionsQuery, + useGetSubscriptionQuery, + useCreateSubscriptionMutation, + useUpdateSubscriptionMutation, + useUnsubscribeMutation, +} = subscriptionApi; diff --git a/frontend/src/metabase/api/tags/constants.ts b/frontend/src/metabase/api/tags/constants.ts index db0db90805f..e558fa6e881 100644 --- a/frontend/src/metabase/api/tags/constants.ts +++ b/frontend/src/metabase/api/tags/constants.ts @@ -18,8 +18,9 @@ export const TAG_TYPES = [ "persisted-model", "revision", "schema", - "snippet", "segment", + "snippet", + "subscription", "table", "task", "timeline", diff --git a/frontend/src/metabase/api/tags/utils.ts b/frontend/src/metabase/api/tags/utils.ts index 7679676ea01..18b06a9e09e 100644 --- a/frontend/src/metabase/api/tags/utils.ts +++ b/frontend/src/metabase/api/tags/utils.ts @@ -10,6 +10,7 @@ import type { CollectionItem, CollectionItemModel, Dashboard, + DashboardSubscription, Database, DatabaseCandidate, Field, @@ -375,6 +376,21 @@ export function provideSnippetTags( return [idTag("snippet", snippet.id)]; } +export function provideSubscriptionListTags( + subscriptions: DashboardSubscription[], +): TagDescription<TagType>[] { + return [ + listTag("subscription"), + ...subscriptions.flatMap(provideSubscriptionTags), + ]; +} + +export function provideSubscriptionTags( + subscription: DashboardSubscription, +): TagDescription<TagType>[] { + return [idTag("subscription", subscription.id)]; +} + export function provideTableListTags( tables: Table[], ): TagDescription<TagType>[] { diff --git a/frontend/src/metabase/entities/pulses.js b/frontend/src/metabase/entities/pulses.js index 978ff30c140..7befcf18c67 100644 --- a/frontend/src/metabase/entities/pulses.js +++ b/frontend/src/metabase/entities/pulses.js @@ -1,12 +1,15 @@ import { t } from "ttag"; -import { canonicalCollectionId } from "metabase/collections/utils"; +import { subscriptionApi } from "metabase/api"; import { getCollectionType } from "metabase/entities/collections"; import { color } from "metabase/lib/colors"; -import { createEntity, undo } from "metabase/lib/entities"; +import { + createEntity, + undo, + entityCompatibleQuery, +} from "metabase/lib/entities"; import * as Urls from "metabase/lib/urls"; import { addUndo } from "metabase/redux/undo"; -import { PulseApi } from "metabase/services"; export const UNSUBSCRIBE = "metabase/entities/pulses/unsubscribe"; @@ -22,6 +25,36 @@ const Pulses = createEntity({ UNSUBSCRIBE, }, + api: { + list: (entityQuery, dispatch) => + entityCompatibleQuery( + entityQuery, + dispatch, + subscriptionApi.endpoints.listSubscriptions, + ), + get: (entityQuery, options, dispatch) => + entityCompatibleQuery( + entityQuery.id, + dispatch, + subscriptionApi.endpoints.getSubscription, + ), + create: (entityQuery, dispatch) => + entityCompatibleQuery( + entityQuery, + dispatch, + subscriptionApi.endpoints.createSubscription, + ), + update: (entityQuery, dispatch) => + entityCompatibleQuery( + entityQuery, + dispatch, + subscriptionApi.endpoints.updateSubscription, + ), + delete: () => { + throw new TypeError("Pulses.api.delete is not supported"); + }, + }, + objectActions: { setArchived: ({ id }, archived, opts) => { return Pulses.actions.update( @@ -31,37 +64,14 @@ const Pulses = createEntity({ ); }, - setChannels: ({ id }, channels, opts) => { - return Pulses.actions.update( - { id }, - { channels }, - undo(opts, t`subscription`, t`updated`), - ); - }, - - setCollection: ({ id }, collection, opts) => { - return Pulses.actions.update( - { id }, - { collection_id: canonicalCollectionId(collection && collection.id) }, - undo(opts, t`subscription`, t`moved`), - ); - }, - - setPinned: ({ id }, pinned, opts) => { - return Pulses.actions.update( - { id }, - { - collection_position: - typeof pinned === "number" ? pinned : pinned ? 1 : null, - }, - opts, - ); - }, - unsubscribe: ({ id }) => async dispatch => { - await PulseApi.unsubscribe({ id }); + await entityCompatibleQuery( + id, + dispatch, + subscriptionApi.endpoints.unsubscribe, + ); dispatch(addUndo({ message: t`Successfully unsubscribed` })); dispatch({ type: UNSUBSCRIBE, payload: { id } }); dispatch({ type: Pulses.actionTypes.INVALIDATE_LISTS_ACTION }); -- GitLab