codeant-ai-for-open-source[bot] commented on code in PR #41285:
URL: https://github.com/apache/superset/pull/41285#discussion_r3453825362
##########
superset-frontend/src/SqlLab/components/SqlEditor/index.tsx:
##########
@@ -271,6 +279,44 @@ const SqlEditor: FC<Props> = ({
const logAction = useLogAction({ queryEditorId: queryEditor.id });
const isActive = currentQueryEditorId === queryEditor.id;
+
+ // Re-renders when an extension registers a northPane view after async load.
+ const northPaneViews = useViews(ViewLocations.sqllab.northPane) || [];
+
+ // ID of the northPane view active for this tab, or null for the default
+ // SQL editor layout. Set by an extension via PENDING_NORTH_PANE_VIEW_KEY
+ // before calling createTab(); persisted per-tab in localStorage.
+ const [northPaneViewId, setNorthPaneViewId] = useState<string | null>(() => {
+ const pendingViewId = localStorage.getItem(PENDING_NORTH_PANE_VIEW_KEY);
+ if (pendingViewId) {
+ localStorage.removeItem(PENDING_NORTH_PANE_VIEW_KEY);
+ localStorage.setItem(NORTH_PANE_VIEW_KEY(queryEditor.id), pendingViewId);
+ return pendingViewId;
+ }
+ return localStorage.getItem(NORTH_PANE_VIEW_KEY(queryEditor.id));
Review Comment:
**Suggestion:** The persisted north-pane mode is written using `tabViewId ??
id` but read back using only `id`, so tabs with a backend `tabViewId` can fail
to restore their saved mode after reloads. Read with the same key strategy used
for writes to keep persistence consistent. [cache]
<details>
<summary><b>Severity Level:</b> Major ⚠️</summary>
```mdx
- ❌ North-pane layout not restored for backend-persisted SQL tabs.
- ⚠️ Extensions' full-pane modes appear unreliable after reloads.
```
</details>
<details>
<summary><b>Steps of Reproduction ✅ </b></summary>
```mdx
1. Open SQL Lab so `TabbedSqlEditors` renders and instantiates `SqlEditor`
for each
`QueryEditor` tab, as seen in
`superset-frontend/src/SqlLab/components/TabbedSqlEditors/index.tsx:254-268`
where it
builds `tabItems` and renders `<SqlEditor queryEditor={qe} />`.
2. Configure an extension to set `PENDING_NORTH_PANE_VIEW_KEY` before
creating a tab as
documented in `superset-frontend/src/SqlLab/contributions.ts:60-72`; when
the tab is
created, `SqlEditor`'s initializer at `index.tsx:289-297` reads this key,
stores it under
`NORTH_PANE_VIEW_KEY(queryEditor.id)` and sets `northPaneViewId` for that
tab.
3. With backend persistence enabled, let `EditorAutoSync` at
`superset-frontend/src/SqlLab/components/EditorAutoSync/index.tsx:161-168`
call
`syncQueryEditor(firstUnsavedQueryEditor)`, and then `syncQueryEditor` at
`superset-frontend/src/SqlLab/actions/sqlLab.ts:124-171` persists the editor
to
`/tabstateview/` and sets `queryEditor.tabViewId = json.id.toString()`.
4. While the persisted tab is open, any change that keeps `northPaneViewId`
set (for
example, the extension default) triggers the effect at
`SqlEditor/index.tsx:299-307`,
which computes `persistKey = NORTH_PANE_VIEW_KEY(queryEditor.tabViewId ??
queryEditor.id)`
and writes the mode under `sqllab.northPaneView.<tabViewId>` when
`tabViewId` is present.
5. Reload the browser: on remount, `SqlEditor`'s state initializer at
`index.tsx:289-297`
still calls `localStorage.getItem(NORTH_PANE_VIEW_KEY(queryEditor.id))`
(line 296), which
uses the `id`-based key instead of the `tabViewId`-based key written in step
4; because
there is no value under `sqllab.northPaneView.<id>`, `northPaneViewId`
becomes `null` and
the tab falls back to the default editor+SouthPane layout instead of
restoring the saved
north-pane mode.
```
</details>
[](https://app.codeant.ai/fix-in-ide?tool=cursor&prompt_id=5c63cc9fe1c942b4aa61a15103e7675b&service=github&base_url=https%3A%2F%2Fgithub.com&org=apache&repo=apache%2Fsuperset)
[](https://app.codeant.ai/fix-in-ide?tool=vscode-claude&prompt_id=5c63cc9fe1c942b4aa61a15103e7675b&service=github&base_url=https%3A%2F%2Fgithub.com&org=apache&repo=apache%2Fsuperset)
*(Use Cmd/Ctrl + Click for best experience)*
<details>
<summary><b>Prompt for AI Agent 🤖 </b></summary>
```mdx
This is a comment left during a code review.
**Path:** superset-frontend/src/SqlLab/components/SqlEditor/index.tsx
**Line:** 296:296
**Comment:**
*Cache: The persisted north-pane mode is written using `tabViewId ??
id` but read back using only `id`, so tabs with a backend `tabViewId` can fail
to restore their saved mode after reloads. Read with the same key strategy used
for writes to keep persistence consistent.
Validate the correctness of the flagged issue. If correct, How can I resolve
this? If you propose a fix, implement it and please make it concise.
Once fix is implemented, also check other comments on the same PR, and ask
user if the user wants to fix the rest of the comments as well. if said yes,
then fetch all the comments validate the correctness and implement a minimal fix
```
</details>
<a
href='https://app.codeant.ai/feedback?pr_url=https%3A%2F%2Fgithub.com%2Fapache%2Fsuperset%2Fpull%2F41285&comment_hash=3c5fa4c500ff2369bc92b0fa7e4fa8651a87b34504a672b3523bd7ad2eb05b8d&reaction=like'>👍</a>
| <a
href='https://app.codeant.ai/feedback?pr_url=https%3A%2F%2Fgithub.com%2Fapache%2Fsuperset%2Fpull%2F41285&comment_hash=3c5fa4c500ff2369bc92b0fa7e4fa8651a87b34504a672b3523bd7ad2eb05b8d&reaction=dislike'>👎</a>
##########
superset-frontend/src/SqlLab/components/SqlEditor/index.tsx:
##########
@@ -271,6 +279,44 @@ const SqlEditor: FC<Props> = ({
const logAction = useLogAction({ queryEditorId: queryEditor.id });
const isActive = currentQueryEditorId === queryEditor.id;
+
+ // Re-renders when an extension registers a northPane view after async load.
+ const northPaneViews = useViews(ViewLocations.sqllab.northPane) || [];
+
+ // ID of the northPane view active for this tab, or null for the default
+ // SQL editor layout. Set by an extension via PENDING_NORTH_PANE_VIEW_KEY
+ // before calling createTab(); persisted per-tab in localStorage.
+ const [northPaneViewId, setNorthPaneViewId] = useState<string | null>(() => {
+ const pendingViewId = localStorage.getItem(PENDING_NORTH_PANE_VIEW_KEY);
+ if (pendingViewId) {
+ localStorage.removeItem(PENDING_NORTH_PANE_VIEW_KEY);
+ localStorage.setItem(NORTH_PANE_VIEW_KEY(queryEditor.id), pendingViewId);
+ return pendingViewId;
+ }
+ return localStorage.getItem(NORTH_PANE_VIEW_KEY(queryEditor.id));
+ });
+
+ useEffect(() => {
+ const persistKey = NORTH_PANE_VIEW_KEY(
+ queryEditor.tabViewId ?? queryEditor.id,
+ );
+ if (northPaneViewId) {
+ localStorage.setItem(persistKey, northPaneViewId);
+ } else {
+ localStorage.removeItem(persistKey);
+ }
+ }, [queryEditor.tabViewId, queryEditor.id, northPaneViewId]);
+
+ useEffect(() => {
+ const handler = (e: StorageEvent) => {
+ if (e.key === NORTH_PANE_VIEW_KEY(queryEditor.id)) {
+ setNorthPaneViewId(e.newValue || null);
Review Comment:
**Suggestion:** The storage event listener only watches the `id`-based key,
but updates are persisted to the `tabViewId`-based key once available. That
mismatch prevents cross-tab/window synchronization of mode changes for
persisted tabs. Listen on the same resolved key used when persisting. [logic
error]
<details>
<summary><b>Severity Level:</b> Major ⚠️</summary>
```mdx
- ⚠️ North-pane mode changes not synced between browser windows.
- ⚠️ Users see inconsistent layouts across concurrent SQL Lab sessions.
```
</details>
<details>
<summary><b>Steps of Reproduction ✅ </b></summary>
```mdx
1. Open SQL Lab in a browser so `TabbedSqlEditors` renders `SqlEditor`
instances for each
tab
(`superset-frontend/src/SqlLab/components/TabbedSqlEditors/index.tsx:254-268`),
and
ensure backend persistence is on so tabs acquire a `tabViewId` via
`syncQueryEditor` in
`actions/sqlLab.ts:124-171`.
2. For a persisted tab (with `queryEditor.tabViewId` set), change or confirm
an
extension-provided north-pane view so that `northPaneViewId` in `SqlEditor`
is non-null;
the effect at
`superset-frontend/src/SqlLab/components/SqlEditor/index.tsx:299-307` then
writes this id using `persistKey = NORTH_PANE_VIEW_KEY(queryEditor.tabViewId
??
queryEditor.id)`, i.e. under `sqllab.northPaneView.<tabViewId>`.
3. Open the same SQL Lab tab in a second browser window (or tab) so both
windows render
`SqlEditor` for the same backend-persisted `QueryEditor`; each instance
registers a
`storage` event listener in `SqlEditor/index.tsx:310-318`.
4. Inspect the listener at `index.tsx:311-313`: it only updates state when
`e.key ===
NORTH_PANE_VIEW_KEY(queryEditor.id)` and then calls
`setNorthPaneViewId(e.newValue ||
null)`; there is no check for the `tabViewId`-based key used by the writer.
5. In window A, switch the north-pane mode again; the effect at
`index.tsx:299-307`
updates `localStorage` key `sqllab.northPaneView.<tabViewId>`, which
triggers a `storage`
event in window B with `e.key` set to that `tabViewId`-based key, but window
B's handler
condition at line 312 fails (it is comparing against
`NORTH_PANE_VIEW_KEY(queryEditor.id)`), so `setNorthPaneViewId` is never
invoked and the
second window's mode remains stale.
```
</details>
[](https://app.codeant.ai/fix-in-ide?tool=cursor&prompt_id=ec2f42d8792c4a1ab8b13c6716966f92&service=github&base_url=https%3A%2F%2Fgithub.com&org=apache&repo=apache%2Fsuperset)
[](https://app.codeant.ai/fix-in-ide?tool=vscode-claude&prompt_id=ec2f42d8792c4a1ab8b13c6716966f92&service=github&base_url=https%3A%2F%2Fgithub.com&org=apache&repo=apache%2Fsuperset)
*(Use Cmd/Ctrl + Click for best experience)*
<details>
<summary><b>Prompt for AI Agent 🤖 </b></summary>
```mdx
This is a comment left during a code review.
**Path:** superset-frontend/src/SqlLab/components/SqlEditor/index.tsx
**Line:** 312:313
**Comment:**
*Logic Error: The storage event listener only watches the `id`-based
key, but updates are persisted to the `tabViewId`-based key once available.
That mismatch prevents cross-tab/window synchronization of mode changes for
persisted tabs. Listen on the same resolved key used when persisting.
Validate the correctness of the flagged issue. If correct, How can I resolve
this? If you propose a fix, implement it and please make it concise.
Once fix is implemented, also check other comments on the same PR, and ask
user if the user wants to fix the rest of the comments as well. if said yes,
then fetch all the comments validate the correctness and implement a minimal fix
```
</details>
<a
href='https://app.codeant.ai/feedback?pr_url=https%3A%2F%2Fgithub.com%2Fapache%2Fsuperset%2Fpull%2F41285&comment_hash=5c70909fcab90aef44b4be35d1df2adf6701ab08659052fc1b9a7a8591ecae1f&reaction=like'>👍</a>
| <a
href='https://app.codeant.ai/feedback?pr_url=https%3A%2F%2Fgithub.com%2Fapache%2Fsuperset%2Fpull%2F41285&comment_hash=5c70909fcab90aef44b4be35d1df2adf6701ab08659052fc1b9a7a8591ecae1f&reaction=dislike'>👎</a>
##########
superset-frontend/src/SqlLab/components/TabbedSqlEditors/index.tsx:
##########
@@ -98,6 +101,82 @@ const AddTabIconWrapper = styled.span`
// Get the user's OS
const userOS = detectOS();
+const newTabTooltip =
+ userOS === 'Windows' ? t('New tab (Ctrl + q)') : t('New tab (Ctrl + t)');
+
+const PlusIcon = (
+ <AddTabIconWrapper>
+ <Icons.PlusOutlined iconSize="l" data-test="add-tab-icon" />
+ </AddTabIconWrapper>
+);
+
+function NewTabButton({ onAddSqlEditor }: { onAddSqlEditor: () => void }) {
+ const [open, setOpen] = useState(false);
+
+ const dropdownItems = useMemo<MenuItemType[]>(() => {
+ if (!open) return [];
+ const primaryItems =
+ menus.getMenu(ViewLocations.sqllab.newTab)?.primary ?? [];
+ return [
+ {
+ key: 'sql-editor',
+ label: t('SQL Editor'),
+ icon: <Icons.TableOutlined iconSize="m" />,
+ onClick: () => {
+ setOpen(false);
+ onAddSqlEditor();
+ },
+ },
+ ...primaryItems.map(item => {
+ const command = commands.getCommand(item.command);
+ const Icon = command?.icon
+ ? ((Icons as Record<string, typeof Icons.FileOutlined>)[
+ command.icon
+ ] ?? Icons.FileOutlined)
+ : Icons.FileOutlined;
+ return {
+ key: command?.id ?? item.command,
+ label: command?.title ?? item.command,
+ icon: <Icon iconSize="m" />,
+ onClick: () => {
+ setOpen(false);
+ commands.executeCommand(item.command);
+ },
+ } as MenuItemType;
+ }),
+ ];
+ }, [open, onAddSqlEditor]);
+
+ const handleClick = (e: React.MouseEvent) => {
+ // Antd's Tabs wraps addIcon in its own <button onClick={() =>
onEdit('add')}>.
+ // Stop propagation so antd doesn't also call newQueryEditor() while we
handle it.
+ e.stopPropagation();
+ const primaryItems =
+ menus.getMenu(ViewLocations.sqllab.newTab)?.primary ?? [];
+ if (primaryItems.length === 0) {
+ onAddSqlEditor();
+ } else {
+ setOpen(prev => !prev);
+ }
+ };
+
+ return (
+ <Tooltip id="add-tab" placement="left" title={newTabTooltip}>
+ <Dropdown
+ open={open}
+ onOpenChange={setOpen}
+ menu={{ items: dropdownItems }}
+ trigger={[]}
+ >
+ {/* eslint-disable-next-line jsx-a11y/click-events-have-key-events */}
+ <span role="button" tabIndex={0} onClick={handleClick}>
+ {PlusIcon}
Review Comment:
**Suggestion:** The custom add-tab behavior is only attached to the inner
`<span>` click handler, while AntD wraps `addIcon` in its own button that still
handles keyboard activation. Pressing Enter/Space on that wrapper triggers the
default tab-add path instead of opening/using the extension tab-type dropdown,
so extension tab types are inaccessible via keyboard. Move the custom handling
to the wrapper interaction path (or intercept keyboard events as well).
[incomplete implementation]
<details>
<summary><b>Severity Level:</b> Major ⚠️</summary>
```mdx
- ⚠️ Keyboard users cannot open extension-contributed SQL tab types.
- ⚠️ New-tab dropdown behavior regresses in accessibility and UX.
```
</details>
<details>
<summary><b>Steps of Reproduction ✅ </b></summary>
```mdx
1. Register an extension that contributes `newTab` menu items under
`ViewLocations.sqllab.newTab` defined in
`superset-frontend/src/SqlLab/contributions.ts:40-57`, so
`menus.getMenu(ViewLocations.sqllab.newTab)?.primary` returns items inside
`NewTabButton`
at `TabbedSqlEditors/index.tsx:116-147`.
2. In SQL Lab, `TabbedSqlEditors` renders `StyledEditableTabs` with
`type={...
'editable-card'}` and `addIcon={<NewTabButton onAddSqlEditor={() =>
this.newQueryEditor()}
/>}` at
`superset-frontend/src/SqlLab/components/TabbedSqlEditors/index.tsx:306-318`,
delegating the add-tab control to a `NewTabButton`.
3. `NewTabButton`'s `handleClick` at `index.tsx:150-161` contains the
comment "Antd's Tabs
wraps addIcon in its own `<button onClick={() => onEdit('add')}>`" and calls
`e.stopPropagation()` before either opening the dropdown or calling
`onAddSqlEditor()`,
but this handler is only attached to the inner `<span>`'s `onClick`.
4. The rendered markup for the inner control is `<span role="button"
tabIndex={0}
onClick={handleClick}>` with `{PlusIcon}` children at `index.tsx:171-174`;
there is no
`onKeyDown` or `onKeyPress` handler on this span, so keyboard events
(Enter/Space) are
handled by AntD's wrapper `<button>` around `addIcon`, not by `handleClick`.
5. With an extension contributing `newTab` items, focus the plus button
using the keyboard
and press Enter/Space: AntD's wrapper button invokes `onEdit('add')`, which
calls
`handleEdit('add')` and `newQueryEditor()` at
`TabbedSqlEditors/index.tsx:229-239`,
creating a default SQL Editor tab; `handleClick` is never invoked, so the
dropdown listing
extension tab types is not shown and extension-provided tab types are
inaccessible via
keyboard.
```
</details>
[](https://app.codeant.ai/fix-in-ide?tool=cursor&prompt_id=6563e1c04129450e9e1e48028dd8b442&service=github&base_url=https%3A%2F%2Fgithub.com&org=apache&repo=apache%2Fsuperset)
[](https://app.codeant.ai/fix-in-ide?tool=vscode-claude&prompt_id=6563e1c04129450e9e1e48028dd8b442&service=github&base_url=https%3A%2F%2Fgithub.com&org=apache&repo=apache%2Fsuperset)
*(Use Cmd/Ctrl + Click for best experience)*
<details>
<summary><b>Prompt for AI Agent 🤖 </b></summary>
```mdx
This is a comment left during a code review.
**Path:** superset-frontend/src/SqlLab/components/TabbedSqlEditors/index.tsx
**Line:** 172:173
**Comment:**
*Incomplete Implementation: The custom add-tab behavior is only
attached to the inner `<span>` click handler, while AntD wraps `addIcon` in its
own button that still handles keyboard activation. Pressing Enter/Space on that
wrapper triggers the default tab-add path instead of opening/using the
extension tab-type dropdown, so extension tab types are inaccessible via
keyboard. Move the custom handling to the wrapper interaction path (or
intercept keyboard events as well).
Validate the correctness of the flagged issue. If correct, How can I resolve
this? If you propose a fix, implement it and please make it concise.
Once fix is implemented, also check other comments on the same PR, and ask
user if the user wants to fix the rest of the comments as well. if said yes,
then fetch all the comments validate the correctness and implement a minimal fix
```
</details>
<a
href='https://app.codeant.ai/feedback?pr_url=https%3A%2F%2Fgithub.com%2Fapache%2Fsuperset%2Fpull%2F41285&comment_hash=3d39fa019e43ff0113da80604a71e981b35e93dd5f0dfa68864328b88905c1d6&reaction=like'>👍</a>
| <a
href='https://app.codeant.ai/feedback?pr_url=https%3A%2F%2Fgithub.com%2Fapache%2Fsuperset%2Fpull%2F41285&comment_hash=3d39fa019e43ff0113da80604a71e981b35e93dd5f0dfa68864328b88905c1d6&reaction=dislike'>👎</a>
##########
superset-frontend/src/extensions/ExtensionsStartup.tsx:
##########
@@ -72,9 +75,28 @@ const ExtensionsStartup: React.FC<{ children?:
React.ReactNode }> = ({
views,
};
+ // Load extensions without blocking the initial render (see #40915);
+ // surface any load failure as a warning toast instead of failing silently.
if (isFeatureEnabled(FeatureFlag.EnableExtensions)) {
- ExtensionsLoader.getInstance().initializeExtensions();
+ ExtensionsLoader.getInstance()
+ .initializeExtensions()
+ .then(() =>
+ supersetCore.utils.logging.info(
+ 'Extensions initialized successfully.',
+ ),
+ )
+ .catch(error => {
+ supersetCore.utils.logging.error(
+ 'Error setting up extensions:',
+ error,
+ );
+ dispatch(
+ addWarningToast(t('Extensions failed to load: %s', String(error))),
+ );
+ });
Review Comment:
**Suggestion:** `initializeExtensions()` already catches and swallows its
own failures, so this promise chain always resolves and the `.catch(...)`
branch here will never run. As a result, extension load failures still won't
show the warning toast, and the success log can be emitted even after an error.
Make the loader rethrow (or return a failure signal) so this caller can
reliably detect and toast failures. [api mismatch]
<details>
<summary><b>Severity Level:</b> Major ⚠️</summary>
```mdx
- ⚠️ Extension load failures never surface as warning toasts.
- ⚠️ Logs may report successful initialization despite underlying errors.
```
</details>
<details>
<summary><b>Steps of Reproduction ✅ </b></summary>
```mdx
1. Ensure the extensions feature flag is enabled so
`FeatureFlag.EnableExtensions` is
true; in this case, `ExtensionsStartup`'s `useEffect` at
`superset-frontend/src/extensions/ExtensionsStartup.tsx:62-80` sets
`window.superset` and
then executes the block starting at line 80 which calls
`ExtensionsLoader.getInstance().initializeExtensions()`.
2. Inspect `ExtensionsLoader.initializeExtensions()` in
`superset-frontend/src/extensions/ExtensionsLoader.ts:55-79`: it wraps the
async logic in
a try/catch at lines 63-77, logging `logging.error('Error setting up
extensions:',
error);` on failure but never rethrowing or rejecting the promise; instead,
`this.initializationPromise` always resolves (line 79) regardless of success.
3. Configure `/api/v1/extensions/` to fail (for example, misconfigure the
endpoint or have
the backend return HTTP 500), causing `SupersetClient.get()` at
`ExtensionsLoader.ts:65-67` to throw; the catch block at
`ExtensionsLoader.ts:74-77` logs
the error and then allows the async IIFE to complete normally, resolving
`initializeExtensions()` without propagating the failure.
4. Back in `ExtensionsStartup`, the `then` branch at
`ExtensionsStartup.tsx:81-87` logs
"Extensions initialized successfully." via
`supersetCore.utils.logging.info(...)` when the
resolved promise returns, even though initialization actually failed, and
because
`initializeExtensions()` never rejects, the `.catch(error => { ...
addWarningToast(...)
})` branch at `ExtensionsStartup.tsx:88-96` is never invoked and the
intended warning
toast is never shown.
```
</details>
[](https://app.codeant.ai/fix-in-ide?tool=cursor&prompt_id=8b4c69b5786548a1bf6bed66fbb6426f&service=github&base_url=https%3A%2F%2Fgithub.com&org=apache&repo=apache%2Fsuperset)
[](https://app.codeant.ai/fix-in-ide?tool=vscode-claude&prompt_id=8b4c69b5786548a1bf6bed66fbb6426f&service=github&base_url=https%3A%2F%2Fgithub.com&org=apache&repo=apache%2Fsuperset)
*(Use Cmd/Ctrl + Click for best experience)*
<details>
<summary><b>Prompt for AI Agent 🤖 </b></summary>
```mdx
This is a comment left during a code review.
**Path:** superset-frontend/src/extensions/ExtensionsStartup.tsx
**Line:** 81:96
**Comment:**
*Api Mismatch: `initializeExtensions()` already catches and swallows
its own failures, so this promise chain always resolves and the `.catch(...)`
branch here will never run. As a result, extension load failures still won't
show the warning toast, and the success log can be emitted even after an error.
Make the loader rethrow (or return a failure signal) so this caller can
reliably detect and toast failures.
Validate the correctness of the flagged issue. If correct, How can I resolve
this? If you propose a fix, implement it and please make it concise.
Once fix is implemented, also check other comments on the same PR, and ask
user if the user wants to fix the rest of the comments as well. if said yes,
then fetch all the comments validate the correctness and implement a minimal fix
```
</details>
<a
href='https://app.codeant.ai/feedback?pr_url=https%3A%2F%2Fgithub.com%2Fapache%2Fsuperset%2Fpull%2F41285&comment_hash=9f1635fc055ae3e78e94e37f56145476000405ddbb9255d35d172a57969d289b&reaction=like'>👍</a>
| <a
href='https://app.codeant.ai/feedback?pr_url=https%3A%2F%2Fgithub.com%2Fapache%2Fsuperset%2Fpull%2F41285&comment_hash=9f1635fc055ae3e78e94e37f56145476000405ddbb9255d35d172a57969d289b&reaction=dislike'>👎</a>
--
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]