Skip to content
This repository has been archived by the owner on Oct 12, 2023. It is now read-only.

Commit

Permalink
Add per-service charts
Browse files Browse the repository at this point in the history
  • Loading branch information
raymondjacobson committed Feb 9, 2022
1 parent 01b648e commit ccc078e
Show file tree
Hide file tree
Showing 10 changed files with 310 additions and 95 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
import LineChart from 'components/LineChart'
import React, { useState } from 'react'
import { useIndividualServiceApiCalls } from 'store/cache/analytics/hooks'
import { Bucket, MetricError } from 'store/cache/analytics/slice'

type OwnProps = {
node: string
}

type IndividualServiceApiCallsChartProps = OwnProps

const IndividualServiceApiCallsChart: React.FC<IndividualServiceApiCallsChartProps> = ({
node
}) => {
const [bucket, setBucket] = useState(Bucket.MONTH)

const { apiCalls } = useIndividualServiceApiCalls(node, bucket)
let error, labels, data
if (apiCalls === MetricError.ERROR) {
error = true
labels = []
data = []
} else {
labels =
apiCalls?.map(
a => new Date(parseInt(a.timestamp, 10) * 1000).getTime() / 1000
) ?? null
data = apiCalls?.map(a => a.count) ?? null
}
return (
<LineChart
title="API Calls"
tooltipTitle="API Calls"
error={error}
data={data}
labels={labels}
selection={bucket}
options={[Bucket.ALL_TIME, Bucket.MONTH, Bucket.WEEK]}
onSelectOption={(option: string) => setBucket(option as Bucket)}
showLeadingDay
/>
)
}

export default IndividualServiceApiCallsChart
1 change: 1 addition & 0 deletions src/components/IndividualServiceApiCallsChart/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export { default } from './IndividualServiceApiCallsChart'
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
import LineChart from 'components/LineChart'
import React, { useState } from 'react'
import { useIndividualServiceApiCalls } from 'store/cache/analytics/hooks'
import { Bucket, MetricError } from 'store/cache/analytics/slice'

type OwnProps = {
node: string
}

type IndividualServiceUniqueUsersChartProps = OwnProps

const IndividualServiceUniqueUsersChart: React.FC<IndividualServiceUniqueUsersChartProps> = ({
node
}) => {
const [bucket, setBucket] = useState(Bucket.MONTH)

const { apiCalls } = useIndividualServiceApiCalls(node, bucket)
let error, labels, data
if (apiCalls === MetricError.ERROR) {
error = true
labels = []
data = []
} else {
labels =
apiCalls?.map(
a => new Date(parseInt(a.timestamp, 10) * 1000).getTime() / 1000
) ?? null
data = apiCalls?.map(a => a.unique_count) ?? null
}
return (
<LineChart
title="Unique Users"
tooltipTitle="Unique Users"
error={error}
data={data}
labels={labels}
selection={bucket}
options={[Bucket.ALL_TIME, Bucket.MONTH, Bucket.WEEK]}
onSelectOption={(option: string) => setBucket(option as Bucket)}
showLeadingDay
/>
)
}

export default IndividualServiceUniqueUsersChart
1 change: 1 addition & 0 deletions src/components/IndividualServiceUniqueUsersChart/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export { default } from './IndividualServiceUniqueUsersChart'
7 changes: 7 additions & 0 deletions src/components/NodeOverview/NodeOverview.module.css
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,13 @@
display: inline-flex;
flex-direction: column;
box-sizing: border-box;
min-height: 240px;
}

.loading {
margin: 42px auto 0;
justify-content: center;
align-items: center;
}

