Skip to content
Snippets Groups Projects
Unverified Commit f6a698d4 authored by Nick Fitzpatrick's avatar Nick Fitzpatrick Committed by GitHub
Browse files

Updating favicon and changing toaster/notification behavior (#21670)

* Updating favicon and changing toaster/notification behavior
parent 35750230
No related branches found
No related tags found
No related merge requests found
...@@ -40,6 +40,7 @@ import { ...@@ -40,6 +40,7 @@ import {
getFavicon, getFavicon,
getDocumentTitle, getDocumentTitle,
getIsRunning, getIsRunning,
getIsLoadingComplete,
} from "../selectors"; } from "../selectors";
import { getDatabases, getMetadata } from "metabase/selectors/metadata"; import { getDatabases, getMetadata } from "metabase/selectors/metadata";
import { import {
...@@ -81,6 +82,7 @@ const mapStateToProps = (state, props) => { ...@@ -81,6 +82,7 @@ const mapStateToProps = (state, props) => {
pageFavicon: getFavicon(state), pageFavicon: getFavicon(state),
documentTitle: getDocumentTitle(state), documentTitle: getDocumentTitle(state),
isRunning: getIsRunning(state), isRunning: getIsRunning(state),
isLoadingComplete: getIsLoadingComplete(state),
}; };
}; };
...@@ -96,16 +98,17 @@ const mapDispatchToProps = { ...@@ -96,16 +98,17 @@ const mapDispatchToProps = {
const DashboardApp = props => { const DashboardApp = props => {
const options = parseHashOptions(window.location.hash); const options = parseHashOptions(window.location.hash);
const { isRunning, dashboard } = props; const { isRunning, isLoadingComplete, dashboard } = props;
const [editingOnLoad] = useState(options.edit); const [editingOnLoad] = useState(options.edit);
const [addCardOnLoad] = useState(options.add && parseInt(options.add)); const [addCardOnLoad] = useState(options.add && parseInt(options.add));
const [shouldSendNotification, setShouldSendNotification] = useState(false);
const [isShowingToaster, setIsShowingToaster] = useState(false); const [isShowingToaster, setIsShowingToaster] = useState(false);
const onTimeout = useCallback(() => { const onTimeout = useCallback(() => {
setIsShowingToaster(true); if (Notification.permission === "default") {
setIsShowingToaster(true);
}
}, []); }, []);
useLoadingTimer(isRunning, { useLoadingTimer(isRunning, {
...@@ -118,26 +121,20 @@ const DashboardApp = props => { ...@@ -118,26 +121,20 @@ const DashboardApp = props => {
useOnUnmount(props.reset); useOnUnmount(props.reset);
useEffect(() => { useEffect(() => {
if (!isRunning) { if (isLoadingComplete) {
setIsShowingToaster(false); setIsShowingToaster(false);
} if (Notification.permission === "granted" && document.hidden) {
if (!isRunning && shouldSendNotification) {
if (document.hidden) {
showNotification( showNotification(
t`All Set! ${dashboard.name} is ready.`, t`All Set! ${dashboard?.name} is ready.`,
t`All questions loaded`, t`All questions loaded`,
); );
} }
setShouldSendNotification(false);
} }
}, [isRunning, shouldSendNotification, showNotification, dashboard?.name]); }, [isLoadingComplete, showNotification, dashboard?.name]);
const onConfirmToast = useCallback(async () => { const onConfirmToast = useCallback(async () => {
const result = await requestPermission(); await requestPermission();
if (result === "granted") { setIsShowingToaster(false);
setIsShowingToaster(false);
setShouldSendNotification(true);
}
}, [requestPermission]); }, [requestPermission]);
const onDismissToast = useCallback(() => { const onDismissToast = useCallback(() => {
......
...@@ -298,7 +298,7 @@ const loadingDashCards = handleActions( ...@@ -298,7 +298,7 @@ const loadingDashCards = handleActions(
[INITIALIZE]: { [INITIALIZE]: {
next: state => ({ next: state => ({
...state, ...state,
isLoadingComplete: false, loadingStatus: "idle",
}), }),
}, },
[FETCH_DASHBOARD]: { [FETCH_DASHBOARD]: {
...@@ -307,13 +307,14 @@ const loadingDashCards = handleActions( ...@@ -307,13 +307,14 @@ const loadingDashCards = handleActions(
dashcardIds: Object.values(payload.entities.dashcard || {}) dashcardIds: Object.values(payload.entities.dashcard || {})
.filter(dc => !isVirtualDashCard(dc)) .filter(dc => !isVirtualDashCard(dc))
.map(dc => dc.id), .map(dc => dc.id),
isLoadingComplete: false, loadingStatus: "idle",
}), }),
}, },
[FETCH_DASHBOARD_CARD_DATA]: { [FETCH_DASHBOARD_CARD_DATA]: {
next: state => ({ next: state => ({
...state, ...state,
loadingIds: state.dashcardIds, loadingIds: state.dashcardIds,
loadingStatus: "running",
startTime: startTime:
state.dashcardIds.length > 0 && state.dashcardIds.length > 0 &&
// check that performance is defined just in case // check that performance is defined just in case
...@@ -329,7 +330,7 @@ const loadingDashCards = handleActions( ...@@ -329,7 +330,7 @@ const loadingDashCards = handleActions(
...state, ...state,
loadingIds, loadingIds,
...(loadingIds.length === 0 ...(loadingIds.length === 0
? { startTime: null, isLoadingComplete: true } ? { startTime: null, loadingStatus: "complete" }
: {}), : {}),
}; };
}, },
...@@ -340,16 +341,14 @@ const loadingDashCards = handleActions( ...@@ -340,16 +341,14 @@ const loadingDashCards = handleActions(
return { return {
...state, ...state,
loadingIds, loadingIds,
...(loadingIds.length === 0 ...(loadingIds.length === 0 ? { startTime: null } : {}),
? { startTime: null, isLoadingComplete: true }
: {}),
}; };
}, },
}, },
[RESET]: { [RESET]: {
next: state => ({ next: state => ({
...state, ...state,
isLoadingComplete: false, loadingStatus: "idle",
}), }),
}, },
}, },
...@@ -357,7 +356,7 @@ const loadingDashCards = handleActions( ...@@ -357,7 +356,7 @@ const loadingDashCards = handleActions(
dashcardIds: [], dashcardIds: [],
loadingIds: [], loadingIds: [],
startTime: null, startTime: null,
isLoadingComplete: false, loadingStatus: "idle",
}, },
); );
......
...@@ -26,7 +26,7 @@ describe("dashboard reducers", () => { ...@@ -26,7 +26,7 @@ describe("dashboard reducers", () => {
dashcardIds: [], dashcardIds: [],
loadingIds: [], loadingIds: [],
startTime: null, startTime: null,
isLoadingComplete: false, loadingStatus: "idle",
}, },
parameterValues: {}, parameterValues: {},
parameterValuesSearchCache: {}, parameterValuesSearchCache: {},
......
...@@ -34,7 +34,9 @@ export const getFavicon = state => ...@@ -34,7 +34,9 @@ export const getFavicon = state =>
: null; : null;
export const getIsRunning = state => export const getIsRunning = state =>
state.dashboard.loadingDashCards.loadingIds > 0; state.dashboard.loadingDashCards.loadingStatus === "running";
export const getIsLoadingComplete = state =>
state.dashboard.loadingDashCards.loadingStatus === "complete";
export const getLoadingStartTime = state => export const getLoadingStartTime = state =>
state.dashboard.loadingDashCards.startTime; state.dashboard.loadingDashCards.startTime;
......
...@@ -86,6 +86,7 @@ import { ...@@ -86,6 +86,7 @@ import {
getDocumentTitle, getDocumentTitle,
getPageFavicon, getPageFavicon,
getIsTimeseries, getIsTimeseries,
getIsLoadingComplete,
} from "../selectors"; } from "../selectors";
import * as actions from "../actions"; import * as actions from "../actions";
...@@ -186,6 +187,7 @@ const mapStateToProps = (state, props) => { ...@@ -186,6 +187,7 @@ const mapStateToProps = (state, props) => {
snippetCollectionId: getSnippetCollectionId(state), snippetCollectionId: getSnippetCollectionId(state),
documentTitle: getDocumentTitle(state), documentTitle: getDocumentTitle(state),
pageFavicon: getPageFavicon(state), pageFavicon: getPageFavicon(state),
isLoadingComplete: getIsLoadingComplete(state),
}; };
}; };
...@@ -222,6 +224,7 @@ function QueryBuilder(props) { ...@@ -222,6 +224,7 @@ function QueryBuilder(props) {
allLoaded, allLoaded,
showTimelinesForCollection, showTimelinesForCollection,
card, card,
isLoadingComplete,
} = props; } = props;
const forceUpdate = useForceUpdate(); const forceUpdate = useForceUpdate();
...@@ -365,13 +368,14 @@ function QueryBuilder(props) { ...@@ -365,13 +368,14 @@ function QueryBuilder(props) {
} }
}); });
const { isRunning } = uiControls;
const [shouldSendNotification, setShouldSendNotification] = useState(false);
const [isShowingToaster, setIsShowingToaster] = useState(false); const [isShowingToaster, setIsShowingToaster] = useState(false);
const { isRunning } = uiControls;
const onTimeout = useCallback(() => { const onTimeout = useCallback(() => {
setIsShowingToaster(true); if (Notification.permission === "default") {
setIsShowingToaster(true);
}
}, []); }, []);
useLoadingTimer(isRunning, { useLoadingTimer(isRunning, {
...@@ -382,26 +386,21 @@ function QueryBuilder(props) { ...@@ -382,26 +386,21 @@ function QueryBuilder(props) {
const [requestPermission, showNotification] = useWebNotification(); const [requestPermission, showNotification] = useWebNotification();
useEffect(() => { useEffect(() => {
if (!isRunning) { if (isLoadingComplete) {
setIsShowingToaster(false); setIsShowingToaster(false);
}
if (!isRunning && shouldSendNotification) { if (Notification.permission === "granted" && document.hidden) {
if (document.hidden) {
showNotification( showNotification(
t`All Set! Your question is ready.`, t`All Set! Your question is ready.`,
t`${card.name} is loaded.`, t`${card.name} is loaded.`,
); );
} }
setShouldSendNotification(false);
} }
}, [isRunning, shouldSendNotification, showNotification, card?.name]); }, [isLoadingComplete, showNotification, card?.name]);
const onConfirmToast = useCallback(async () => { const onConfirmToast = useCallback(async () => {
const result = await requestPermission(); await requestPermission();
if (result === "granted") { setIsShowingToaster(false);
setIsShowingToaster(false);
setShouldSendNotification(true);
}
}, [requestPermission]); }, [requestPermission]);
const onDismissToast = useCallback(() => { const onDismissToast = useCallback(() => {
......
...@@ -72,6 +72,7 @@ const DEFAULT_UI_CONTROLS = { ...@@ -72,6 +72,7 @@ const DEFAULT_UI_CONTROLS = {
isShowingNewbModal: false, isShowingNewbModal: false,
isEditing: false, isEditing: false,
isRunning: false, isRunning: false,
isQueryComplete: false,
isShowingSummarySidebar: false, isShowingSummarySidebar: false,
isShowingFilterSidebar: false, isShowingFilterSidebar: false,
isShowingChartTypeSidebar: false, isShowingChartTypeSidebar: false,
...@@ -93,6 +94,8 @@ const DEFAULT_LOADING_CONTROLS = { ...@@ -93,6 +94,8 @@ const DEFAULT_LOADING_CONTROLS = {
timeoutId: "", timeoutId: "",
}; };
const DEFAULT_QUERY_STATUS = "idle";
const UI_CONTROLS_SIDEBAR_DEFAULTS = { const UI_CONTROLS_SIDEBAR_DEFAULTS = {
isShowingSummarySidebar: false, isShowingSummarySidebar: false,
isShowingFilterSidebar: false, isShowingFilterSidebar: false,
...@@ -196,12 +199,18 @@ export const uiControls = handleActions( ...@@ -196,12 +199,18 @@ export const uiControls = handleActions(
next: (state, { payload }) => ({ ...state, isEditing: false }), next: (state, { payload }) => ({ ...state, isEditing: false }),
}, },
[RUN_QUERY]: state => ({ ...state, isRunning: true }), [RUN_QUERY]: state => ({
...state,
isRunning: true,
}),
[CANCEL_QUERY]: { [CANCEL_QUERY]: {
next: (state, { payload }) => ({ ...state, isRunning: false }), next: (state, { payload }) => ({ ...state, isRunning: false }),
}, },
[QUERY_COMPLETED]: { [QUERY_COMPLETED]: {
next: (state, { payload }) => ({ ...state, isRunning: false }), next: (state, { payload }) => ({
...state,
isRunning: false,
}),
}, },
[QUERY_ERRORED]: { [QUERY_ERRORED]: {
next: (state, { payload }) => ({ ...state, isRunning: false }), next: (state, { payload }) => ({ ...state, isRunning: false }),
...@@ -324,6 +333,15 @@ export const loadingControls = handleActions( ...@@ -324,6 +333,15 @@ export const loadingControls = handleActions(
DEFAULT_LOADING_CONTROLS, DEFAULT_LOADING_CONTROLS,
); );
export const queryStatus = handleActions(
{
[RUN_QUERY]: state => "running",
[QUERY_COMPLETED]: state => "complete",
[CANCEL_QUERY]: state => "idle",
},
DEFAULT_QUERY_STATUS,
);
export const zoomedRowObjectId = handleActions( export const zoomedRowObjectId = handleActions(
{ {
[INITIALIZE_QB]: { [INITIALIZE_QB]: {
......
...@@ -38,6 +38,7 @@ import ObjectMode from "metabase/modes/components/modes/ObjectMode"; ...@@ -38,6 +38,7 @@ import ObjectMode from "metabase/modes/components/modes/ObjectMode";
import { LOAD_COMPLETE_FAVICON } from "metabase/hoc/Favicon"; import { LOAD_COMPLETE_FAVICON } from "metabase/hoc/Favicon";
export const getUiControls = state => state.qb.uiControls; export const getUiControls = state => state.qb.uiControls;
const getQueryStatus = state => state.qb.queryStatus;
const getLoadingControls = state => state.qb.loadingControls; const getLoadingControls = state => state.qb.loadingControls;
export const getIsShowingTemplateTagsEditor = state => export const getIsShowingTemplateTagsEditor = state =>
...@@ -69,6 +70,8 @@ export const getIsAnySidebarOpen = createSelector([getUiControls], uiControls => ...@@ -69,6 +70,8 @@ export const getIsAnySidebarOpen = createSelector([getUiControls], uiControls =>
export const getIsEditing = state => getUiControls(state).isEditing; export const getIsEditing = state => getUiControls(state).isEditing;
export const getIsRunning = state => getUiControls(state).isRunning; export const getIsRunning = state => getUiControls(state).isRunning;
export const getIsLoadingComplete = state =>
getQueryStatus(state) === "complete";
export const getCard = state => state.qb.card; export const getCard = state => state.qb.card;
export const getOriginalCard = state => state.qb.originalCard; export const getOriginalCard = state => state.qb.originalCard;
......
resources/frontend_client/app/assets/img/blue_check.png

449 B | W: | H:

resources/frontend_client/app/assets/img/blue_check.png

780 B | W: | H:

resources/frontend_client/app/assets/img/blue_check.png
resources/frontend_client/app/assets/img/blue_check.png
resources/frontend_client/app/assets/img/blue_check.png
resources/frontend_client/app/assets/img/blue_check.png
  • 2-up
  • Swipe
  • Onion skin
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment