This is an automated email from the ASF dual-hosted git repository.
pierrejeambrun pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/airflow.git
The following commit(s) were added to refs/heads/main by this push:
new a3ec1c59f5a Move grid focus state to store (#54393)
a3ec1c59f5a is described below
commit a3ec1c59f5af83deba650376ecbfa9cb8d44f26b
Author: Pierre Jeambrun <[email protected]>
AuthorDate: Tue Aug 12 18:58:05 2025 +0200
Move grid focus state to store (#54393)
---
.../airflow/ui/src/layouts/Details/Grid/Grid.tsx | 22 ++++++++++-------
.../ui/src/layouts/Details/Grid/useGridStore.ts | 28 ++++++++++++++++++++++
2 files changed, 41 insertions(+), 9 deletions(-)
diff --git a/airflow-core/src/airflow/ui/src/layouts/Details/Grid/Grid.tsx
b/airflow-core/src/airflow/ui/src/layouts/Details/Grid/Grid.tsx
index f631fc57e46..f8a618015c3 100644
--- a/airflow-core/src/airflow/ui/src/layouts/Details/Grid/Grid.tsx
+++ b/airflow-core/src/airflow/ui/src/layouts/Details/Grid/Grid.tsx
@@ -35,6 +35,7 @@ import { Bar } from "./Bar";
import { DurationAxis } from "./DurationAxis";
import { DurationTick } from "./DurationTick";
import { TaskNames } from "./TaskNames";
+import { useGridStore } from "./useGridStore";
import { flattenNodes } from "./utils";
dayjs.extend(dayjsDuration);
@@ -59,7 +60,7 @@ type Props = {
export const Grid = ({ limit }: Props) => {
const { t: translate } = useTranslation("dag");
const gridRef = useRef<HTMLDivElement>(null);
- const [isGridFocused, setIsGridFocused] = useState(false);
+ const { isGridFocused, setIsGridFocused } = useGridStore();
const [selectedIsVisible, setSelectedIsVisible] = useState<boolean |
undefined>();
const [hasActiveRun, setHasActiveRun] = useState<boolean | undefined>();
@@ -104,14 +105,17 @@ export const Grid = ({ limit }: Props) => {
const { flatNodes } = useMemo(() => flattenNodes(dagStructure,
openGroupIds), [dagStructure, openGroupIds]);
- const setGridFocus = useCallback((focused: boolean) => {
- setIsGridFocused(focused);
- if (focused) {
- gridRef.current?.focus();
- } else {
- gridRef.current?.blur();
- }
- }, []);
+ const setGridFocus = useCallback(
+ (focused: boolean) => {
+ setIsGridFocused(focused);
+ if (focused) {
+ gridRef.current?.focus();
+ } else {
+ gridRef.current?.blur();
+ }
+ },
+ [setIsGridFocused],
+ );
const { mode, setMode } = useNavigation({
enabled: isGridFocused,
diff --git
a/airflow-core/src/airflow/ui/src/layouts/Details/Grid/useGridStore.ts
b/airflow-core/src/airflow/ui/src/layouts/Details/Grid/useGridStore.ts
new file mode 100644
index 00000000000..7f580649932
--- /dev/null
+++ b/airflow-core/src/airflow/ui/src/layouts/Details/Grid/useGridStore.ts
@@ -0,0 +1,28 @@
+/*!
+ * 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 { create } from "zustand";
+
+export const useGridStore = create<{ isGridFocused: boolean; setIsGridFocused:
(value: boolean) => void }>(
+ (set) => ({
+ // isGridFocused is shared between different pages (Run, GroupInstance,
MappedInstance, TaskInstance, etc.).
+ // This will avoid many prop drilling and allow proper refocus of the grid
when navigating between these pages via grid links.
+ isGridFocused: false,
+ setIsGridFocused: (value: boolean) => set({ isGridFocused: value }),
+ }),
+);