.header {
Expand Down
111 changes: 66 additions & 45 deletions src/components/NodeOverview/NodeOverview.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import { useModalControls } from 'utils/hooks'
import desktopStyles from './NodeOverview.module.css'
import mobileStyles from './NodeOverviewMobile.module.css'
import { createStyles } from 'utils/mobile'
import Loading from 'components/Loading'

const styles = createStyles({ desktopStyles, mobileStyles })

Expand All @@ -36,14 +37,15 @@ const ServiceDetail = ({ label, value }: { label: string; value: string }) => {
}

type NodeOverviewProps = {
spID: number
serviceType: ServiceType
version: string
endpoint: string
operatorWallet: Address
delegateOwnerWallet: Address
isOwner: boolean
isDeregistered: boolean
spID?: number
serviceType?: ServiceType
version?: string
endpoint?: string
operatorWallet?: Address
delegateOwnerWallet?: Address
isOwner?: boolean
isDeregistered?: boolean
isLoading: boolean
}

const NodeOverview = ({
Expand All @@ -54,50 +56,69 @@ const NodeOverview = ({
operatorWallet,
delegateOwnerWallet,
isOwner,
isDeregistered
isDeregistered,
isLoading
}: NodeOverviewProps) => {
const { isOpen, onClick, onClose } = useModalControls()

return (
<Paper className={styles.container}>
<div className={styles.header}>
<div className={styles.serviceType}>
{serviceType === ServiceType.DiscoveryProvider
? messages.dp
: messages.cn}
</div>
{isDeregistered ? (
<div className={styles.deregistered}>{messages.deregistered}</div>
) : (
<div className={styles.version}>
{`${messages.version} ${version}`}
{isLoading ? (
<Loading className={styles.loading} />
) : (
<>
<div className={styles.header}>
<div className={styles.serviceType}>
{serviceType === ServiceType.DiscoveryProvider
? messages.dp
: messages.cn}
</div>
{isDeregistered ? (
<div className={styles.deregistered}>{messages.deregistered}</div>
) : (
<div className={styles.version}>
{`${messages.version} ${version || ''}`}
</div>
)}
{isOwner &&
!isDeregistered &&
spID &&
endpoint &&
serviceType &&
delegateOwnerWallet && (
<>
<Button
onClick={onClick}
leftIcon={<IconPencil />}
type={ButtonType.PRIMARY_ALT}
text={messages.modify}
className={clsx(styles.modifyBtn)}
textClassName={styles.modifyBtnText}
/>
<ModifyServiceModal
isOpen={isOpen}
onClose={onClose}
spID={spID}
serviceType={serviceType}
endpoint={endpoint}
delegateOwnerWallet={delegateOwnerWallet}
/>
</>
)}
</div>
)}
{isOwner && !isDeregistered && (
<>
<Button
onClick={onClick}
leftIcon={<IconPencil />}
type={ButtonType.PRIMARY_ALT}
text={messages.modify}
className={clsx(styles.modifyBtn)}
textClassName={styles.modifyBtnText}
{endpoint ? (
<ServiceDetail label={messages.endpoint} value={endpoint} />
) : null}
{operatorWallet ? (
<ServiceDetail label={messages.operator} value={operatorWallet} />
) : null}
{delegateOwnerWallet ? (
<ServiceDetail
label={messages.delegate}
value={delegateOwnerWallet}
/>
<ModifyServiceModal
isOpen={isOpen}
onClose={onClose}
spID={spID}
serviceType={serviceType}
endpoint={endpoint}
delegateOwnerWallet={delegateOwnerWallet}
/>
</>
)}
</div>
<ServiceDetail label={messages.endpoint} value={endpoint} />
<ServiceDetail label={messages.operator} value={operatorWallet} />
{delegateOwnerWallet && (
<ServiceDetail label={messages.delegate} value={delegateOwnerWallet} />
) : null}
</>
)}
</Paper>
)
Expand Down
17 changes: 16 additions & 1 deletion src/containers/Node/Node.module.css
Original file line number Diff line number Diff line change
@@ -1,4 +1,19 @@
.container {
display: inline-flex;
width: 100%;
}

.section {
margin-bottom: 16px;
display: flex;
margin-left: -8px;
margin-right: -8px;
}

.section > * {
width: 100%;
margin: 0 8px;
}

.chart {
min-height: 340px;
}
64 changes: 37 additions & 27 deletions src/containers/Node/Node.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,9 @@ import {
SERVICES,
NOT_FOUND
} from 'utils/routes'
import IndividualServiceApiCallsChart from 'components/IndividualServiceApiCallsChart'
import clsx from 'clsx'
import IndividualServiceUniqueUsersChart from 'components/IndividualServiceUniqueUsersChart'

const messages = {
title: 'SERVICE',
Expand All @@ -32,57 +35,64 @@ const ContentNode: React.FC<ContentNodeProps> = ({

if (status === Status.Failure) {
return null
} else if (status === Status.Loading) {
return null
}

// TODO: compare owner with the current user
const isOwner = accountWallet === contentNode!.owner
const isOwner = accountWallet === contentNode?.owner ?? false

return (
<NodeOverview
spID={spID}
serviceType={ServiceType.ContentNode}
version={contentNode!.version}
endpoint={contentNode!.endpoint}
operatorWallet={contentNode!.owner}
delegateOwnerWallet={contentNode!.delegateOwnerWallet}
version={contentNode?.version}
endpoint={contentNode?.endpoint}
operatorWallet={contentNode?.owner}
delegateOwnerWallet={contentNode?.delegateOwnerWallet}
isOwner={isOwner}
isDeregistered={contentNode!.isDeregistered}
isDeregistered={contentNode?.isDeregistered}
isLoading={status === Status.Loading}
/>
)
}

type DiscoveryProviderProps = {
type DiscoveryNodeProps = {
spID: number
accountWallet: Address | undefined
}
const DiscoveryProvider: React.FC<DiscoveryProviderProps> = ({
const DiscoveryNode: React.FC<DiscoveryNodeProps> = ({
spID,
accountWallet
}: DiscoveryProviderProps) => {
const { node: discoveryProvider, status } = useDiscoveryProvider({ spID })
}: DiscoveryNodeProps) => {
const { node: discoveryNode, status } = useDiscoveryProvider({ spID })
const pushRoute = usePushRoute()
if (status === Status.Failure) {
pushRoute(NOT_FOUND)
return null
} else if (status === Status.Loading) {
return null
}

const isOwner = accountWallet === discoveryProvider!.owner
const isOwner = accountWallet === discoveryNode?.owner ?? false

return (
<NodeOverview
spID={spID}
serviceType={ServiceType.DiscoveryProvider}
version={discoveryProvider!.version}
endpoint={discoveryProvider!.endpoint}
operatorWallet={discoveryProvider!.owner}
delegateOwnerWallet={discoveryProvider!.delegateOwnerWallet}
isOwner={isOwner}
isDeregistered={discoveryProvider!.isDeregistered}
/>
<>
<div className={styles.section}>
<NodeOverview
spID={spID}
serviceType={ServiceType.DiscoveryProvider}
version={discoveryNode?.version}
endpoint={discoveryNode?.endpoint}
operatorWallet={discoveryNode?.owner}
delegateOwnerWallet={discoveryNode?.delegateOwnerWallet}
isOwner={isOwner}
isDeregistered={discoveryNode?.isDeregistered}
isLoading={status === Status.Loading}
/>
</div>
{discoveryNode ? (
<div className={clsx(styles.section, styles.chart)}>
<IndividualServiceApiCallsChart node={discoveryNode?.endpoint} />
<IndividualServiceUniqueUsersChart node={discoveryNode?.endpoint} />
</div>
) : null}
</>
)
}

Expand All @@ -107,7 +117,7 @@ const Node: React.FC<NodeProps> = (props: NodeProps) => {
defaultPreviousPageRoute={SERVICES}
>
{isDiscovery ? (
<DiscoveryProvider spID={spID} accountWallet={accountWallet} />
<DiscoveryNode spID={spID} accountWallet={accountWallet} />
) : (
<ContentNode spID={spID} accountWallet={accountWallet} />
)}
Expand Down
Loading

0 comments on commit ccc078e

Please sign in to comment.