From 8d3713067162f73b7d6fdcfd4db54d1ea7105004 Mon Sep 17 00:00:00 2001 From: Suzette McCanny Date: Thu, 25 Jul 2024 15:18:45 -0400 Subject: [PATCH 01/21] make menu bar responsive --- client/src/components/menubar/index.tsx | 295 +++++++++++------------ client/src/components/menubar/style.ts | 50 ++++ client/src/components/menubar/subset.tsx | 17 +- 3 files changed, 207 insertions(+), 155 deletions(-) create mode 100644 client/src/components/menubar/style.ts diff --git a/client/src/components/menubar/index.tsx b/client/src/components/menubar/index.tsx index df404e649..89c37daf9 100644 --- a/client/src/components/menubar/index.tsx +++ b/client/src/components/menubar/index.tsx @@ -6,6 +6,13 @@ import { IconNames } from "@blueprintjs/icons"; import * as globals from "../../globals"; // @ts-expect-error ts-migrate(2307) FIXME: Cannot find module './menubar.css' or its correspo... Remove this comment to see the full error message import styles from "./menubar.css"; +import { + ControlsWrapper, + EmbeddingWrapper, + MenuBarWrapper, + ResponsiveMenuGroupOne, + ResponsiveMenuGroupTwo, +} from "./style"; import actions from "../../actions"; import Clip from "./clip"; @@ -73,6 +80,7 @@ interface DispatchProps { } export type MenuBarProps = StateProps & DispatchProps; interface State { + mediaWidthMatches: boolean; pendingClipPercentiles: { clipPercentileMin: number; clipPercentileMax: number; @@ -109,9 +117,18 @@ class MenuBar extends React.PureComponent { this.state = { pendingClipPercentiles: INITIAL_PERCENTILES, + mediaWidthMatches: window.matchMedia("(max-width: 1275px)").matches, }; } + componentDidMount() { + const handler = (e: MediaQueryListEvent) => + this.setState({ mediaWidthMatches: e.matches }); + window + .matchMedia("(max-width: 1275px)") + .addEventListener("change", handler); + } + isClipDisabled = () => { /* return true if clip button should be disabled. @@ -215,7 +232,6 @@ class MenuBar extends React.PureComponent { }); }; - // eslint-disable-next-line @typescript-eslint/explicit-module-boundary-types --- FIXME: disabled temporarily on migrate to TS. handleCentroidChange = () => { const { dispatch, showCentroidLabels } = this.props; @@ -230,7 +246,6 @@ class MenuBar extends React.PureComponent { }); }; - // eslint-disable-next-line @typescript-eslint/explicit-module-boundary-types --- FIXME: disabled temporarily on migrate to TS. handleSubset = () => { const { dispatch } = this.props; @@ -239,7 +254,6 @@ class MenuBar extends React.PureComponent { dispatch(actions.subsetAction()); }; - // eslint-disable-next-line @typescript-eslint/explicit-module-boundary-types --- FIXME: disabled temporarily on migrate to TS. handleSubsetReset = () => { const { dispatch } = this.props; @@ -262,7 +276,7 @@ class MenuBar extends React.PureComponent { subsetResetPossible, screenCap, } = this.props; - const { pendingClipPercentiles } = this.state; + const { pendingClipPercentiles, mediaWidthMatches } = this.state; const isColoredByCategorical = !!categoricalSelection?.[colorAccessor || ""]; @@ -277,171 +291,154 @@ class MenuBar extends React.PureComponent { ]; return ( -
-
+ + -
-
- - { - dispatch({ - type: "toggle active info panel", - activeTab: "Dataset", - }); - }} - style={{ - cursor: "pointer", - }} - data-testid="drawer" - /> - - {isDownload && ( - + + + + { + dispatch({ + type: "toggle active info panel", + activeTab: "Dataset", + }); + }} style={{ cursor: "pointer", }} - loading={screenCap} - onClick={() => dispatch({ type: "graph: screencap start" })} + data-testid="drawer" /> - - )} - {isTest && ( - dispatch({ type: "test: screencap start" })} - /> - )} - - - - - - + + {isDownload && ( + + dispatch({ type: "graph: screencap start" })} + /> + + )} + {isTest && ( { - track(EVENTS.EXPLORER_MODE_LASSO_BUTTON_CLICKED); - - dispatch({ - type: "change graph interaction mode", - data: "select", - }); + icon={IconNames.TORCH} + style={{ + cursor: "pointer", }} + data-testid={GRAPH_AS_IMAGE_TEST_ID} + data-chromatic="ignore" + loading={screenCap} + onClick={() => dispatch({ type: "test: screencap start" })} /> - + )} + { - track(EVENTS.EXPLORER_MODE_PAN_ZOOM_BUTTON_CLICKED); - - dispatch({ - type: "change graph interaction mode", - data: "zoom", - }); - }} + data-testid="centroid-label-toggle" + icon="property" + onClick={this.handleCentroidChange} + active={showCentroidLabels} + intent={showCentroidLabels ? "primary" : "none"} + disabled={!isColoredByCategorical} /> - - + + + + + { + track(EVENTS.EXPLORER_MODE_LASSO_BUTTON_CLICKED); + + dispatch({ + type: "change graph interaction mode", + data: "select", + }); + }} + /> + + + { + track(EVENTS.EXPLORER_MODE_PAN_ZOOM_BUTTON_CLICKED); + + dispatch({ + type: "change graph interaction mode", + data: "zoom", + }); + }} + /> + + + + {disableDiffexp ? null : } -
-
+ + ); } } diff --git a/client/src/components/menubar/style.ts b/client/src/components/menubar/style.ts new file mode 100644 index 000000000..dae5c0a6d --- /dev/null +++ b/client/src/components/menubar/style.ts @@ -0,0 +1,50 @@ +import styled from "@emotion/styled"; +import { spacesS } from "../theme"; + +export const MenuBarWrapper = styled.div` + display: flex; + flex-direction: row; + flex-wrap: wrap; + justify-content: space-between; + width: 100%; +`; + +export const ResponsiveMenuGroupOne = styled.div` + display: flex; + flex-direction: row-reverse; + flex-wrap: wrap; + justify-content: right; + @media screen and (max-width: 1275px) { + flex-direction: column-reverse; + } +`; + +export const ResponsiveMenuGroupTwo = styled.div` + display: flex; + flex-direction: row-reverse; + flex-wrap: wrap; + justify-content: right; + @media screen and (max-width: 1350px) { + flex-direction: column-reverse; + } +`; + +export const EmbeddingWrapper = styled.div` + display: flex; + flex-direction: row; + flex-wrap: wrap; + justify-content: left; + margin-top: ${spacesS}px; +`; + +export const ControlsWrapper = styled.div` + display: flex; + flex-direction: row-reverse; + flex-wrap: wrap; + justify-content: right; + align-items: flex-start; + @media screen and (max-width: 1275px) { + flex-direction: column-reverse; + align-items: flex-end; + } +`; diff --git a/client/src/components/menubar/subset.tsx b/client/src/components/menubar/subset.tsx index ca96329e2..47a7cc39f 100644 --- a/client/src/components/menubar/subset.tsx +++ b/client/src/components/menubar/subset.tsx @@ -4,20 +4,25 @@ import { AnchorButton, ButtonGroup, Tooltip } from "@blueprintjs/core"; import styles from "./menubar.css"; import * as globals from "../../globals"; -const Subset = React.memo((props) => { +interface SubsetProps { + subsetPossible: boolean; + subsetResetPossible: boolean; + handleSubset: () => void; + handleSubsetReset: () => void; + vertical: boolean; +} + +const Subset = React.memo((props: SubsetProps) => { const { - // @ts-expect-error ts-migrate(2339) FIXME: Property 'subsetPossible' does not exist on type '... Remove this comment to see the full error message subsetPossible, - // @ts-expect-error ts-migrate(2339) FIXME: Property 'subsetResetPossible' does not exist on t... Remove this comment to see the full error message subsetResetPossible, - // @ts-expect-error ts-migrate(2339) FIXME: Property 'handleSubset' does not exist on type '{ ... Remove this comment to see the full error message handleSubset, - // @ts-expect-error ts-migrate(2339) FIXME: Property 'handleSubsetReset' does not exist on typ... Remove this comment to see the full error message handleSubsetReset, + vertical, } = props; return ( - + Date: Thu, 25 Jul 2024 19:29:52 +0000 Subject: [PATCH 02/21] chore: Updated [rdev] values.yaml image tags to sha-8d371306 --- .infra/rdev/values.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.infra/rdev/values.yaml b/.infra/rdev/values.yaml index 099ee5c0f..d9f11202d 100644 --- a/.infra/rdev/values.yaml +++ b/.infra/rdev/values.yaml @@ -2,7 +2,7 @@ stack: services: explorer: image: - tag: sha-e0592b8d + tag: sha-8d371306 replicaCount: 1 env: # env vars common to all deployment stages From ae09341138411bbaa6ed42355ec61a1ff17388cf Mon Sep 17 00:00:00 2001 From: Suzette McCanny Date: Thu, 25 Jul 2024 22:47:29 -0400 Subject: [PATCH 03/21] fix overlap and account for all buttons --- client/src/components/menubar/index.tsx | 8 +++---- client/src/components/menubar/style.ts | 28 ++++++++++++++++++++++--- 2 files changed, 29 insertions(+), 7 deletions(-) diff --git a/client/src/components/menubar/index.tsx b/client/src/components/menubar/index.tsx index 89c37daf9..c6a16539a 100644 --- a/client/src/components/menubar/index.tsx +++ b/client/src/components/menubar/index.tsx @@ -12,6 +12,7 @@ import { MenuBarWrapper, ResponsiveMenuGroupOne, ResponsiveMenuGroupTwo, + fullVerticalScreenWidth, } from "./style"; import actions from "../../actions"; import Clip from "./clip"; @@ -33,6 +34,7 @@ const INITIAL_PERCENTILES = { clipPercentileMax: 100, }; +const MEDIA_QUERY = `(max-width: ${fullVerticalScreenWidth})`; interface StateProps { subsetPossible: boolean; subsetResetPossible: boolean; @@ -117,16 +119,14 @@ class MenuBar extends React.PureComponent { this.state = { pendingClipPercentiles: INITIAL_PERCENTILES, - mediaWidthMatches: window.matchMedia("(max-width: 1275px)").matches, + mediaWidthMatches: window.matchMedia(MEDIA_QUERY).matches, }; } componentDidMount() { const handler = (e: MediaQueryListEvent) => this.setState({ mediaWidthMatches: e.matches }); - window - .matchMedia("(max-width: 1275px)") - .addEventListener("change", handler); + window.matchMedia(MEDIA_QUERY).addEventListener("change", handler); } isClipDisabled = () => { diff --git a/client/src/components/menubar/style.ts b/client/src/components/menubar/style.ts index dae5c0a6d..eef291daa 100644 --- a/client/src/components/menubar/style.ts +++ b/client/src/components/menubar/style.ts @@ -1,5 +1,18 @@ import styled from "@emotion/styled"; import { spacesS } from "../theme"; +import { getFeatureFlag } from "../../util/featureFlags/featureFlags"; +import { FEATURES } from "../../util/featureFlags/features"; + +export const fullVerticalScreenWidth = "1275px"; +const isTest = getFeatureFlag(FEATURES.TEST); +const isDownload = getFeatureFlag(FEATURES.DOWNLOAD); + +let firstBreakpoint = "1400px"; +if (isTest && isDownload) { + firstBreakpoint = "1455px"; +} else if (isTest || isDownload) { + firstBreakpoint = "1430px"; +} export const MenuBarWrapper = styled.div` display: flex; @@ -7,6 +20,7 @@ export const MenuBarWrapper = styled.div` flex-wrap: wrap; justify-content: space-between; width: 100%; + position: relative; `; export const ResponsiveMenuGroupOne = styled.div` @@ -14,7 +28,7 @@ export const ResponsiveMenuGroupOne = styled.div` flex-direction: row-reverse; flex-wrap: wrap; justify-content: right; - @media screen and (max-width: 1275px) { + @media screen and (max-width: ${fullVerticalScreenWidth}) { flex-direction: column-reverse; } `; @@ -24,8 +38,13 @@ export const ResponsiveMenuGroupTwo = styled.div` flex-direction: row-reverse; flex-wrap: wrap; justify-content: right; - @media screen and (max-width: 1350px) { + @media screen and (max-width: ${firstBreakpoint}) { flex-direction: column-reverse; + position: absolute; + top: 40px; + } + @media screen and (max-width: ${fullVerticalScreenWidth}) { + top: 172px; } `; @@ -43,8 +62,11 @@ export const ControlsWrapper = styled.div` flex-wrap: wrap; justify-content: right; align-items: flex-start; - @media screen and (max-width: 1275px) { + position: relative; + @media screen and (max-width: ${fullVerticalScreenWidth}) { flex-direction: column-reverse; align-items: flex-end; + position: absolute; + right: 0px; } `; From 6de50fd65090709144514ff23d5f793a5b7e6f9f Mon Sep 17 00:00:00 2001 From: Suzette McCanny Date: Fri, 26 Jul 2024 10:11:22 -0400 Subject: [PATCH 04/21] switch cc to fc --- client/src/components/menubar/index.tsx | 446 +++++++++++------------- 1 file changed, 204 insertions(+), 242 deletions(-) diff --git a/client/src/components/menubar/index.tsx b/client/src/components/menubar/index.tsx index c6a16539a..bfc939f7d 100644 --- a/client/src/components/menubar/index.tsx +++ b/client/src/components/menubar/index.tsx @@ -1,4 +1,4 @@ -import React from "react"; +import React, { useEffect, useState } from "react"; import { connect } from "react-redux"; import { ButtonGroup, AnchorButton, Tooltip } from "@blueprintjs/core"; import { IconNames } from "@blueprintjs/icons"; @@ -81,66 +81,64 @@ interface DispatchProps { dispatch: AppDispatch; } export type MenuBarProps = StateProps & DispatchProps; -interface State { - mediaWidthMatches: boolean; - pendingClipPercentiles: { - clipPercentileMin: number; - clipPercentileMax: number; - }; -} -class MenuBar extends React.PureComponent { - // eslint-disable-next-line @typescript-eslint/explicit-module-boundary-types, @typescript-eslint/no-explicit-any -- - FIXME: disabled temporarily on migrate to TS. - static isValidDigitKeyEvent(e: any) { - /* + +const isValidDigitKeyEvent = (e: KeyboardEvent) => { + /* Return true if this event is necessary to enter a percent number input. Return false if not. Returns true for events with keys: backspace, control, alt, meta, [0-9], or events that don't have a key. */ - if (e.key === null) return true; - if (e.ctrlKey || e.altKey || e.metaKey) return true; - - // concept borrowed from blueprint's numericInputUtils: - // keys that print a single character when pressed have a `key` name of - // length 1. every other key has a longer `key` name (e.g. "Backspace", - // "ArrowUp", "Shift"). since none of those keys can print a character - // to the field--and since they may have important native behaviors - // beyond printing a character--we don't want to disable their effects. - const isSingleCharKey = e.key.length === 1; - if (!isSingleCharKey) return true; - - const key = e.key.charCodeAt(0) - 48; /* "0" */ - return key >= 0 && key <= 9; - } - - constructor(props: MenuBarProps) { - super(props); - - this.state = { - pendingClipPercentiles: INITIAL_PERCENTILES, - mediaWidthMatches: window.matchMedia(MEDIA_QUERY).matches, - }; - } + if (e.key === null) return true; + if (e.ctrlKey || e.altKey || e.metaKey) return true; + + // concept borrowed from blueprint's numericInputUtils: + // keys that print a single character when pressed have a `key` name of + // length 1. every other key has a longer `key` name (e.g. "Backspace", + // "ArrowUp", "Shift"). since none of those keys can print a character + // to the field--and since they may have important native behaviors + // beyond printing a character--we don't want to disable their effects. + const isSingleCharKey = e.key.length === 1; + if (!isSingleCharKey) return true; + + const key = e.key.charCodeAt(0) - 48; /* "0" */ + return key >= 0 && key <= 9; +}; - componentDidMount() { - const handler = (e: MediaQueryListEvent) => - this.setState({ mediaWidthMatches: e.matches }); +const MenuBar = ({ + dispatch, + disableDiffexp, + clipPercentileMin: currentClipMin, + clipPercentileMax: currentClipMax, + graphInteractionMode, + showCentroidLabels, + categoricalSelection, + colorAccessor, + subsetPossible, + subsetResetPossible, + screenCap, +}: MenuBarProps) => { + const [pendingClipPercentiles, setPendingClipPercentiles] = + useState(INITIAL_PERCENTILES); + const [mediaWidthMatches, setMediaWidthMatches] = useState( + window.matchMedia(MEDIA_QUERY).matches + ); + + useEffect(() => { + const handler = (e: MediaQueryListEvent) => setMediaWidthMatches(e.matches); window.matchMedia(MEDIA_QUERY).addEventListener("change", handler); - } + return () => { + window.matchMedia(MEDIA_QUERY).removeEventListener("change", handler); + }; + }, []); - isClipDisabled = () => { + const isClipDisabled = () => { /* return true if clip button should be disabled. */ - const { - pendingClipPercentiles: { clipPercentileMin, clipPercentileMax }, - } = this.state; - const { - clipPercentileMin: currentClipMin, - clipPercentileMax: currentClipMax, - } = this.props; + const { clipPercentileMin, clipPercentileMax } = pendingClipPercentiles; // if you change this test, be careful with logic around // comparisons between undefined / NaN handling. @@ -153,24 +151,23 @@ class MenuBar extends React.PureComponent { }; // eslint-disable-next-line @typescript-eslint/explicit-module-boundary-types, @typescript-eslint/no-explicit-any -- - FIXME: disabled temporarily on migrate to TS. - handleClipOnKeyPress = (e: any) => { + const handleClipOnKeyPress = (e: KeyboardEvent) => { /* allow only numbers, plus other critical keys which may be required to make a number */ - if (!MenuBar.isValidDigitKeyEvent(e)) { + if (!isValidDigitKeyEvent(e)) { e.preventDefault(); } }; // eslint-disable-next-line @typescript-eslint/explicit-module-boundary-types, @typescript-eslint/no-explicit-any -- - FIXME: disabled temporarily on migrate to TS. - handleClipPercentileMinValueChange = (v: any) => { + const handleClipPercentileMinValueChange = (v: any) => { /* Ignore anything that isn't a legit number */ if (!Number.isFinite(v)) return; - const { pendingClipPercentiles } = this.state; const clipPercentileMax = pendingClipPercentiles?.clipPercentileMax; /* @@ -179,19 +176,17 @@ class MenuBar extends React.PureComponent { if (v <= 0) v = 0; if (v > 100) v = 100; const clipPercentileMin = Math.round(v); // paranoia - this.setState({ - pendingClipPercentiles: { clipPercentileMin, clipPercentileMax }, - }); + + setPendingClipPercentiles({ clipPercentileMin, clipPercentileMax }); }; // eslint-disable-next-line @typescript-eslint/explicit-module-boundary-types, @typescript-eslint/no-explicit-any -- - FIXME: disabled temporarily on migrate to TS. - handleClipPercentileMaxValueChange = (v: any) => { + const handleClipPercentileMaxValueChange = (v: any) => { /* Ignore anything that isn't a legit number */ if (!Number.isFinite(v)) return; - const { pendingClipPercentiles } = this.state; const clipPercentileMin = pendingClipPercentiles?.clipPercentileMin; /* @@ -201,14 +196,10 @@ class MenuBar extends React.PureComponent { if (v > 100) v = 100; const clipPercentileMax = Math.round(v); // paranoia - this.setState({ - pendingClipPercentiles: { clipPercentileMin, clipPercentileMax }, - }); + setPendingClipPercentiles({ clipPercentileMin, clipPercentileMax }); }; - handleClipCommit = () => { - const { dispatch } = this.props; - const { pendingClipPercentiles } = this.state; + const handleClipCommit = () => { const { clipPercentileMin, clipPercentileMax } = pendingClipPercentiles; const min = clipPercentileMin / 100; const max = clipPercentileMax / 100; @@ -218,23 +209,19 @@ class MenuBar extends React.PureComponent { dispatch(actions.clipAction(min, max)); }; - handleClipOpening = () => { - const { clipPercentileMin, clipPercentileMax } = this.props; + const handleClipOpening = () => { track(EVENTS.EXPLORER_CLIP_CLICKED); - this.setState({ - pendingClipPercentiles: { clipPercentileMin, clipPercentileMax }, + setPendingClipPercentiles({ + clipPercentileMin: currentClipMin, + clipPercentileMax: currentClipMax, }); }; - handleClipClosing = () => { - this.setState({ - pendingClipPercentiles: INITIAL_PERCENTILES, - }); + const handleClipClosing = () => { + setPendingClipPercentiles(INITIAL_PERCENTILES); }; - handleCentroidChange = () => { - const { dispatch, showCentroidLabels } = this.props; - + const handleCentroidChange = () => { if (!showCentroidLabels) { // only track when turning on track(EVENTS.EXPLORER_SHOW_LABELS); @@ -246,201 +233,176 @@ class MenuBar extends React.PureComponent { }); }; - handleSubset = () => { - const { dispatch } = this.props; - + const handleSubset = () => { track(EVENTS.EXPLORER_SUBSET_BUTTON_CLICKED); dispatch(actions.subsetAction()); }; - handleSubsetReset = () => { - const { dispatch } = this.props; - + const handleSubsetReset = () => { track(EVENTS.EXPLORER_RESET_SUBSET_BUTTON_CLICKED); dispatch(actions.resetSubsetAction()); }; - render() { - const { - dispatch, - disableDiffexp, - clipPercentileMin, - clipPercentileMax, - graphInteractionMode, - showCentroidLabels, - categoricalSelection, - colorAccessor, - subsetPossible, - subsetResetPossible, - screenCap, - } = this.props; - const { pendingClipPercentiles, mediaWidthMatches } = this.state; - - const isColoredByCategorical = - !!categoricalSelection?.[colorAccessor || ""]; - - const isTest = getFeatureFlag(FEATURES.TEST); - const isDownload = getFeatureFlag(FEATURES.DOWNLOAD); - - // constants used to create selection tool button - const [selectionTooltip, selectionButtonIcon] = [ - "select", - "polygon-filter", - ]; - - return ( - - - - - - - - { - dispatch({ - type: "toggle active info panel", - activeTab: "Dataset", - }); - }} - style={{ - cursor: "pointer", - }} - data-testid="drawer" - /> - - {isDownload && ( - - dispatch({ type: "graph: screencap start" })} - /> - - )} - {isTest && ( + const isColoredByCategorical = !!categoricalSelection?.[colorAccessor || ""]; + + const isTest = getFeatureFlag(FEATURES.TEST); + const isDownload = getFeatureFlag(FEATURES.DOWNLOAD); + + // constants used to create selection tool button + const [selectionTooltip, selectionButtonIcon] = ["select", "polygon-filter"]; + console.log("MenuBar Test!"); + return ( + + + + + + + + { + dispatch({ + type: "toggle active info panel", + activeTab: "Dataset", + }); + }} + style={{ + cursor: "pointer", + }} + data-testid="drawer" + /> + + {isDownload && ( + dispatch({ type: "test: screencap start" })} + onClick={() => dispatch({ type: "graph: screencap start" })} /> - )} - + )} + {isTest && ( + dispatch({ type: "test: screencap start" })} + /> + )} + + + + + + + { + track(EVENTS.EXPLORER_MODE_LASSO_BUTTON_CLICKED); + + dispatch({ + type: "change graph interaction mode", + data: "select", + }); + }} /> - - - - - { - track(EVENTS.EXPLORER_MODE_LASSO_BUTTON_CLICKED); - - dispatch({ - type: "change graph interaction mode", - data: "select", - }); - }} - /> - - - { - track(EVENTS.EXPLORER_MODE_PAN_ZOOM_BUTTON_CLICKED); - - dispatch({ - type: "change graph interaction mode", - data: "zoom", - }); - }} - /> - - - - - {disableDiffexp ? null : } - - - ); - } -} + { + track(EVENTS.EXPLORER_MODE_PAN_ZOOM_BUTTON_CLICKED); + + dispatch({ + type: "change graph interaction mode", + data: "zoom", + }); + }} + /> + + + + + {disableDiffexp ? null : } + + + ); +}; export default connect(mapStateToProps)(MenuBar); From 847a0ca90e3118924b0e499c0e791ae896947095 Mon Sep 17 00:00:00 2001 From: rainandbare Date: Fri, 26 Jul 2024 14:20:29 +0000 Subject: [PATCH 05/21] chore: Updated [rdev] values.yaml image tags to sha-6de50fd6 --- .infra/rdev/values.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.infra/rdev/values.yaml b/.infra/rdev/values.yaml index d9f11202d..b8a871100 100644 --- a/.infra/rdev/values.yaml +++ b/.infra/rdev/values.yaml @@ -2,7 +2,7 @@ stack: services: explorer: image: - tag: sha-8d371306 + tag: sha-6de50fd6 replicaCount: 1 env: # env vars common to all deployment stages From 16571b44da9a1e3eeb7879bf40c06f76fc558449 Mon Sep 17 00:00:00 2001 From: Suzette McCanny Date: Fri, 26 Jul 2024 10:36:39 -0400 Subject: [PATCH 06/21] remove console.log --- client/src/components/menubar/index.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/client/src/components/menubar/index.tsx b/client/src/components/menubar/index.tsx index bfc939f7d..ab6643a9e 100644 --- a/client/src/components/menubar/index.tsx +++ b/client/src/components/menubar/index.tsx @@ -252,7 +252,7 @@ const MenuBar = ({ // constants used to create selection tool button const [selectionTooltip, selectionButtonIcon] = ["select", "polygon-filter"]; - console.log("MenuBar Test!"); + return ( From 7aaedb31d1edbc3e17e3580b0fe56d7e4cced508 Mon Sep 17 00:00:00 2001 From: rainandbare Date: Fri, 26 Jul 2024 14:48:55 +0000 Subject: [PATCH 07/21] chore: Updated [rdev] values.yaml image tags to sha-59485d07 --- .infra/rdev/values.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.infra/rdev/values.yaml b/.infra/rdev/values.yaml index b8a871100..a1877b307 100644 --- a/.infra/rdev/values.yaml +++ b/.infra/rdev/values.yaml @@ -2,7 +2,7 @@ stack: services: explorer: image: - tag: sha-6de50fd6 + tag: sha-59485d07 replicaCount: 1 env: # env vars common to all deployment stages From 8f2e246236da76e1893b937fdf86fd4b486e2af3 Mon Sep 17 00:00:00 2001 From: Suzette McCanny Date: Fri, 26 Jul 2024 11:17:36 -0400 Subject: [PATCH 08/21] fix dead zone 2 --- client/src/components/menubar/style.ts | 2 ++ 1 file changed, 2 insertions(+) diff --git a/client/src/components/menubar/style.ts b/client/src/components/menubar/style.ts index eef291daa..6ec5bf523 100644 --- a/client/src/components/menubar/style.ts +++ b/client/src/components/menubar/style.ts @@ -30,6 +30,8 @@ export const ResponsiveMenuGroupOne = styled.div` justify-content: right; @media screen and (max-width: ${fullVerticalScreenWidth}) { flex-direction: column-reverse; + position: absolute; + top: 37px; } `; From cbed2336dbf68ce17236e0cdcc2bb1b122cc9230 Mon Sep 17 00:00:00 2001 From: rainandbare Date: Fri, 26 Jul 2024 15:33:14 +0000 Subject: [PATCH 09/21] chore: Updated [rdev] values.yaml image tags to sha-8f2e2462 --- .infra/rdev/values.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.infra/rdev/values.yaml b/.infra/rdev/values.yaml index a1877b307..fbf204987 100644 --- a/.infra/rdev/values.yaml +++ b/.infra/rdev/values.yaml @@ -2,7 +2,7 @@ stack: services: explorer: image: - tag: sha-59485d07 + tag: sha-8f2e2462 replicaCount: 1 env: # env vars common to all deployment stages From a33a90f53daaa58148de71ae756cb178c731ea75 Mon Sep 17 00:00:00 2001 From: Suzette McCanny Date: Fri, 26 Jul 2024 14:12:58 -0400 Subject: [PATCH 10/21] fix e2e tests --- client/__tests__/e2e/data.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/client/__tests__/e2e/data.ts b/client/__tests__/e2e/data.ts index 3b9a9d749..0f4a58e19 100644 --- a/client/__tests__/e2e/data.ts +++ b/client/__tests__/e2e/data.ts @@ -100,7 +100,7 @@ export const datasets = { }, lasso: { "coordinates-as-percent": { x1: 0.25, y1: 0.1, x2: 0.75, y2: 0.65 }, - count: "357", + count: "332", }, }, scatter: { @@ -273,7 +273,7 @@ export const datasets = { }, lasso: { "coordinates-as-percent": { x1: 0.25, y1: 0.1, x2: 0.75, y2: 0.65 }, - count: "44", + count: "12", }, }, scatter: { From 65f4a1082ea53689cb328053d083e920dc9691e9 Mon Sep 17 00:00:00 2001 From: rainandbare Date: Fri, 26 Jul 2024 18:25:27 +0000 Subject: [PATCH 11/21] chore: Updated [rdev] values.yaml image tags to sha-a33a90f5 --- .infra/rdev/values.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.infra/rdev/values.yaml b/.infra/rdev/values.yaml index fbf204987..e8f836536 100644 --- a/.infra/rdev/values.yaml +++ b/.infra/rdev/values.yaml @@ -2,7 +2,7 @@ stack: services: explorer: image: - tag: sha-8f2e2462 + tag: sha-a33a90f5 replicaCount: 1 env: # env vars common to all deployment stages From c9203776b1921f72723401059a3b0b897de81a6a Mon Sep 17 00:00:00 2001 From: Suzette McCanny Date: Fri, 26 Jul 2024 15:09:44 -0400 Subject: [PATCH 12/21] check menu width rather than viewportwidth --- client/src/components/menubar/index.tsx | 293 ++++++++++++------------ client/src/components/menubar/style.ts | 17 +- 2 files changed, 157 insertions(+), 153 deletions(-) diff --git a/client/src/components/menubar/index.tsx b/client/src/components/menubar/index.tsx index ab6643a9e..1aed73690 100644 --- a/client/src/components/menubar/index.tsx +++ b/client/src/components/menubar/index.tsx @@ -1,6 +1,11 @@ -import React, { useEffect, useState } from "react"; +import React, { useState } from "react"; import { connect } from "react-redux"; -import { ButtonGroup, AnchorButton, Tooltip } from "@blueprintjs/core"; +import { + ButtonGroup, + AnchorButton, + Tooltip, + ResizeSensor, +} from "@blueprintjs/core"; import { IconNames } from "@blueprintjs/icons"; import * as globals from "../../globals"; @@ -33,8 +38,6 @@ const INITIAL_PERCENTILES = { clipPercentileMin: 0, clipPercentileMax: 100, }; - -const MEDIA_QUERY = `(max-width: ${fullVerticalScreenWidth})`; interface StateProps { subsetPossible: boolean; subsetResetPossible: boolean; @@ -121,17 +124,7 @@ const MenuBar = ({ }: MenuBarProps) => { const [pendingClipPercentiles, setPendingClipPercentiles] = useState(INITIAL_PERCENTILES); - const [mediaWidthMatches, setMediaWidthMatches] = useState( - window.matchMedia(MEDIA_QUERY).matches - ); - - useEffect(() => { - const handler = (e: MediaQueryListEvent) => setMediaWidthMatches(e.matches); - window.matchMedia(MEDIA_QUERY).addEventListener("change", handler); - return () => { - window.matchMedia(MEDIA_QUERY).removeEventListener("change", handler); - }; - }, []); + const [menuBarWidthMatches, setMenuBarWidthMatches] = useState(false); const isClipDisabled = () => { /* @@ -245,6 +238,14 @@ const MenuBar = ({ dispatch(actions.resetSubsetAction()); }; + const onResize = (e: ResizeObserverEntry[]) => { + if (e[0].contentRect.width <= fullVerticalScreenWidth) { + setMenuBarWidthMatches(true); + } else { + setMenuBarWidthMatches(false); + } + }; + const isColoredByCategorical = !!categoricalSelection?.[colorAccessor || ""]; const isTest = getFeatureFlag(FEATURES.TEST); @@ -254,154 +255,156 @@ const MenuBar = ({ const [selectionTooltip, selectionButtonIcon] = ["select", "polygon-filter"]; return ( - - - - - - - - { - dispatch({ - type: "toggle active info panel", - activeTab: "Dataset", - }); - }} - style={{ - cursor: "pointer", - }} - data-testid="drawer" - /> - - {isDownload && ( - + + + + + + + + { + dispatch({ + type: "toggle active info panel", + activeTab: "Dataset", + }); + }} style={{ cursor: "pointer", }} - loading={screenCap} - onClick={() => dispatch({ type: "graph: screencap start" })} + data-testid="drawer" /> - - )} - {isTest && ( - dispatch({ type: "test: screencap start" })} - /> - )} - - - - - - - - + + {isDownload && ( + + dispatch({ type: "graph: screencap start" })} + /> + + )} + {isTest && ( { - track(EVENTS.EXPLORER_MODE_LASSO_BUTTON_CLICKED); - - dispatch({ - type: "change graph interaction mode", - data: "select", - }); + icon={IconNames.TORCH} + style={{ + cursor: "pointer", }} + data-testid={GRAPH_AS_IMAGE_TEST_ID} + data-chromatic="ignore" + loading={screenCap} + onClick={() => dispatch({ type: "test: screencap start" })} /> - + )} + { - track(EVENTS.EXPLORER_MODE_PAN_ZOOM_BUTTON_CLICKED); - - dispatch({ - type: "change graph interaction mode", - data: "zoom", - }); - }} + data-testid="centroid-label-toggle" + icon="property" + onClick={handleCentroidChange} + active={showCentroidLabels} + intent={showCentroidLabels ? "primary" : "none"} + disabled={!isColoredByCategorical} /> - - - - {disableDiffexp ? null : } - - + + + + + { + track(EVENTS.EXPLORER_MODE_LASSO_BUTTON_CLICKED); + + dispatch({ + type: "change graph interaction mode", + data: "select", + }); + }} + /> + + + { + track(EVENTS.EXPLORER_MODE_PAN_ZOOM_BUTTON_CLICKED); + + dispatch({ + type: "change graph interaction mode", + data: "zoom", + }); + }} + /> + + + + + {disableDiffexp ? null : } + + + ); }; diff --git a/client/src/components/menubar/style.ts b/client/src/components/menubar/style.ts index 6ec5bf523..711bb0ee0 100644 --- a/client/src/components/menubar/style.ts +++ b/client/src/components/menubar/style.ts @@ -3,15 +3,15 @@ import { spacesS } from "../theme"; import { getFeatureFlag } from "../../util/featureFlags/featureFlags"; import { FEATURES } from "../../util/featureFlags/features"; -export const fullVerticalScreenWidth = "1275px"; +export const fullVerticalScreenWidth = 500; const isTest = getFeatureFlag(FEATURES.TEST); const isDownload = getFeatureFlag(FEATURES.DOWNLOAD); -let firstBreakpoint = "1400px"; +let firstBreakpoint = "655px"; if (isTest && isDownload) { - firstBreakpoint = "1455px"; + firstBreakpoint = "705px"; } else if (isTest || isDownload) { - firstBreakpoint = "1430px"; + firstBreakpoint = "685px"; } export const MenuBarWrapper = styled.div` @@ -21,6 +21,7 @@ export const MenuBarWrapper = styled.div` justify-content: space-between; width: 100%; position: relative; + container: menu-bar / inline-size; `; export const ResponsiveMenuGroupOne = styled.div` @@ -28,7 +29,7 @@ export const ResponsiveMenuGroupOne = styled.div` flex-direction: row-reverse; flex-wrap: wrap; justify-content: right; - @media screen and (max-width: ${fullVerticalScreenWidth}) { + @container menu-bar (max-width: ${fullVerticalScreenWidth}px) { flex-direction: column-reverse; position: absolute; top: 37px; @@ -40,12 +41,12 @@ export const ResponsiveMenuGroupTwo = styled.div` flex-direction: row-reverse; flex-wrap: wrap; justify-content: right; - @media screen and (max-width: ${firstBreakpoint}) { + @container menu-bar (max-width: ${firstBreakpoint}) { flex-direction: column-reverse; position: absolute; top: 40px; } - @media screen and (max-width: ${fullVerticalScreenWidth}) { + @container menu-bar (max-width: ${fullVerticalScreenWidth}px) { top: 172px; } `; @@ -65,7 +66,7 @@ export const ControlsWrapper = styled.div` justify-content: right; align-items: flex-start; position: relative; - @media screen and (max-width: ${fullVerticalScreenWidth}) { + @container menu-bar (max-width: ${fullVerticalScreenWidth}px) { flex-direction: column-reverse; align-items: flex-end; position: absolute; From dde13f34a2de1733dd9f1ba33267653a2174e977 Mon Sep 17 00:00:00 2001 From: rainandbare Date: Fri, 26 Jul 2024 19:18:34 +0000 Subject: [PATCH 13/21] chore: Updated [rdev] values.yaml image tags to sha-c9203776 --- .infra/rdev/values.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.infra/rdev/values.yaml b/.infra/rdev/values.yaml index e8f836536..0b7db04d7 100644 --- a/.infra/rdev/values.yaml +++ b/.infra/rdev/values.yaml @@ -2,7 +2,7 @@ stack: services: explorer: image: - tag: sha-a33a90f5 + tag: sha-c9203776 replicaCount: 1 env: # env vars common to all deployment stages From 2c5fd819cf9e83501eb052ce4c16074396d2962e Mon Sep 17 00:00:00 2001 From: Suzette McCanny Date: Mon, 29 Jul 2024 14:43:50 -0400 Subject: [PATCH 14/21] change variable names --- client/src/components/menubar/index.tsx | 4 ++-- client/src/components/menubar/style.ts | 16 ++++++++-------- 2 files changed, 10 insertions(+), 10 deletions(-) diff --git a/client/src/components/menubar/index.tsx b/client/src/components/menubar/index.tsx index 1aed73690..6e701b710 100644 --- a/client/src/components/menubar/index.tsx +++ b/client/src/components/menubar/index.tsx @@ -17,7 +17,7 @@ import { MenuBarWrapper, ResponsiveMenuGroupOne, ResponsiveMenuGroupTwo, - fullVerticalScreenWidth, + MAX_VERTICAL_THRESHOLD_WIDTH_PX, } from "./style"; import actions from "../../actions"; import Clip from "./clip"; @@ -239,7 +239,7 @@ const MenuBar = ({ }; const onResize = (e: ResizeObserverEntry[]) => { - if (e[0].contentRect.width <= fullVerticalScreenWidth) { + if (e[0].contentRect.width <= MAX_VERTICAL_THRESHOLD_WIDTH_PX) { setMenuBarWidthMatches(true); } else { setMenuBarWidthMatches(false); diff --git a/client/src/components/menubar/style.ts b/client/src/components/menubar/style.ts index 711bb0ee0..4aa5a2184 100644 --- a/client/src/components/menubar/style.ts +++ b/client/src/components/menubar/style.ts @@ -3,15 +3,15 @@ import { spacesS } from "../theme"; import { getFeatureFlag } from "../../util/featureFlags/featureFlags"; import { FEATURES } from "../../util/featureFlags/features"; -export const fullVerticalScreenWidth = 500; +export const MAX_VERTICAL_THRESHOLD_WIDTH_PX = 500; const isTest = getFeatureFlag(FEATURES.TEST); const isDownload = getFeatureFlag(FEATURES.DOWNLOAD); -let firstBreakpoint = "655px"; +let FIRST_VERTICAL_THRESHOLD_WIDTH_PX = 655; if (isTest && isDownload) { - firstBreakpoint = "705px"; + FIRST_VERTICAL_THRESHOLD_WIDTH_PX = 705; } else if (isTest || isDownload) { - firstBreakpoint = "685px"; + FIRST_VERTICAL_THRESHOLD_WIDTH_PX = 685; } export const MenuBarWrapper = styled.div` @@ -29,7 +29,7 @@ export const ResponsiveMenuGroupOne = styled.div` flex-direction: row-reverse; flex-wrap: wrap; justify-content: right; - @container menu-bar (max-width: ${fullVerticalScreenWidth}px) { + @container menu-bar (max-width: ${MAX_VERTICAL_THRESHOLD_WIDTH_PX}px) { flex-direction: column-reverse; position: absolute; top: 37px; @@ -41,12 +41,12 @@ export const ResponsiveMenuGroupTwo = styled.div` flex-direction: row-reverse; flex-wrap: wrap; justify-content: right; - @container menu-bar (max-width: ${firstBreakpoint}) { + @container menu-bar (max-width: ${FIRST_VERTICAL_THRESHOLD_WIDTH_PX}px) { flex-direction: column-reverse; position: absolute; top: 40px; } - @container menu-bar (max-width: ${fullVerticalScreenWidth}px) { + @container menu-bar (max-width: ${MAX_VERTICAL_THRESHOLD_WIDTH_PX}px) { top: 172px; } `; @@ -66,7 +66,7 @@ export const ControlsWrapper = styled.div` justify-content: right; align-items: flex-start; position: relative; - @container menu-bar (max-width: ${fullVerticalScreenWidth}px) { + @container menu-bar (max-width: ${MAX_VERTICAL_THRESHOLD_WIDTH_PX}px) { flex-direction: column-reverse; align-items: flex-end; position: absolute; From 1877f8c605d682cb05f768bcf36b1dd958fc0c77 Mon Sep 17 00:00:00 2001 From: rainandbare Date: Mon, 29 Jul 2024 19:00:02 +0000 Subject: [PATCH 15/21] chore: Updated [rdev] values.yaml image tags to sha-9acb1f01 --- .infra/rdev/values.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.infra/rdev/values.yaml b/.infra/rdev/values.yaml index 0b7db04d7..21728bdaa 100644 --- a/.infra/rdev/values.yaml +++ b/.infra/rdev/values.yaml @@ -2,7 +2,7 @@ stack: services: explorer: image: - tag: sha-c9203776 + tag: sha-9acb1f01 replicaCount: 1 env: # env vars common to all deployment stages From 31a15e1cf1aa21bcb20ae7b6913654832496bf0a Mon Sep 17 00:00:00 2001 From: Suzette McCanny Date: Mon, 29 Jul 2024 15:01:24 -0400 Subject: [PATCH 16/21] change boolean name --- client/src/components/menubar/index.tsx | 13 +++++-------- client/src/components/menubar/subset.tsx | 6 +++--- 2 files changed, 8 insertions(+), 11 deletions(-) diff --git a/client/src/components/menubar/index.tsx b/client/src/components/menubar/index.tsx index 6e701b710..8183a8932 100644 --- a/client/src/components/menubar/index.tsx +++ b/client/src/components/menubar/index.tsx @@ -124,7 +124,7 @@ const MenuBar = ({ }: MenuBarProps) => { const [pendingClipPercentiles, setPendingClipPercentiles] = useState(INITIAL_PERCENTILES); - const [menuBarWidthMatches, setMenuBarWidthMatches] = useState(false); + const [isVertical, setIsVertical] = useState(false); const isClipDisabled = () => { /* @@ -240,9 +240,9 @@ const MenuBar = ({ const onResize = (e: ResizeObserverEntry[]) => { if (e[0].contentRect.width <= MAX_VERTICAL_THRESHOLD_WIDTH_PX) { - setMenuBarWidthMatches(true); + setIsVertical(true); } else { - setMenuBarWidthMatches(false); + setIsVertical(false); } }; @@ -347,10 +347,7 @@ const MenuBar = ({ - + {disableDiffexp ? null : } diff --git a/client/src/components/menubar/subset.tsx b/client/src/components/menubar/subset.tsx index 47a7cc39f..5fa87af17 100644 --- a/client/src/components/menubar/subset.tsx +++ b/client/src/components/menubar/subset.tsx @@ -9,7 +9,7 @@ interface SubsetProps { subsetResetPossible: boolean; handleSubset: () => void; handleSubsetReset: () => void; - vertical: boolean; + isVertical: boolean; } const Subset = React.memo((props: SubsetProps) => { @@ -18,11 +18,11 @@ const Subset = React.memo((props: SubsetProps) => { subsetResetPossible, handleSubset, handleSubsetReset, - vertical, + isVertical, } = props; return ( - + Date: Mon, 29 Jul 2024 19:10:51 +0000 Subject: [PATCH 17/21] chore: Updated [rdev] values.yaml image tags to sha-cfd373ef --- .infra/rdev/values.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.infra/rdev/values.yaml b/.infra/rdev/values.yaml index 21728bdaa..5d1a56295 100644 --- a/.infra/rdev/values.yaml +++ b/.infra/rdev/values.yaml @@ -2,7 +2,7 @@ stack: services: explorer: image: - tag: sha-9acb1f01 + tag: sha-cfd373ef replicaCount: 1 env: # env vars common to all deployment stages From 5c764d529b91792505e0013458e97a3e9fffeee1 Mon Sep 17 00:00:00 2001 From: rainandbare Date: Tue, 30 Jul 2024 14:17:08 +0000 Subject: [PATCH 18/21] chore: Updated [rdev] values.yaml image tags to sha-b2901095 --- .infra/rdev/values.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.infra/rdev/values.yaml b/.infra/rdev/values.yaml index 5d1a56295..ff42558a5 100644 --- a/.infra/rdev/values.yaml +++ b/.infra/rdev/values.yaml @@ -2,7 +2,7 @@ stack: services: explorer: image: - tag: sha-cfd373ef + tag: sha-b2901095 replicaCount: 1 env: # env vars common to all deployment stages From 6c64e98cf57add3e561f34194b11b64df35810ca Mon Sep 17 00:00:00 2001 From: Suzette McCanny Date: Tue, 30 Jul 2024 13:42:42 -0400 Subject: [PATCH 19/21] fix e2e test failure (dialoge was covering test icon) --- client/__tests__/e2e/cellxgeneActions.ts | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/client/__tests__/e2e/cellxgeneActions.ts b/client/__tests__/e2e/cellxgeneActions.ts index cc96feb61..7c4331353 100644 --- a/client/__tests__/e2e/cellxgeneActions.ts +++ b/client/__tests__/e2e/cellxgeneActions.ts @@ -337,6 +337,8 @@ export async function clip(min = "0", max = "100", page: Page): Promise { await clearInputAndTypeInto("clip-min-input", min, page); await clearInputAndTypeInto("clip-max-input", max, page); await page.getByTestId("clip-commit").click(); + // close clip dialog + await page.getByTestId("visualization-settings").click(); } /** @@ -799,7 +801,7 @@ export async function snapshotTestGraph(page: Page, testInfo: TestInfo) { await tryUntil( async () => { await page.getByTestId(GRAPH_AS_IMAGE_TEST_ID).click({ force: true }); - + await page .getByTestId(imageID) /** From 8a03b930b2a00a42f8049feb13e0b065f56eddb3 Mon Sep 17 00:00:00 2001 From: Suzette McCanny Date: Tue, 30 Jul 2024 13:45:44 -0400 Subject: [PATCH 20/21] spacing --- client/__tests__/e2e/cellxgeneActions.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/client/__tests__/e2e/cellxgeneActions.ts b/client/__tests__/e2e/cellxgeneActions.ts index 7c4331353..ec9a3eb59 100644 --- a/client/__tests__/e2e/cellxgeneActions.ts +++ b/client/__tests__/e2e/cellxgeneActions.ts @@ -801,7 +801,7 @@ export async function snapshotTestGraph(page: Page, testInfo: TestInfo) { await tryUntil( async () => { await page.getByTestId(GRAPH_AS_IMAGE_TEST_ID).click({ force: true }); - + await page .getByTestId(imageID) /** From ccd71dce561798004f26a1d7898aacb23f9a5fec Mon Sep 17 00:00:00 2001 From: rainandbare Date: Tue, 30 Jul 2024 17:57:46 +0000 Subject: [PATCH 21/21] chore: Updated [rdev] values.yaml image tags to sha-8a03b930 --- .infra/rdev/values.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.infra/rdev/values.yaml b/.infra/rdev/values.yaml index ff42558a5..89887401a 100644 --- a/.infra/rdev/values.yaml +++ b/.infra/rdev/values.yaml @@ -2,7 +2,7 @@ stack: services: explorer: image: - tag: sha-b2901095 + tag: sha-8a03b930 replicaCount: 1 env: # env vars common to all deployment stages