kopia lustrzana https://github.com/bugout-dev/moonstream
commit
44f9cfdfad
|
@ -0,0 +1,68 @@
|
||||||
|
import React, { useContext, useEffect } from "react";
|
||||||
|
import { getLayout } from "../../src/layouts/EntriesLayout";
|
||||||
|
import StreamEntryDetails from "../../src/components/SteamEntryDetails";
|
||||||
|
import UIContext from "../../src/core/providers/UIProvider/context";
|
||||||
|
import {
|
||||||
|
Box,
|
||||||
|
Heading,
|
||||||
|
Text,
|
||||||
|
Stack,
|
||||||
|
UnorderedList,
|
||||||
|
ListItem,
|
||||||
|
} from "@chakra-ui/react";
|
||||||
|
import RouteButton from "../../src/components/RouteButton";
|
||||||
|
const Entry = () => {
|
||||||
|
console.count("render stream!");
|
||||||
|
const ui = useContext(UIContext);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (typeof window !== "undefined") {
|
||||||
|
if (ui?.currentTransaction) {
|
||||||
|
document.title = `Stream details: ${ui.currentTransaction.hash}`;
|
||||||
|
} else {
|
||||||
|
document.title = `Stream`;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}, [ui?.currentTransaction]);
|
||||||
|
|
||||||
|
if (ui?.currentTransaction) {
|
||||||
|
return <StreamEntryDetails />;
|
||||||
|
} else
|
||||||
|
return (
|
||||||
|
<Box px="7%" pt={12}>
|
||||||
|
<>
|
||||||
|
<Stack direction="column">
|
||||||
|
<Heading>Stream view</Heading>
|
||||||
|
<Text>
|
||||||
|
In this view you can follow events that happen on your subscribed
|
||||||
|
addresses
|
||||||
|
</Text>
|
||||||
|
<UnorderedList pl={4}>
|
||||||
|
<ListItem>
|
||||||
|
Click filter icon on right top corner to filter by specific
|
||||||
|
address across your subscriptions
|
||||||
|
</ListItem>
|
||||||
|
<ListItem>
|
||||||
|
On event cards you can click at right corner to see detailed
|
||||||
|
view!
|
||||||
|
</ListItem>
|
||||||
|
<ListItem>
|
||||||
|
For any adress of interest here you can copy it and subscribe at
|
||||||
|
subscription screen
|
||||||
|
</ListItem>
|
||||||
|
</UnorderedList>
|
||||||
|
<RouteButton
|
||||||
|
variant="solid"
|
||||||
|
size="md"
|
||||||
|
colorScheme="green"
|
||||||
|
href="/welcome"
|
||||||
|
>
|
||||||
|
Learn how to use moonstream
|
||||||
|
</RouteButton>
|
||||||
|
</Stack>
|
||||||
|
</>
|
||||||
|
</Box>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
Entry.getLayout = getLayout;
|
||||||
|
export default Entry;
|
|
@ -0,0 +1,520 @@
|
||||||
|
import React, { useEffect, useContext, useState, useCallback } from "react";
|
||||||
|
import {
|
||||||
|
Flex,
|
||||||
|
Spinner,
|
||||||
|
Button,
|
||||||
|
Center,
|
||||||
|
Text,
|
||||||
|
Menu,
|
||||||
|
MenuButton,
|
||||||
|
MenuList,
|
||||||
|
MenuItem,
|
||||||
|
MenuGroup,
|
||||||
|
IconButton,
|
||||||
|
Input,
|
||||||
|
Select,
|
||||||
|
Drawer,
|
||||||
|
DrawerBody,
|
||||||
|
DrawerFooter,
|
||||||
|
DrawerHeader,
|
||||||
|
DrawerOverlay,
|
||||||
|
DrawerContent,
|
||||||
|
DrawerCloseButton,
|
||||||
|
useDisclosure,
|
||||||
|
Tag,
|
||||||
|
TagLabel,
|
||||||
|
TagCloseButton,
|
||||||
|
Stack,
|
||||||
|
Spacer,
|
||||||
|
} from "@chakra-ui/react";
|
||||||
|
import { useSubscriptions } from "../core/hooks";
|
||||||
|
import StreamEntry from "./StreamEntry";
|
||||||
|
import UIContext from "../core/providers/UIProvider/context";
|
||||||
|
import { FaFilter } from "react-icons/fa";
|
||||||
|
import useStream from "../core/hooks/useStream";
|
||||||
|
import { ImCancelCircle } from "react-icons/im";
|
||||||
|
import { previousEvent } from "../core/services/stream.service";
|
||||||
|
import { PAGE_SIZE } from "../core/constants";
|
||||||
|
import DataContext from "../core/providers/DataProvider/context";
|
||||||
|
|
||||||
|
const FILTER_TYPES = {
|
||||||
|
ADDRESS: 0,
|
||||||
|
GAS: 1,
|
||||||
|
GAS_PRICE: 2,
|
||||||
|
AMOUNT: 3,
|
||||||
|
HASH: 4,
|
||||||
|
DISABLED: 99,
|
||||||
|
};
|
||||||
|
const DIRECTIONS = { SOURCE: "from", DESTINATION: "to" };
|
||||||
|
const CONDITION = {
|
||||||
|
EQUAL: 0,
|
||||||
|
CONTAINS: 1,
|
||||||
|
LESS: 2,
|
||||||
|
LESS_EQUAL: 3,
|
||||||
|
GREATER: 4,
|
||||||
|
GREATER_EQUAL: 5,
|
||||||
|
NOT_EQUAL: 6,
|
||||||
|
};
|
||||||
|
|
||||||
|
const EntriesNavigation = () => {
|
||||||
|
const { cursor, setCursor, streamCache, setStreamCache } =
|
||||||
|
useContext(DataContext);
|
||||||
|
const ui = useContext(UIContext);
|
||||||
|
const [firstLoading, setFirstLoading] = useState(true);
|
||||||
|
const { isOpen, onOpen, onClose } = useDisclosure();
|
||||||
|
const { subscriptionsCache } = useSubscriptions();
|
||||||
|
const [initialized, setInitialized] = useState(false);
|
||||||
|
const [newFilterState, setNewFilterState] = useState([
|
||||||
|
{
|
||||||
|
type: FILTER_TYPES.ADDRESS,
|
||||||
|
direction: DIRECTIONS.SOURCE,
|
||||||
|
condition: CONDITION.EQUAL,
|
||||||
|
value: null,
|
||||||
|
},
|
||||||
|
]);
|
||||||
|
const [filterState, setFilterState] = useState([]);
|
||||||
|
|
||||||
|
const {
|
||||||
|
eventsIsLoading,
|
||||||
|
eventsRefetch,
|
||||||
|
latestEventsRefetch,
|
||||||
|
nextEventRefetch,
|
||||||
|
previousEventRefetch,
|
||||||
|
streamBoundary,
|
||||||
|
setDefaultBoundary,
|
||||||
|
loadPreviousEventHandler,
|
||||||
|
loadNewesEventHandler,
|
||||||
|
loadOlderEventsIsFetching,
|
||||||
|
loadNewerEventsIsFetching,
|
||||||
|
previousEventIsFetching,
|
||||||
|
nextEventIsFetching,
|
||||||
|
olderEvent,
|
||||||
|
} = useStream(
|
||||||
|
ui.searchTerm.q,
|
||||||
|
streamCache,
|
||||||
|
setStreamCache,
|
||||||
|
cursor,
|
||||||
|
setCursor
|
||||||
|
);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (!streamBoundary.start_time && !streamBoundary.end_time) {
|
||||||
|
setDefaultBoundary();
|
||||||
|
} else if (!initialized) {
|
||||||
|
eventsRefetch();
|
||||||
|
latestEventsRefetch();
|
||||||
|
nextEventRefetch();
|
||||||
|
previousEventRefetch();
|
||||||
|
setInitialized(true);
|
||||||
|
} else if (
|
||||||
|
streamCache.length == 0 &&
|
||||||
|
olderEvent?.event_timestamp &&
|
||||||
|
firstLoading
|
||||||
|
) {
|
||||||
|
loadPreviousEventHandler();
|
||||||
|
setFirstLoading(false);
|
||||||
|
}
|
||||||
|
//TODO @AAndrey Dolgolev This useeffect produces lint warning, please review and
|
||||||
|
//Either add dependencies and remove comment line below, or add dependencies
|
||||||
|
//eslint-disable-next-line
|
||||||
|
}, [
|
||||||
|
streamBoundary,
|
||||||
|
initialized,
|
||||||
|
setInitialized,
|
||||||
|
setDefaultBoundary,
|
||||||
|
eventsRefetch,
|
||||||
|
latestEventsRefetch,
|
||||||
|
nextEventRefetch,
|
||||||
|
previousEventRefetch,
|
||||||
|
]);
|
||||||
|
|
||||||
|
const setFilterProps = useCallback(
|
||||||
|
(filterIdx, props) => {
|
||||||
|
const newFilterProps = [...newFilterState];
|
||||||
|
newFilterProps[filterIdx] = { ...newFilterProps[filterIdx], ...props };
|
||||||
|
setNewFilterState(newFilterProps);
|
||||||
|
},
|
||||||
|
[newFilterState, setNewFilterState]
|
||||||
|
);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (
|
||||||
|
subscriptionsCache.data?.subscriptions[0]?.id &&
|
||||||
|
newFilterState[0]?.value === null
|
||||||
|
) {
|
||||||
|
setFilterProps(0, {
|
||||||
|
value: subscriptionsCache?.data?.subscriptions[0]?.address,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}, [subscriptionsCache, newFilterState, setFilterProps]);
|
||||||
|
|
||||||
|
const canCreate = false;
|
||||||
|
|
||||||
|
const canDelete = false;
|
||||||
|
|
||||||
|
const dropNewFilterArrayItem = (idx) => {
|
||||||
|
const oldArray = [...newFilterState];
|
||||||
|
|
||||||
|
const newArray = oldArray.filter(function (ele) {
|
||||||
|
return ele != oldArray[idx];
|
||||||
|
});
|
||||||
|
setNewFilterState(newArray);
|
||||||
|
};
|
||||||
|
|
||||||
|
const dropFilterArrayItem = (idx) => {
|
||||||
|
const oldArray = [...filterState];
|
||||||
|
const newArray = oldArray.filter(function (ele) {
|
||||||
|
return ele != oldArray[idx];
|
||||||
|
});
|
||||||
|
|
||||||
|
setFilterState(newArray);
|
||||||
|
setNewFilterState(newArray);
|
||||||
|
ui.setSearchTerm(
|
||||||
|
newArray
|
||||||
|
.map((filter) => {
|
||||||
|
return filter.direction + ":" + filter.value;
|
||||||
|
})
|
||||||
|
.join("+")
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleFilterSubmit = () => {
|
||||||
|
setFilterState(newFilterState);
|
||||||
|
ui.setSearchTerm(
|
||||||
|
newFilterState
|
||||||
|
.map((filter) => {
|
||||||
|
return filter.direction + ":" + filter.value;
|
||||||
|
})
|
||||||
|
.join("+")
|
||||||
|
);
|
||||||
|
onClose();
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleAddressChange = (idx) => (e) => {
|
||||||
|
setFilterProps(idx, { value: e.target.value });
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleConditionChange = (idx) => (e) => {
|
||||||
|
setFilterProps(idx, { condition: parseInt(e.target.value) });
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleFilterStateCallback = (props) => {
|
||||||
|
const currentFilterState = [...filterState];
|
||||||
|
currentFilterState.push({ ...props });
|
||||||
|
|
||||||
|
ui.setSearchTerm(
|
||||||
|
currentFilterState
|
||||||
|
.map((filter) => {
|
||||||
|
return filter.direction + ":" + filter.value;
|
||||||
|
})
|
||||||
|
.join("+")
|
||||||
|
);
|
||||||
|
|
||||||
|
setFilterState(currentFilterState);
|
||||||
|
};
|
||||||
|
if (subscriptionsCache.isLoading) return "";
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Flex
|
||||||
|
id="JournalNavigation"
|
||||||
|
height="100%"
|
||||||
|
maxH="100%"
|
||||||
|
overflow="hidden"
|
||||||
|
direction="column"
|
||||||
|
flexGrow={1}
|
||||||
|
>
|
||||||
|
{streamCache && !eventsIsLoading ? (
|
||||||
|
<>
|
||||||
|
<Drawer onClose={onClose} isOpen={isOpen} size="lg">
|
||||||
|
<DrawerOverlay />
|
||||||
|
<DrawerContent bgColor="gray.100">
|
||||||
|
<DrawerCloseButton />
|
||||||
|
<DrawerHeader>{`Filter results`}</DrawerHeader>
|
||||||
|
<DrawerBody>
|
||||||
|
<Text pt={2} fontWeight="600">
|
||||||
|
Source:
|
||||||
|
</Text>
|
||||||
|
{newFilterState.map((filter, idx) => {
|
||||||
|
if (filter.type === FILTER_TYPES.DISABLED) return "";
|
||||||
|
return (
|
||||||
|
<Flex
|
||||||
|
key={`subscription-filter-item-${idx}`}
|
||||||
|
direction="column"
|
||||||
|
>
|
||||||
|
<Flex
|
||||||
|
mt={4}
|
||||||
|
direction="row"
|
||||||
|
flexWrap="nowrap"
|
||||||
|
placeItems="center"
|
||||||
|
bgColor="gray.300"
|
||||||
|
borderRadius="md"
|
||||||
|
>
|
||||||
|
{filter.type === FILTER_TYPES.ADDRESS && (
|
||||||
|
<>
|
||||||
|
<Flex w="120px" placeContent="center">
|
||||||
|
{filter.direction === DIRECTIONS.SOURCE
|
||||||
|
? `From:`
|
||||||
|
: `To:`}
|
||||||
|
</Flex>
|
||||||
|
<Select
|
||||||
|
pr={2}
|
||||||
|
w="180px"
|
||||||
|
onChange={handleConditionChange(idx)}
|
||||||
|
>
|
||||||
|
<option value={CONDITION.EQUAL}>Is</option>
|
||||||
|
<option value={CONDITION.NOT_EQUAL}>
|
||||||
|
Is not
|
||||||
|
</option>
|
||||||
|
</Select>
|
||||||
|
{filter.direction === DIRECTIONS.SOURCE && (
|
||||||
|
<Select
|
||||||
|
variant="solid"
|
||||||
|
colorScheme="blue"
|
||||||
|
name="address"
|
||||||
|
onChange={handleAddressChange(idx)}
|
||||||
|
>
|
||||||
|
{!subscriptionsCache.isLoading &&
|
||||||
|
subscriptionsCache?.data?.subscriptions.map(
|
||||||
|
(subscription, idx) => {
|
||||||
|
return (
|
||||||
|
<option
|
||||||
|
value={subscription.address}
|
||||||
|
key={`subscription-filter-item-${idx}`}
|
||||||
|
>
|
||||||
|
{`${
|
||||||
|
subscription.label
|
||||||
|
} - ${subscription.address.slice(
|
||||||
|
0,
|
||||||
|
5
|
||||||
|
)}...${subscription.address.slice(
|
||||||
|
-3
|
||||||
|
)}`}
|
||||||
|
</option>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
)}
|
||||||
|
</Select>
|
||||||
|
)}
|
||||||
|
{filter.direction === DIRECTIONS.DESTINATION && (
|
||||||
|
<Input
|
||||||
|
type="text"
|
||||||
|
onChange={(e) =>
|
||||||
|
setFilterProps(idx, {
|
||||||
|
value: e.target.value,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
placeholder="Type in address"
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
</>
|
||||||
|
)}
|
||||||
|
<IconButton
|
||||||
|
placeItems="center"
|
||||||
|
colorScheme="blue"
|
||||||
|
variant="ghost"
|
||||||
|
onClick={() => dropNewFilterArrayItem(idx)}
|
||||||
|
icon={<ImCancelCircle />}
|
||||||
|
/>
|
||||||
|
</Flex>
|
||||||
|
</Flex>
|
||||||
|
);
|
||||||
|
})}
|
||||||
|
<Menu>
|
||||||
|
<MenuButton
|
||||||
|
as={Button}
|
||||||
|
mt={4}
|
||||||
|
colorScheme="orange"
|
||||||
|
variant="solid"
|
||||||
|
>
|
||||||
|
Add filter row
|
||||||
|
</MenuButton>
|
||||||
|
<MenuList>
|
||||||
|
<MenuGroup title="source"></MenuGroup>
|
||||||
|
<MenuItem
|
||||||
|
onClick={() =>
|
||||||
|
setNewFilterState([
|
||||||
|
...newFilterState,
|
||||||
|
{
|
||||||
|
type: FILTER_TYPES.ADDRESS,
|
||||||
|
direction: DIRECTIONS.SOURCE,
|
||||||
|
condition: CONDITION.EQUAL,
|
||||||
|
value:
|
||||||
|
subscriptionsCache?.data?.subscriptions[0]
|
||||||
|
?.address,
|
||||||
|
},
|
||||||
|
])
|
||||||
|
}
|
||||||
|
>
|
||||||
|
Source
|
||||||
|
</MenuItem>
|
||||||
|
<MenuItem
|
||||||
|
onClick={() =>
|
||||||
|
setNewFilterState([
|
||||||
|
...newFilterState,
|
||||||
|
{
|
||||||
|
type: FILTER_TYPES.ADDRESS,
|
||||||
|
direction: DIRECTIONS.DESTINATION,
|
||||||
|
condition: CONDITION.EQUAL,
|
||||||
|
value:
|
||||||
|
subscriptionsCache?.data?.subscriptions[0]
|
||||||
|
?.address,
|
||||||
|
},
|
||||||
|
])
|
||||||
|
}
|
||||||
|
>
|
||||||
|
Destination
|
||||||
|
</MenuItem>
|
||||||
|
</MenuList>
|
||||||
|
</Menu>
|
||||||
|
</DrawerBody>
|
||||||
|
<DrawerFooter pb={16} placeContent="center">
|
||||||
|
<Button
|
||||||
|
colorScheme="green"
|
||||||
|
variant="solid"
|
||||||
|
// type="submit"
|
||||||
|
onClick={() => handleFilterSubmit()}
|
||||||
|
>
|
||||||
|
Apply selected filters
|
||||||
|
</Button>
|
||||||
|
</DrawerFooter>
|
||||||
|
</DrawerContent>
|
||||||
|
</Drawer>
|
||||||
|
<Flex h="3rem" w="100%" bgColor="gray.100" alignItems="center">
|
||||||
|
<Flex maxW="90%">
|
||||||
|
{filterState.map((filter, idx) => {
|
||||||
|
if (filter.type === FILTER_TYPES.DISABLED) return "";
|
||||||
|
return (
|
||||||
|
<Tag
|
||||||
|
key={`filter-badge-display-${idx}`}
|
||||||
|
mx={1}
|
||||||
|
size="lg"
|
||||||
|
variant="solid"
|
||||||
|
colorScheme="orange"
|
||||||
|
>
|
||||||
|
{filter?.type === FILTER_TYPES.ADDRESS && (
|
||||||
|
<TagLabel>
|
||||||
|
{filter.condition === CONDITION.NOT_EQUAL && "Not "}
|
||||||
|
{filter.direction === DIRECTIONS.SOURCE
|
||||||
|
? "From: "
|
||||||
|
: "To: "}
|
||||||
|
{subscriptionsCache?.data?.subscriptions.find(
|
||||||
|
(subscription) =>
|
||||||
|
subscription.address === filter.value
|
||||||
|
)?.label ?? filter.value}
|
||||||
|
</TagLabel>
|
||||||
|
)}
|
||||||
|
|
||||||
|
<TagCloseButton onClick={() => dropFilterArrayItem(idx)} />
|
||||||
|
</Tag>
|
||||||
|
);
|
||||||
|
})}
|
||||||
|
</Flex>
|
||||||
|
<Spacer />
|
||||||
|
<IconButton
|
||||||
|
mr={4}
|
||||||
|
onClick={onOpen}
|
||||||
|
colorScheme="blue"
|
||||||
|
variant="ghost"
|
||||||
|
icon={<FaFilter />}
|
||||||
|
/>
|
||||||
|
</Flex>
|
||||||
|
|
||||||
|
<Flex
|
||||||
|
className="ScrollableWrapper"
|
||||||
|
w="100%"
|
||||||
|
overflowY="hidden"
|
||||||
|
h="calc(100% - 3rem)"
|
||||||
|
>
|
||||||
|
<Flex
|
||||||
|
className="Scrollable"
|
||||||
|
id="StreamEntry"
|
||||||
|
overflowY="scroll"
|
||||||
|
direction="column"
|
||||||
|
w="100%"
|
||||||
|
//onScroll={(e) => handleScroll(e)}
|
||||||
|
>
|
||||||
|
<Stack direction="row" justifyContent="space-between">
|
||||||
|
{!loadNewerEventsIsFetching && !nextEventIsFetching ? (
|
||||||
|
<Button
|
||||||
|
onClick={() => {
|
||||||
|
loadNewesEventHandler();
|
||||||
|
}}
|
||||||
|
variant="outline"
|
||||||
|
colorScheme="green"
|
||||||
|
>
|
||||||
|
Load newer events
|
||||||
|
</Button>
|
||||||
|
) : (
|
||||||
|
<Button
|
||||||
|
isLoading
|
||||||
|
loadingText="Loading"
|
||||||
|
variant="outline"
|
||||||
|
colorScheme="green"
|
||||||
|
></Button>
|
||||||
|
)}
|
||||||
|
</Stack>
|
||||||
|
{streamCache
|
||||||
|
.slice(
|
||||||
|
cursor,
|
||||||
|
streamCache.length <= cursor + PAGE_SIZE
|
||||||
|
? streamCache.length
|
||||||
|
: cursor + PAGE_SIZE
|
||||||
|
)
|
||||||
|
.map((entry, idx) => (
|
||||||
|
<StreamEntry
|
||||||
|
showOnboardingTooltips={false}
|
||||||
|
key={`entry-list-${idx}`}
|
||||||
|
entry={entry}
|
||||||
|
disableDelete={!canDelete}
|
||||||
|
disableCopy={!canCreate}
|
||||||
|
filterCallback={handleFilterStateCallback}
|
||||||
|
filterConstants={{ DIRECTIONS, CONDITION, FILTER_TYPES }}
|
||||||
|
/>
|
||||||
|
))}
|
||||||
|
{previousEvent &&
|
||||||
|
!loadOlderEventsIsFetching &&
|
||||||
|
!previousEventIsFetching ? (
|
||||||
|
<Center>
|
||||||
|
<Button
|
||||||
|
onClick={() => {
|
||||||
|
loadPreviousEventHandler();
|
||||||
|
}}
|
||||||
|
variant="outline"
|
||||||
|
colorScheme="green"
|
||||||
|
>
|
||||||
|
Load older events
|
||||||
|
</Button>
|
||||||
|
</Center>
|
||||||
|
) : (
|
||||||
|
<Center>
|
||||||
|
{!previousEventIsFetching && !loadOlderEventsIsFetching ? (
|
||||||
|
"Тransactions not found. You can subscribe to more addresses in Subscriptions menu."
|
||||||
|
) : (
|
||||||
|
<Button
|
||||||
|
isLoading
|
||||||
|
loadingText="Loading"
|
||||||
|
variant="outline"
|
||||||
|
colorScheme="green"
|
||||||
|
></Button>
|
||||||
|
)}
|
||||||
|
</Center>
|
||||||
|
)}
|
||||||
|
</Flex>
|
||||||
|
</Flex>
|
||||||
|
</>
|
||||||
|
) : (
|
||||||
|
<Center>
|
||||||
|
<Spinner
|
||||||
|
mt="50%"
|
||||||
|
size="lg"
|
||||||
|
color="blue.500"
|
||||||
|
thickness="4px"
|
||||||
|
speed="1.5s"
|
||||||
|
/>
|
||||||
|
</Center>
|
||||||
|
)}
|
||||||
|
</Flex>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default EntriesNavigation;
|
|
@ -1,7 +1,7 @@
|
||||||
import React from "react";
|
import React from "react";
|
||||||
import { ResponsiveLineCanvas } from "@nivo/line";
|
import { ResponsiveLineCanvas } from "@nivo/line";
|
||||||
|
|
||||||
const Report = ({ data, metric, timeRange }) => {
|
const Report = ({ data, timeRange }) => {
|
||||||
const commonProperties = {
|
const commonProperties = {
|
||||||
animate: false,
|
animate: false,
|
||||||
enableSlices: "x",
|
enableSlices: "x",
|
||||||
|
|
|
@ -24,7 +24,7 @@ import {
|
||||||
ArrowRightIcon,
|
ArrowRightIcon,
|
||||||
LockIcon,
|
LockIcon,
|
||||||
} from "@chakra-ui/icons";
|
} from "@chakra-ui/icons";
|
||||||
import { MdSettings, MdDashboard } from "react-icons/md";
|
import { MdSettings, MdDashboard, MdTimeline } from "react-icons/md";
|
||||||
import { WHITE_LOGO_W_TEXT_URL, ALL_NAV_PATHES } from "../core/constants";
|
import { WHITE_LOGO_W_TEXT_URL, ALL_NAV_PATHES } from "../core/constants";
|
||||||
import { v4 } from "uuid";
|
import { v4 } from "uuid";
|
||||||
import useDashboard from "../core/hooks/useDashboard";
|
import useDashboard from "../core/hooks/useDashboard";
|
||||||
|
@ -177,6 +177,9 @@ const Sidebar = () => {
|
||||||
<MenuItem icon={<MdSettings />}>
|
<MenuItem icon={<MdSettings />}>
|
||||||
<RouterLink href="/subscriptions">Subscriptions </RouterLink>
|
<RouterLink href="/subscriptions">Subscriptions </RouterLink>
|
||||||
</MenuItem>
|
</MenuItem>
|
||||||
|
<MenuItem icon={<MdTimeline />}>
|
||||||
|
<RouterLink href="/stream">Stream</RouterLink>
|
||||||
|
</MenuItem>
|
||||||
<Divider />
|
<Divider />
|
||||||
<Text
|
<Text
|
||||||
pt={4}
|
pt={4}
|
||||||
|
|
|
@ -0,0 +1,82 @@
|
||||||
|
import React from "react";
|
||||||
|
import { useBreakpointValue, Flex } from "@chakra-ui/react";
|
||||||
|
import SplitPane, { Pane } from "react-split-pane";
|
||||||
|
import { getLayout as getSiteLayout } from "./AppLayout";
|
||||||
|
import EntriesNavigation from "../components/EntriesNavigation";
|
||||||
|
import { useContext } from "react";
|
||||||
|
import UIContext from "../core/providers/UIProvider/context";
|
||||||
|
const EntriesLayout = (props) => {
|
||||||
|
const ui = useContext(UIContext);
|
||||||
|
const defaultWidth = useBreakpointValue({
|
||||||
|
base: "14rem",
|
||||||
|
sm: "16rem",
|
||||||
|
md: "18rem",
|
||||||
|
lg: "20rem",
|
||||||
|
xl: "22rem",
|
||||||
|
"2xl": "24rem",
|
||||||
|
});
|
||||||
|
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<Flex id="Entries" flexGrow={1} maxW="100%">
|
||||||
|
<SplitPane
|
||||||
|
allowResize={false}
|
||||||
|
split="vertical"
|
||||||
|
defaultSize={defaultWidth}
|
||||||
|
primary="first"
|
||||||
|
minSize={defaultWidth}
|
||||||
|
pane1Style={
|
||||||
|
ui.entriesViewMode === "list"
|
||||||
|
? { transition: "1s", width: "100%" }
|
||||||
|
: ui.entriesViewMode === "entry"
|
||||||
|
? { transition: "1s", width: "0%" }
|
||||||
|
: {
|
||||||
|
overflowX: "hidden",
|
||||||
|
height: "100%",
|
||||||
|
width: ui.isMobileView ? "100%" : "55%",
|
||||||
|
}
|
||||||
|
}
|
||||||
|
pane2Style={
|
||||||
|
ui.entriesViewMode === "entry"
|
||||||
|
? { transition: "1s", width: "0%" }
|
||||||
|
: ui.entriesViewMode === "list"
|
||||||
|
? {
|
||||||
|
transition: "1s",
|
||||||
|
width: "100%",
|
||||||
|
}
|
||||||
|
: { overflowX: "hidden", height: "100%" }
|
||||||
|
}
|
||||||
|
style={{
|
||||||
|
position: "relative",
|
||||||
|
height: "100%",
|
||||||
|
flexBasis: "100px",
|
||||||
|
overflowX: "hidden",
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<Pane
|
||||||
|
className="EntriesNavigation"
|
||||||
|
style={{
|
||||||
|
height: "100%",
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<EntriesNavigation />
|
||||||
|
</Pane>
|
||||||
|
|
||||||
|
<Pane
|
||||||
|
className="EntryScreen"
|
||||||
|
style={{
|
||||||
|
height: "100%",
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
{props.children}
|
||||||
|
</Pane>
|
||||||
|
</SplitPane>
|
||||||
|
</Flex>
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export const getLayout = (page) =>
|
||||||
|
getSiteLayout(<EntriesLayout>{page}</EntriesLayout>);
|
||||||
|
|
||||||
|
export default EntriesLayout;
|
Ładowanie…
Reference in New Issue