edit dashboard experience

pull/477/head
Tim Pechersky 2021-12-15 15:56:46 +00:00
rodzic 447742d3bc
commit 1918d3b0d8
13 zmienionych plików z 642 dodań i 418 usunięć

Wyświetl plik

@ -23,6 +23,7 @@ import SubscriptionReport from "../../src/components/SubscriptionReport";
import { AiOutlinePlusCircle } from "react-icons/ai";
import { v4 } from "uuid";
import { DRAWER_TYPES } from "../../src/core/providers/OverlayProvider/constants";
import Page404 from "../../src/components/FourOFour";
const HOUR_KEY = "Hourly";
const DAY_KEY = "Daily";
@ -158,12 +159,12 @@ const Analytics = () => {
const updateCallback = ({ name }) => {
updateDashboard.mutate({
id: dashboardCache.data.data.id,
id: dashboardCache.data.id,
dashboard: {
dashboard_id: dashboardCache.data.data.id,
dashboard_id: dashboardCache.data.id,
name: name,
subscription_cache:
dashboardCache.data.data.resource_data.subscription_setting,
dashboardCache.data.resource_data.subscription_setting,
},
});
};
@ -175,6 +176,13 @@ const Analytics = () => {
)
return <Spinner />;
if (
dashboardCache.isLoadingError &&
dashboardCache?.error?.response?.status === 404
) {
return <Page404 />;
}
const plotMinW = "250px";
return (
@ -193,7 +201,7 @@ const Analytics = () => {
as={Heading}
colorScheme="blue"
placeholder="enter note here"
defaultValue={dashboardCache.data.data.resource_data.name}
defaultValue={dashboardCache.data.resource_data.name}
onSubmit={(nextValue) =>
updateCallback({
name: nextValue,
@ -224,7 +232,7 @@ const Analytics = () => {
onClick={() =>
overlay.toggleDrawer({
type: DRAWER_TYPES.NEW_DASHBOARD_ITEM,
props: dashboardCache.data.data.resource_data,
props: dashboardCache.data.resource_data,
})
}
mr={8}
@ -273,7 +281,7 @@ const Analytics = () => {
</Flex>
);
})}
{dashboardCache.data.data.resource_data.subscription_settings[0] ===
{dashboardCache.data.resource_data.subscription_settings[0] ===
undefined && (
<Flex pt="220px" w="100%" placeContent="center">
<Button
@ -282,7 +290,7 @@ const Analytics = () => {
onClick={() =>
overlay.toggleDrawer({
type: DRAWER_TYPES.NEW_DASHBOARD_ITEM,
props: dashboardCache.data.data.resource_data,
props: dashboardCache.data.resource_data,
})
}
>

Wyświetl plik

@ -24,13 +24,18 @@ const AutoCompleter = ({
dropdownItem,
getLeftAddonColor,
itemIdx,
selectedItem,
initialIsOpen,
}) => {
const ui = useContext(UIContext);
return (
<Downshift
onSelect={onSelect}
itemToString={itemToString}
initialSelectedItem={initialSelectedItem ?? undefined}
initialInputValue={itemToString(initialSelectedItem)}
selectedItem={selectedItem}
initialIsOpen={initialIsOpen}
>
{({
getInputProps,

Wyświetl plik

@ -1,14 +1,20 @@
import React, { useEffect } from "react";
import React, { useContext, useMemo } from "react";
import { chakra, Stack, Spinner } from "@chakra-ui/react";
import { useSubscription, usePresignedURL } from "../core/hooks";
import CheckboxGrouped from "./CheckboxGrouped";
import massageAbi from "../core/utils/massageAbi";
import UIContext from "../core/providers/UIProvider/context";
import {
DASHBOARD_CONFIGURE_SETTING_SCOPES,
DASHBOARD_UPDATE_ACTIONS,
} from "../core/constants";
const SuggestABI = ({ subscriptionId, drawerState, setState }) => {
const SuggestABI = ({ subscriptionId, state }) => {
const { subscriptionLinksCache } = useSubscription({
id: subscriptionId,
});
const { dispatchDashboardUpdate } = useContext(UIContext);
const { data, isLoading } = usePresignedURL({
url: subscriptionLinksCache?.data?.data?.url,
isEnabled: true,
@ -17,73 +23,58 @@ const SuggestABI = ({ subscriptionId, drawerState, setState }) => {
requestNewURLCallback: subscriptionLinksCache.refetch,
});
const setFunctions = (arg) => {
setState((currentHeadState) => {
const newHeadState = { ...currentHeadState };
if (typeof arg === "function") {
newHeadState.methods = arg(newHeadState.methods);
} else {
newHeadState.methods = { ...arg };
}
return newHeadState;
});
};
const setEvents = (arg) => {
setState((currentHeadState) => {
const newHeadState = { ...currentHeadState };
if (typeof arg === "function") {
newHeadState.events = arg(newHeadState.events);
} else {
newHeadState.events = { ...arg };
}
return newHeadState;
});
};
useEffect(() => {
if (data && !isLoading) {
const { fnsObj, eventsObj } = massageAbi(data);
setState((currentHeadState) => {
const newHeadState = { ...currentHeadState };
newHeadState.methods = fnsObj;
newHeadState.events = eventsObj;
return newHeadState;
});
}
//eslint-disable-next-line
}, [data, isLoading]);
if (isLoading || !data) return <Spinner />;
const abiEvents = useMemo(
() => data && data.filter((abiItem) => abiItem.type === "event"),
[data]
);
const abiMethods = useMemo(
() => data && data.filter((abiItem) => abiItem.type === "function"),
[data]
);
if (isLoading) return <Spinner />;
if (!data) return "";
return (
<>
<Stack>
<CheckboxGrouped
groupName="events"
list={Object.values(drawerState.events)}
isItemChecked={(item) => item.checked}
isAllChecked={Object.values(drawerState.events).every(
(item) => !!item.checked
list={abiEvents}
isItemChecked={(item) => {
return state.events.some((event) => event.name === item.name);
}}
isAllChecked={abiEvents.every((abiEvent) => {
return state.events.some((event) => abiEvent.name === event.name);
})}
isIndeterminate={state.events.some((event) =>
abiEvents.some((abiEvent) => abiEvent.name === event.name)
)}
isIndeterminate={
Object.values(drawerState.events).some((item) => item.checked) &&
!Object.values(drawerState.events).every((item) => item.checked)
}
setItemChecked={(item, isChecked) =>
setEvents((currentState) => {
const newState = { ...currentState };
newState[item.signature].checked = isChecked;
return newState;
dispatchDashboardUpdate({
type: isChecked
? DASHBOARD_UPDATE_ACTIONS.APPEND_METRIC
: DASHBOARD_UPDATE_ACTIONS.DROP_METRIC,
scope: DASHBOARD_CONFIGURE_SETTING_SCOPES.METRIC_NAME,
payload: {
subscriptionId: subscriptionId,
data: item.name,
propertyName: "events",
},
})
}
setAll={(isChecked) =>
setEvents((currentEvents) => {
const newEvents = { ...currentEvents };
Object.keys(newEvents).forEach(
(key) => (newEvents[key].checked = isChecked)
);
return newEvents;
dispatchDashboardUpdate({
type: isChecked
? DASHBOARD_UPDATE_ACTIONS.APPEND_METRIC
: DASHBOARD_UPDATE_ACTIONS.DROP_METRIC,
scope: DASHBOARD_CONFIGURE_SETTING_SCOPES.METRICS_ARRAY,
payload: {
subscriptionId: subscriptionId,
data: abiEvents.map((abiEvent) => {
return { name: abiEvent.name };
}),
propertyName: "events",
},
})
}
getName={(item) => {
@ -97,30 +88,43 @@ const SuggestABI = ({ subscriptionId, drawerState, setState }) => {
}}
/>
<CheckboxGrouped
groupName="functions"
list={Object.values(drawerState.methods)}
isItemChecked={(item) => item.checked}
isAllChecked={Object.values(drawerState.methods).every(
(item) => !!item.checked
)}
isIndeterminate={
Object.values(drawerState.methods).some((item) => item.checked) &&
!Object.values(drawerState.methods).every((item) => item.checked)
groupName="methods"
list={abiMethods}
isItemChecked={(item) =>
state.methods.some((fn) => fn.name === item.name)
}
isAllChecked={abiMethods.every((abiMethod) => {
return state.methods.some((fn) => abiMethod.name === fn.name);
})}
isIndeterminate={state.methods.some((fn) =>
abiMethods.some((abiMethod) => abiMethod.name === fn.name)
)}
setItemChecked={(item, isChecked) =>
setFunctions((currentState) => {
const newState = { ...currentState };
newState[item.signature].checked = isChecked;
return newState;
dispatchDashboardUpdate({
type: isChecked
? DASHBOARD_UPDATE_ACTIONS.APPEND_METRIC
: DASHBOARD_UPDATE_ACTIONS.DROP_METRIC,
scope: DASHBOARD_CONFIGURE_SETTING_SCOPES.METRIC_NAME,
payload: {
subscriptionId: subscriptionId,
data: item.name,
propertyName: "methods",
},
})
}
setAll={(isChecked) =>
setFunctions((currentFunctions) => {
const newFunctions = { ...currentFunctions };
Object.keys(newFunctions).forEach(
(key) => (newFunctions[key].checked = isChecked)
);
return newFunctions;
dispatchDashboardUpdate({
type: isChecked
? DASHBOARD_UPDATE_ACTIONS.APPEND_METRIC
: DASHBOARD_UPDATE_ACTIONS.DROP_METRIC,
scope: DASHBOARD_CONFIGURE_SETTING_SCOPES.METRICS_ARRAY,
payload: {
subscriptionId: subscriptionId,
data: abiMethods.map((abiMethod) => {
return { name: abiMethod.name };
}),
propertyName: "methods",
},
})
}
getName={(item) => {

Wyświetl plik

@ -6,6 +6,13 @@ import {
Button,
Badge,
Spinner,
Accordion,
AccordionItem,
AccordionButton,
AccordionPanel,
AccordionIcon,
Box,
IconButton,
} from "@chakra-ui/react";
import { useSubscriptions } from "../core/hooks";
import color from "color";
@ -14,10 +21,17 @@ import { MODAL_TYPES } from "../core/providers/OverlayProvider/constants";
import CheckboxABI from "./CheckboxABI";
import AutoCompleter from "./AutoCompleter";
import CheckboxGrouped from "./CheckboxGrouped";
import { emptySubscriptionSettingItem } from "../core/utils/massageAbi";
import { GENERIC_METRICS } from "../core/constants";
import UIContext from "../core/providers/UIProvider/context";
import {
DASHBOARD_UPDATE_ACTIONS,
DASHBOARD_CONFIGURE_SETTING_SCOPES,
} from "../core/constants";
import { BiTrash } from "react-icons/bi";
const NewDashboardChart = ({ drawerState, setDrawerState }) => {
const NewDashboardChart = () => {
const overlay = useContext(OverlayContext);
const ui = useContext(UIContext);
const [pickerItems, setPickerItems] = useState();
@ -32,164 +46,255 @@ const NewDashboardChart = ({ drawerState, setDrawerState }) => {
}, [subscriptionsCache.isLoading, subscriptionsCache.data]);
if (subscriptionsCache.isLoading || !pickerItems) return <Spinner />;
const filterFn = (item, inputValue) =>
(item.subscription_type_id === "ethereum_blockchain" ||
item.subscription_type_id === "polygon_blockchain") &&
!item.subscription_type_id.includes("_whalewatch") &&
(!inputValue ||
item.address.toUpperCase().includes(inputValue.toUpperCase()) ||
item.label.toUpperCase().includes(inputValue.toUpperCase()));
return (
<>
<Stack spacing="24px">
{drawerState.map((subscribedItem, idx) => {
const setGeneric = (callbackFn) => {
setDrawerState((currentDrawerState) => {
const newDrawerState = [...currentDrawerState];
newDrawerState[idx].generic = callbackFn(
newDrawerState[idx].generic
);
return newDrawerState;
});
};
const setDrawerAtHead = (arg) => {
let newDrawerState = [...drawerState];
if (typeof arg === "function") {
newDrawerState[idx] = arg(newDrawerState[idx]);
} else {
newDrawerState[idx] = [...arg];
}
setDrawerState(newDrawerState);
};
return (
<Stack key={`new-chart-component-${idx}`}>
<FormLabel pb={0}>Subscription:</FormLabel>
<AutoCompleter
itemIdx={idx}
pickerItems={pickerItems}
initialSelectedItem={undefined}
itemToString={(item) => item?.label}
onSelect={(selectedItem) =>
setDrawerState((currentValue) => {
const newValue = [...currentValue];
newValue[idx] = {
...emptySubscriptionSettingItem,
subscription: selectedItem,
};
return newValue;
})
}
getLeftAddonColor={(item) => item?.color ?? "inherit"}
getLabelColor={(item) =>
item?.color ? color(item.color) : undefined
}
placeholder="Select subcription"
getDefaultValue={(item) => (item?.label ? item.label : "")}
filterFn={filterFn}
empyListCTA={(inputValue) => (
<Button
colorScheme="orange"
variant="outline"
size="sm"
fontSize="sm"
w="100%"
m={0}
isTruncated
onClick={() => {
overlay.toggleModal({
type: MODAL_TYPES.NEW_SUBSCRIPTON,
props: {
initialValue: inputValue,
},
});
}}
>
Subscribe to: {inputValue}{" "}
</Button>
)}
dropdownItem={(item) => {
const badgeColor = color(`${item.color}`);
return (
<>
<chakra.span whiteSpace="nowrap">
{item.label}
</chakra.span>
<Badge
size="sm"
placeSelf="self-end"
colorScheme={item.abi ? "green" : "gray"}
>
ABI
</Badge>
<Badge
isTruncated
size="sm"
placeSelf="self-end"
bgColor={item.color}
color={
badgeColor.isDark()
? badgeColor.lighten(100).hex()
: badgeColor.darken(0.6).hex()
}
>
{item.address}
</Badge>
</>
<Stack spacing="24px" pb="100px">
{ui.dashboardUpdate.subscription_settings.length > 0 && (
<>
<FormLabel pb={0}>Subscriptions:</FormLabel>
<Accordion allowToggle allowMultiple defaultIndex={[0]}>
{ui.dashboardUpdate.subscription_settings.map(
(subscribedItem, idx) => {
const subscriptionItem =
subscriptionsCache.data.subscriptions.find(
(subscription) =>
subscription.id === subscribedItem?.subscription_id
);
}}
/>
{subscribedItem?.subscription?.id && (
<Stack spacing={1}>
<FormLabel pb={0}>Metric:</FormLabel>
<CheckboxGrouped
groupName="generic metrics:"
getName={(item) => item.name}
list={Object.values(drawerState[idx].generic)}
isItemChecked={(item) => item.checked}
isAllChecked={Object.values(drawerState[idx].generic).every(
(item) => !!item.checked
)}
isIndeterminate={
Object.values(drawerState[idx].generic).some(
(item) => item.checked
) &&
!Object.values(drawerState[idx].generic).every(
(item) => item.checked
)
}
setItemChecked={(item, isChecked) =>
setGeneric((currentState) => {
const newState = { ...currentState };
newState[item.value].checked = isChecked;
return newState;
})
}
setAll={(isChecked) =>
setGeneric((currentState) => {
const newState = { ...currentState };
Object.keys(newState).forEach(
(key) => (newState[key].checked = isChecked)
);
return newState;
})
}
/>
return (
<AccordionItem key={`new-chart-component-${idx}`}>
{subscribedItem?.subscription_id && (
<>
<h2>
<AccordionButton>
<Box flex="1" textAlign="left">
<FormLabel>{`${subscriptionItem.label} (${subscriptionItem.address})`}</FormLabel>
</Box>
<AccordionIcon />
</AccordionButton>
</h2>
<CheckboxABI
subscriptionId={subscribedItem.subscription.id}
drawerState={drawerState[idx]}
setState={setDrawerAtHead}
idx={idx}
/>
</Stack>
)}
</Stack>
);
})}
</Stack>
</>
<AccordionPanel pb={4}>
<Stack>
{subscribedItem?.subscription_id && (
<Stack spacing={1}>
<IconButton
icon={<BiTrash />}
variant="ghost"
colorScheme="red"
size="sm"
onClick={() =>
ui.dispatchDashboardUpdate({
type: DASHBOARD_UPDATE_ACTIONS.DROP_SUBSCRIPTION,
payload: {
subscriptionId:
subscribedItem.subscription_id,
},
})
}
/>
<FormLabel pb={0}>Metric:</FormLabel>
<CheckboxGrouped
groupName="generic metrics:"
getName={(item) => item}
list={GENERIC_METRICS}
isItemChecked={(item) =>
subscribedItem.generic.some(
(subscribedGenericItem) =>
subscribedGenericItem.name === item
)
}
isAllChecked={GENERIC_METRICS.some((item) =>
subscribedItem.generic.some(
(subscribedGenericItem) =>
subscribedGenericItem.name === item
)
)}
isIndeterminate={GENERIC_METRICS.some(
(item) =>
subscribedItem.generic.some(
(subscribedGenericItem) =>
subscribedGenericItem.name == item
)
)}
setItemChecked={(item, isChecked) =>
ui.dispatchDashboardUpdate({
type: isChecked
? DASHBOARD_UPDATE_ACTIONS.APPEND_METRIC
: DASHBOARD_UPDATE_ACTIONS.DROP_METRIC,
scope:
DASHBOARD_CONFIGURE_SETTING_SCOPES.METRIC_NAME,
payload: {
subscriptionId:
subscribedItem.subscription_id,
data: item,
propertyName: "generic",
},
})
}
setAll={(isChecked) =>
ui.dispatchDashboardUpdate({
type: isChecked
? DASHBOARD_UPDATE_ACTIONS.APPEND_METRIC
: DASHBOARD_UPDATE_ACTIONS.DROP_METRIC,
scope:
DASHBOARD_CONFIGURE_SETTING_SCOPES.METRICS_ARRAY,
payload: {
subscriptionId:
subscribedItem.subscription_id,
data: GENERIC_METRICS.map(
(genericMetricName) => {
return { name: genericMetricName };
}
),
propertyName: "generic",
},
})
}
/>
<CheckboxABI
subscriptionId={
subscribedItem.subscription_id
}
state={subscribedItem}
idx={idx}
/>
</Stack>
)}
</Stack>
</AccordionPanel>
</>
)}
{subscribedItem?.subscription_id === undefined && (
<>
<AutoCompleter
initialIsOpen={true}
itemIdx={
ui.dashboardUpdate.subscription_settings.length
}
pickerItems={pickerItems.filter(
(pickerItem) =>
!ui.dashboardUpdate.subscription_settings.some(
(subscriptiponSetting) =>
pickerItem.id ===
subscriptiponSetting.subscription_id
) && pickerItem.abi === "True"
)}
itemToString={(item) => item?.label}
onSelect={(selectedItem) => {
ui.dispatchDashboardUpdate({
type: DASHBOARD_UPDATE_ACTIONS.OVERRIDE_SUBSCRIPTION,
payload: {
subscriptionId: selectedItem.id,
index: idx,
},
});
}}
getLeftAddonColor={(item) => item?.color ?? "inherit"}
getLabelColor={(item) =>
item?.color ? color(item.color) : undefined
}
placeholder="Select subcription"
getDefaultValue={(item) =>
item?.label ? item.label : ""
}
filterFn={filterFn}
empyListCTA={(inputValue) => (
<Button
colorScheme="orange"
variant="outline"
size="sm"
fontSize="sm"
w="100%"
m={0}
isTruncated
onClick={() => {
overlay.toggleModal({
type: MODAL_TYPES.NEW_SUBSCRIPTON,
props: {
initialValue: inputValue,
},
});
}}
>
Subscribe to: {inputValue}{" "}
</Button>
)}
dropdownItem={(item) => {
const badgeColor = color(`${item.color}`);
return (
<>
<chakra.span whiteSpace="nowrap">
{item.label}
</chakra.span>
<Badge
size="sm"
placeSelf="self-end"
colorScheme={item.abi ? "green" : "gray"}
>
ABI
</Badge>
<Badge
isTruncated
size="sm"
placeSelf="self-end"
bgColor={item.color}
color={
badgeColor.isDark()
? badgeColor.lighten(100).hex()
: badgeColor.darken(0.6).hex()
}
>
{item.address}
</Badge>
</>
);
}}
/>
<Button
onClick={() => {
ui.dispatchDashboardUpdate({
type: DASHBOARD_UPDATE_ACTIONS.DROP_SUBSCRIPTION,
payload: {
subscriptionId: undefined,
},
});
}}
colorScheme="blue"
variant="outline"
>
Remove
</Button>
</>
)}
</AccordionItem>
);
}
)}
</Accordion>
</>
)}
<Button
colorScheme="green"
size="md"
onClick={() =>
ui.dispatchDashboardUpdate({
type: DASHBOARD_UPDATE_ACTIONS.APPEND_SUBSCRIPTION,
payload: {
subscriptionId: undefined,
},
})
}
>
Add subscription to dashboard:
</Button>
</Stack>
);
};

Wyświetl plik

@ -20,9 +20,12 @@ import {
colors,
animals,
} from "unique-names-generator";
import UIContext from "../core/providers/UIProvider/context";
import { DASHBOARD_UPDATE_ACTIONS } from "../core/constants";
const NewDashboardName = (props) => {
const overlay = useContext(OverlayContext);
const { dispatchDashboardUpdate } = useContext(UIContext);
const { createDashboard } = useDashboard();
const [name, setName] = useState(props.initialName);
const [placeholder] = useState(
@ -35,6 +38,10 @@ const NewDashboardName = (props) => {
const router = useRouter();
useEffect(() => {
if (createDashboard.isSuccess && createDashboard.data) {
createDashboard.reset();
dispatchDashboardUpdate({
type: DASHBOARD_UPDATE_ACTIONS.RESET_TO_DEFAULT,
});
router.push({
pathname: "/dashboard/[dashboardId]",
query: { dashboardId: createDashboard.data.id },
@ -45,7 +52,7 @@ const NewDashboardName = (props) => {
props: createDashboard.data.resource_data,
});
}
}, [createDashboard, router, overlay]);
}, [createDashboard, router, overlay, dispatchDashboardUpdate]);
return (
<>

Wyświetl plik

@ -25,7 +25,7 @@ const SubscriptionReport = ({ timeRange, url, id, refetchLinks }) => {
url: url,
isEnabled: true,
id: id,
cacheType: timeRange,
cacheType: `${timeRange} subscription_report`,
requestNewURLCallback: refetchLinks,
hideToastOn404: true,
});

Wyświetl plik

@ -77,3 +77,28 @@ export const CHART_METRICS = {
FUNCTIONS: "function",
EVENTS: "event",
};
export const DASHBOARD_UPDATE_ACTIONS = {
RENAME_DASHBOARD: 0,
APPEND_METRIC: 1,
DROP_METRIC: 2,
APPEND_SUBSCRIPTION: 4,
DROP_SUBSCRIPTION: 6,
OVERRIDE_DASHBOARD: 7,
OVERRIDE_SUBSCRIPTION: 8,
RESET_TO_DEFAULT: 9,
};
export const DASHBOARD_CONFIGURE_SETTING_SCOPES = {
METRICS_ARRAY: 1, //Scope to change whole array (methods | events | generics)
METRIC_NAME: 2, //Scope to one metric based on name
METRICS_ALL: 3, //Scope to replace whole subscription_setting object keeping subscriptionId
};
export const GENERIC_METRICS = [
"transactions_in",
"transactions_out",
"value_in",
"value_out",
"balance",
];

Wyświetl plik

@ -22,6 +22,22 @@ const useDashboard = (dashboardId) => {
}
);
// const dashboardUpdateState = useQuery(
// ["DashboardUpdateState", { dashboardId: dashboardId }],
// () =>
// new Promise((resolve, reject) =>
// reject("Dashboard Update State has no network functionality")
// ),
// {
// ...queryCacheProps,
// staleTime: Infinity,
// onError: (error) => {
// toast(error, "error");
// },
// enabled: false,
// }
// );
const _createDashboard = async (dashboard) => {
const _dashboard = { ...dashboard };
if (!_dashboard.subscription_settings) {
@ -74,9 +90,14 @@ const useDashboard = (dashboardId) => {
}
);
const _getDashboard = async (dashboardId) => {
const response = await DashboardService.getDashboard(dashboardId);
return response.data;
};
const dashboardCache = useQuery(
["dashboards", { dashboardId }],
() => DashboardService.getDashboard(dashboardId),
["dashboards", { dashboardId: dashboardId }],
() => _getDashboard(dashboardId),
{
...queryCacheProps,
onError: (error) => {
@ -87,7 +108,7 @@ const useDashboard = (dashboardId) => {
);
const dashboardLinksCache = useQuery(
["dashboardLinks", { dashboardId }],
["dashboardLinks", { dashboardId: dashboardId }],
() => DashboardService.getDashboardLinks(dashboardId),
{
...queryCacheProps,

Wyświetl plik

@ -2,7 +2,6 @@ import { useQuery } from "react-query";
import { queryCacheProps } from "./hookCommon";
import { useToast } from ".";
import axios from "axios";
import { useEffect } from "react";
const usePresignedURL = ({
url,
@ -24,11 +23,15 @@ const usePresignedURL = ({
return response.data;
};
const { data, isLoading, error, refetch, failureCount } = useQuery(
["presignedURL", cacheType, id],
const { data, isLoading, error, failureCount } = useQuery(
["presignedURL", cacheType, id, url],
getFromPresignedURL,
{
...queryCacheProps,
refetchOnMount: false,
refetchOnWindowFocus: false,
refetchOnReconnect: false,
staleTime: Infinity,
enabled: isEnabled && url ? true : false,
keepPreviousData: true,
onError: (e) => {
@ -44,12 +47,6 @@ const usePresignedURL = ({
}
);
useEffect(() => {
if (url && isEnabled) {
refetch();
}
}, [url, isEnabled, refetch]);
return {
data,
isLoading,

Wyświetl plik

@ -37,7 +37,7 @@ import useDashboard from "../../hooks/useDashboard";
import SignUp from "../../../components/SignUp";
import NewDashboardChart from "../../../components/NewDashboardChart";
import { useRouter } from "../../hooks";
import { emptySubscriptionSettingItem } from "../../utils/massageAbi";
import { DASHBOARD_UPDATE_ACTIONS } from "../../constants";
const NewDashboardName = React.lazy(() =>
import("../../../components/NewDashboardName")
);
@ -73,9 +73,6 @@ const OverlayProvider = ({ children }) => {
const drawerDisclosure = useDisclosure();
const modalDisclosure = useDisclosure();
const alertDisclosure = useDisclosure();
const [drawerState, setDrawerState] = useState([
emptySubscriptionSettingItem,
]);
useLayoutEffect(() => {
if (modal.type === MODAL_TYPES.OFF && modalDisclosure.isOpen) {
@ -119,7 +116,9 @@ const OverlayProvider = ({ children }) => {
!modalDisclosure.isOpen &&
ui.isAppView &&
!ui.isLoggedIn &&
!ui.isLoggingOut
!ui.isLoggingOut &&
!ui.isLoggingIn &&
ui.isAppReady
) {
toggleModal({ type: MODAL_TYPES.LOGIN });
} else if (
@ -134,12 +133,14 @@ const OverlayProvider = ({ children }) => {
ui.isAppView,
ui.isLoggedIn,
ui.isLoggingOut,
ui.isLoggingIn,
ui.isAppReady,
]);
const finishNewDashboard = () => {
toggleDrawer({
type: DRAWER_TYPES.OFF,
props: dashboardCache.data.data.resource_data,
props: dashboardCache.data.resource_data,
});
window.sessionStorage.removeItem("new_dashboard");
};
@ -183,74 +184,7 @@ const OverlayProvider = ({ children }) => {
};
const submitNewDashboardItem = () => {
const newDashboard = { ...drawer.props };
drawerState.forEach((drawerSubscriptionSetting) => {
let index = newDashboard.subscription_settings.findIndex(
(subscriptionSetting) =>
subscriptionSetting.subscription_id ===
drawerSubscriptionSetting.subscription.id
);
if (index === -1) {
newDashboard.subscription_settings.push({
subscription_id: drawerSubscriptionSetting.subscription.id,
events: [],
generic: [],
methods: [],
});
index = newDashboard.subscription_settings.length - 1;
}
let temp = [];
Object.values(drawerSubscriptionSetting.generic).forEach(
(drawerGenericItem) => {
if (
drawerGenericItem.checked &&
!newDashboard.subscription_settings[index].generic.some(
(metric) => metric === drawerGenericItem.value
)
) {
temp.push({ name: drawerGenericItem.value });
}
}
);
newDashboard.subscription_settings[index].generic = [
...newDashboard.subscription_settings[index].generic,
...temp,
];
temp = [];
Object.values(drawerSubscriptionSetting.events).forEach(
(drawerEventItem) => {
const isSome = newDashboard.subscription_settings[index].events.some(
(metric) => metric === drawerEventItem.name
);
if (drawerEventItem.checked && !isSome) {
temp.push({ name: drawerEventItem.name });
}
}
);
newDashboard.subscription_settings[index].events = [
...newDashboard.subscription_settings[index].events,
...temp,
];
temp = [];
Object.values(drawerSubscriptionSetting.methods).forEach(
(drawerFunctionItem) => {
const isSome = newDashboard.subscription_settings[index].methods.some(
(metric) => metric === drawerFunctionItem.name
);
if (drawerFunctionItem.checked && !isSome) {
temp.push({ name: drawerFunctionItem.name });
}
}
);
newDashboard.subscription_settings[index].methods = [
...newDashboard.subscription_settings[index].methods,
...temp,
];
});
updateDashboard.mutate({ dashboard: newDashboard, id: dashboardId });
updateDashboard.mutate({ dashboard: ui.dashboardUpdate, id: dashboardId });
};
useEffect(() => {
@ -259,12 +193,17 @@ const OverlayProvider = ({ children }) => {
updateDashboard.isSuccess
) {
toggleDrawer({ type: DRAWER_TYPES.OFF, props: undefined });
updateDashboard.reset();
}
}, [updateDashboard.isSuccess, drawer.type]);
}, [updateDashboard, drawer.type]);
useEffect(() => {
if (createDashboard.isSuccess) {
if (
drawer.type === DRAWER_TYPES.NEW_DASHBOARD &&
createDashboard.isSuccess
) {
finishNewDashboard();
createDashboard.reset();
}
//eslint-disable-next-line
}, [createDashboard.isSuccess]);
@ -274,15 +213,17 @@ const OverlayProvider = ({ children }) => {
createDashboard.isSuccess &&
drawer.type === DRAWER_TYPES.NEW_DASHBOARD_ITEM
) {
setDrawerState([emptySubscriptionSettingItem]);
toggleDrawer({ type: DRAWER_TYPES.OFF, props: undefined });
}
}, [createDashboard.isSuccess, drawer.type]);
const cancelDashboardItem = () => {
setDrawerState([emptySubscriptionSettingItem]);
toggleDrawer({ type: DRAWER_TYPES.OFF, props: undefined });
ui.dispatchDashboardUpdate({
type: DASHBOARD_UPDATE_ACTIONS.RESET_TO_DEFAULT,
});
};
return (
<OverlayContext.Provider
value={{ modal, toggleModal, drawer, toggleDrawer, toggleAlert }}
@ -403,7 +344,7 @@ const OverlayProvider = ({ children }) => {
<DrawerHeader borderBottomWidth="1px">
{drawer.type === DRAWER_TYPES.NEW_DASHBOARD && "New dashboard"}
{drawer.type === DRAWER_TYPES.NEW_DASHBOARD_ITEM &&
"New dashboard element"}
"Edit dashboard"}
</DrawerHeader>
<DrawerBody h="auto">
@ -413,14 +354,10 @@ const OverlayProvider = ({ children }) => {
</Suspense>
)}
{drawer.type === DRAWER_TYPES.NEW_DASHBOARD_ITEM && (
<Suspense
fallback={<Spinner id={"new dashboard element fallback"} />}
>
<Suspense fallback={<Spinner id={"edit dahsboard fallback"} />}>
<NewDashboardChart
firstField={firstField}
props={drawer.props}
drawerState={drawerState}
setDrawerState={setDrawerState}
/>
</Suspense>
)}
@ -430,7 +367,6 @@ const OverlayProvider = ({ children }) => {
variant="outline"
mr={3}
onClick={() => {
console.log("cancel click on drawer", drawer.type);
if (drawer.type === DRAWER_TYPES.NEW_DASHBOARD) {
toggleAlert(() => finishNewDashboard());
}

Wyświetl plik

@ -4,13 +4,18 @@ import React, {
useEffect,
useCallback,
useLayoutEffect,
useReducer,
} from "react";
import { useBreakpointValue } from "@chakra-ui/react";
import { useStorage, useQuery, useRouter } from "../../hooks";
import { useStorage, useQuery, useRouter, useDashboard } from "../../hooks";
import UIContext from "./context";
import UserContext from "../UserProvider/context";
import { v4 as uuid4 } from "uuid";
import { PreferencesService } from "../../services";
import {
DASHBOARD_CONFIGURE_SETTING_SCOPES,
DASHBOARD_UPDATE_ACTIONS,
} from "../../constants";
const onboardingSteps = [
{
@ -29,6 +34,8 @@ const onboardingSteps = [
const UIProvider = ({ children }) => {
const router = useRouter();
const { dashboardId } = router.params;
const { dashboardCache } = useDashboard(dashboardId);
const { user, isInit } = useContext(UserContext);
const isMobileView = useBreakpointValue({
base: true,
@ -274,12 +281,187 @@ const UIProvider = ({ children }) => {
onboardingRedirectCheckPassed,
]);
//***************Overlay's states ************************/
// const [newDashboardForm, setNewDashboardForm] = useStorage(
// window.sessionStorage,
// "newDashboardForm",
// null
// );
//***************New chart item 's state ************************/
const dashboardUpdateReducer = useCallback(
(state, command) => {
let newState = undefined;
let index = -1;
switch (command.type) {
case DASHBOARD_UPDATE_ACTIONS.RESET_TO_DEFAULT:
newState = { ...state };
if (!dashboardCache.isLoading && dashboardCache.data?.resource_data) {
newState = { ...dashboardCache.data.resource_data };
}
return newState;
case DASHBOARD_UPDATE_ACTIONS.RENAME_DASHBOARD:
return { ...state, name: command.payload };
case DASHBOARD_UPDATE_ACTIONS.OVERRIDE_DASHBOARD:
return { ...command.payload };
case DASHBOARD_UPDATE_ACTIONS.APPEND_SUBSCRIPTION:
newState = { ...state };
if (
state.subscription_settings.every(
(subscriptionSetting) =>
subscriptionSetting.subscription_id !==
command.payload.subscriptionId
)
) {
newState.subscription_settings.push({
subscription_id: command.payload.subscriptionId,
all_methods: false,
all_events: false,
generic: [],
methods: [],
events: [],
});
}
return newState;
case DASHBOARD_UPDATE_ACTIONS.OVERRIDE_SUBSCRIPTION:
newState = { ...state };
index =
dashboardCache.data?.resource_data?.subscription_settings?.findIndex(
(subscriptionSetting) =>
subscriptionSetting.subscription_id ===
command.payload.subscriptionId
);
newState.subscription_settings[command.payload.index] =
index !== -1
? JSON.parse(
JSON.stringify(
dashboardCache.data?.resource_data?.subscription_settings[
index
]
)
)
: {
subscription_id: command.payload.subscriptionId,
all_methods: false,
all_events: false,
generic: [],
methods: [],
events: [],
};
return newState;
case DASHBOARD_UPDATE_ACTIONS.DROP_SUBSCRIPTION:
newState = { ...state };
newState.subscription_settings =
newState.subscription_settings.filter(
(subscriptionSetting) =>
subscriptionSetting.subscription_id !==
command.payload.subscriptionId
);
return newState;
case DASHBOARD_UPDATE_ACTIONS.APPEND_METRIC:
switch (command.scope) {
case DASHBOARD_CONFIGURE_SETTING_SCOPES.METRICS_ARRAY:
newState = { ...state };
index = state.subscription_settings.findIndex(
(subscriptionSetting) =>
subscriptionSetting.subscription_id ===
command.payload.subscriptionId
);
if (index !== -1) {
newState.subscription_settings[index][
command.payload.propertyName
] = [...command.payload.data];
}
return newState;
case DASHBOARD_CONFIGURE_SETTING_SCOPES.METRIC_NAME:
newState = { ...state };
index = state.subscription_settings.findIndex(
(subscriptionSetting) =>
subscriptionSetting.subscription_id ===
command.payload.subscriptionId
);
if (index !== -1) {
if (
!newState.subscription_settings[index][
command.payload.propertyName
].some((method) => method.name === command.payload.data.name)
) {
newState.subscription_settings[index][
command.payload.propertyName
].push({
name: command.payload.data,
});
}
}
return newState;
default:
throw new Error();
}
case DASHBOARD_UPDATE_ACTIONS.DROP_METRIC:
switch (command.scope) {
case DASHBOARD_CONFIGURE_SETTING_SCOPES.METRICS_ARRAY:
newState = { ...state };
index = state.subscription_settings.findIndex(
(subscriptionSetting) =>
subscriptionSetting.subscription_id ===
command.payload.subscriptionId
);
newState.subscription_settings[index][
command.payload.propertyName
] = [];
return newState;
case DASHBOARD_CONFIGURE_SETTING_SCOPES.METRIC_NAME:
newState = { ...state };
index = state.subscription_settings.findIndex(
(subscriptionSetting) =>
subscriptionSetting.subscription_id ===
command.payload.subscriptionId
);
newState.subscription_settings[index][
command.payload.propertyName
] = newState.subscription_settings[index][
command.payload.propertyName
].filter((metric) => metric.name !== command.payload.data);
return newState;
default:
throw new Error(`unhandled case command.scope: ${command.scope}`);
}
default:
throw new Error(`unhandled case command.type: ${command.type}`);
}
},
[dashboardCache.data, dashboardCache.isLoading]
);
const [dashboardUpdate, dispatchDashboardUpdate] = useReducer(
dashboardUpdateReducer,
{
name: undefined,
subscription_settings: [
{
subscription_id: undefined,
all_methods: false,
all_events: false,
generic: [],
methods: [],
events: [],
},
],
}
);
useEffect(() => {
if (!dashboardCache.isLoading && dashboardCache.data?.resource_data) {
const dashboardCachedData = JSON.parse(
JSON.stringify({ ...dashboardCache.data.resource_data })
);
dispatchDashboardUpdate({
type: DASHBOARD_UPDATE_ACTIONS.OVERRIDE_DASHBOARD,
payload: dashboardCachedData,
});
}
}, [dashboardId, dashboardCache.isLoading, dashboardCache.data]);
//***************New dashboard state ************************/
const [newDashboardForm, setNewDashboardForm] = useState();
return (
@ -318,6 +500,8 @@ const UIProvider = ({ children }) => {
setLoggingIn,
newDashboardForm,
setNewDashboardForm,
dashboardUpdate,
dispatchDashboardUpdate,
}}
>
{children}

Wyświetl plik

@ -74,3 +74,9 @@ export const getSubscriptionABI = (id) => () => {
url: `${API}/subscriptions/${id}/abi`,
});
};
export const getSubscription = (id) =>
http({
method: "GET",
url: `${API}/subscriptions/${id}`,
});

Wyświetl plik

@ -1,74 +0,0 @@
const massageAbi = (abi) => {
const coder = require("web3-eth-abi");
const getSignature = (item) => {
if (item.type === `function`) {
const retval = coder.encodeFunctionSignature(item);
return retval;
} else if (item.type === `event`) {
const retval = coder.encodeEventSignature(item);
return retval;
}
console.error("item passed to getKay was neither fn neither event!");
};
const filtered = abi.filter(
(item) => item.type === `event` || item.type === `function`
);
const signed = filtered.map((item) => {
item.signature = getSignature(item);
return item;
});
const events = [];
const functions = [];
signed.forEach((item) => {
if (item.type === "event") {
events.push(item);
}
if (item.type === "function") {
functions.push(item);
}
});
const keyEv = {};
const keyFn = {};
const eventsObj =
events.length > 0
? events.reduce(
(acc, curr) => ((acc[curr.signature] = { ...curr }), keyEv)
)
: [];
const fnsObj =
functions.length > 0
? functions.reduce(
(acc, curr) => ((acc[curr.signature] = { ...curr }), keyFn)
)
: 0;
return { fnsObj, eventsObj };
};
export const emptySubscriptionSettingItem = {
all_methods: false,
all_events: false,
subscription: undefined,
generic: {
transactions_in: {
value: "transactions_in",
name: "transactions in",
checked: false,
},
transactions_out: {
value: "transactions_out",
name: "transactions out",
checked: false,
},
value_in: { value: "value_in", name: "value in", checked: false },
value_out: { value: "value_out", name: "value out", checked: false },
balance: { value: "balance", name: "balance", checked: false },
},
events: {},
methods: {},
};
export default massageAbi;