sadpandajoe commented on code in PR #35832:
URL: https://github.com/apache/superset/pull/35832#discussion_r4051285470


##########
superset-frontend/src/features/alerts/components/NotificationMethod.tsx:
##########
@@ -540,24 +551,33 @@ export const NotificationMethod: 
FunctionComponent<NotificationMethodProps> = ({
                 ) : (
                   // for SlackV2
                   <div className="input-container">
-                    <Select
+                    <AsyncSelect
                       ariaLabel={t('Select channels')}
                       mode="multiple"
                       name="recipients"
                       value={slackRecipients}
-                      options={slackOptions}
+                      options={fetchSlackChannels}

Review Comment:
   An earlier search can resolve after a newer one and `AsyncSelect` will still 
merge that late result; with filtering disabled, those stale channels remain 
selectable under the current query. Could this abort or ignore responses whose 
search generation is no longer current?



##########
superset/reports/api.py:
##########
@@ -577,14 +582,31 @@ def slack_channels(self, **kwargs: Any) -> Response:
             search_string = params.get("search_string")
             types = params.get("types", [])
             exact_match = params.get("exact_match", False)
+            cursor = params.get("cursor")
+            limit = params.get("limit", 100)
             force = params.get("force", False)
-            channels = get_channels_with_search(
+
+            # Clear cache if force refresh requested
+            if force:
+                cache_manager.cache.delete(SLACK_CHANNELS_CACHE_KEY)

Review Comment:
   Deleting the last known-good channel cache before either refresh path 
succeeds means a Slack or broker failure turns a manual refresh into a global 
cold cache; the previous forced fetch kept the old entry until a replacement 
was available. Could this retain or restore the cached list until the new fetch 
completes successfully?



##########
superset-frontend/src/features/alerts/hooks/useSlackChannels.ts:
##########
@@ -0,0 +1,191 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+import { useCallback, useRef, useState } from 'react';
+import { logging, SupersetClient, t } from '@superset-ui/core';
+import rison from 'rison';
+import { SlackChannel } from '../types';
+
+export interface SlackChannelOption {
+  label: string;
+  value: string;
+}
+
+export interface SlackChannelsResult {
+  data: SlackChannelOption[];
+  totalCount: number;
+  has_more?: boolean;
+  next_cursor?: string | null;
+}
+
+export interface FetchChannelsParams {
+  search: string;
+  page: number;
+  pageSize: number;
+  force?: boolean;
+}
+
+export interface UseSlackChannelsResult {
+  fetchChannels: (params: FetchChannelsParams) => Promise<SlackChannelsResult>;
+  refreshChannels: () => Promise<void>;
+  isRefreshing: boolean;
+}
+
+/**
+ * Cache types for managing Slack channel data
+ */
+type CursorCache = Record<string, string | null>;
+type DataCache = Record<string, SlackChannelsResult>;
+type PendingRequestsCache = Record<string, Promise<SlackChannelsResult>>;
+
+/**
+ * Custom hook for managing Slack channels with caching and pagination
+ */
+export function useSlackChannels(
+  onError?: (message: string) => void,
+): UseSlackChannelsResult {
+  const cursorRef = useRef<CursorCache>({});
+  const dataCache = useRef<DataCache>({});
+  const pendingRequests = useRef<PendingRequestsCache>({});
+  const [isRefreshing, setIsRefreshing] = useState(false);
+
+  const fetchChannels = useCallback(
+    async ({
+      search,
+      page,
+      pageSize,
+      force = false,
+    }: FetchChannelsParams): Promise<SlackChannelsResult> => {
+      const cacheKey = `${search}:${page}`;
+
+      if (!force && dataCache.current[cacheKey]) {
+        return dataCache.current[cacheKey];
+      }
+
+      if (!force && cacheKey in pendingRequests.current) {
+        return pendingRequests.current[cacheKey];
+      }
+
+      const cursor = page > 0 ? cursorRef.current[cacheKey] : null;
+
+      const params: Record<string, any> = {
+        types: ['public_channel', 'private_channel'],
+        limit: pageSize,
+      };
+
+      if (search) {
+        params.search_string = search;
+      }
+
+      if (cursor) {
+        params.cursor = cursor;
+      }
+
+      if (force) {
+        params.force = true;
+      }
+
+      const queryString = rison.encode(params);
+      const endpoint = `/api/v1/report/slack_channels/?q=${queryString}`;
+
+      const fetchPromise = (async () => {
+        try {
+          const response = await SupersetClient.get({ endpoint });
+
+          const {
+            result,
+            next_cursor: nextCursor,
+            has_more: hasMore,
+          } = response.json;
+
+          if (nextCursor) {
+            cursorRef.current[`${search}:${page + 1}`] = nextCursor;
+          }
+
+          const options = result.map((channel: SlackChannel) => ({
+            label: channel.name,

Review Comment:
   Mapping every channel to only its name and ID drops `is_member` and removes 
the previous “Bot not in channel” warning, so users can save a public channel 
that the Slack app cannot post to and discover that only when delivery fails. 
Could the option label preserve the membership warning?



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: [email protected]

For queries about this service, please contact Infrastructure at:
[email protected]


---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]

Reply via email to