Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

F-nodeAsService-bufan #292

Merged
merged 2 commits into from
Jan 17, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion packages/client/dashboard/src/api/index.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import axios from 'axios'
import { UPLOAD_API_URL } from '../constants'

enum ApiRespCode {
export enum ApiRespCode {
SUCCESS = 0,
ERROR = 1,
}
Expand Down
59 changes: 59 additions & 0 deletions packages/client/dashboard/src/api/user.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
import axios, { AxiosPromise } from 'axios'
import { ApiResp } from '.'
import { APP_API_URL } from '../constants'
import { AccountType } from '../types.d'

export function getUserEmail(
didSession: string
): AxiosPromise<ApiResp<{ email: string }>> {
let host = APP_API_URL
return axios({
url: host + `/users/email`,
method: 'GET',
headers: {
'did-session': didSession,
},
})
}

export function postUserEmail(
didSession: string,
email: string,
): AxiosPromise<ApiResp<undefined>> {
if (!email) throw new Error('email id is required')

let host = APP_API_URL

return axios({
url: host + '/users/email',
method: 'POST',
headers: {
'did-session': didSession,
},
data: { email },
})
}

export function linkUserEmail(
didSession: string,
email: string,
code: string,
): AxiosPromise<ApiResp<undefined>> {
if (!email) throw new Error('email is required')
if (!code) throw new Error('code is required')

let host = APP_API_URL

return axios({
url: host + '/users/link',
method: 'POST',
headers: {
'did-session': didSession,
},
data: {
thirdpartyId: email,
code,
type: AccountType.EMAIL
},
})
}
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
export default function CheckCircleIcon({ bgc = '#5BA85A' }: { bgc?: string }) {
export default function CheckCircleIcon({ bgc = '#00b171' }: { bgc?: string }) {
return (
<svg
width="20"
Expand All @@ -7,10 +7,7 @@ export default function CheckCircleIcon({ bgc = '#5BA85A' }: { bgc?: string }) {
fill="none"
xmlns="http://www.w3.org/2000/svg"
>
<path
d="M10.0003 18.3327C14.6027 18.3327 18.3337 14.6017 18.3337 9.99935C18.3337 5.39698 14.6027 1.66602 10.0003 1.66602C5.39795 1.66602 1.66699 5.39698 1.66699 9.99935C1.66699 14.6017 5.39795 18.3327 10.0003 18.3327Z"
fill={bgc}
/>
<circle cx='10' cy='10' r='8' stroke={bgc} stroke-width='4' fill={bgc}/>
<path
d="M6.25 10L8.75 12.5L13.75 7.5"
stroke="white"
Expand Down
13 changes: 13 additions & 0 deletions packages/client/dashboard/src/components/icons/CircleIcon.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
export default function CircleIcon ({ bgc = '#5BA85A' }: { bgc?: string }) {
return (
<svg
width='20'
height='20'
viewBox='0 0 20 20'
fill='none'
xmlns='http://www.w3.org/2000/svg'
>
<circle cx='10' cy='10' r='8' stroke={bgc} stroke-width='4' />
</svg>
)
}
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@ import { createCeramicNode } from '../../api/ceramicNode'
import { CeramicDBType, CeramicNetwork } from '../../types.d'
import EnumSelect from '../common/EnumSelect'
import CloseIcon from '../icons/CloseIcon'
import UserEmail from './UserEmail'
import { EmailStatus } from '../../hooks/useUserAccount'

export default function CreateCeramicNodeModal ({
fixedNetwork,
Expand Down Expand Up @@ -60,8 +62,17 @@ export default function CreateCeramicNodeModal ({
} finally {
setSubmitting(false)
}
}, [submitting, session, signIn, nodeName, network, dbType, onSussess, closeModal])

}, [
submitting,
session,
signIn,
nodeName,
network,
dbType,
onSussess,
closeModal
])
const [userEmailVerified, setUserEmailVerified] = useState(false)
return (
<CreateBox>
<div className='title'>
Expand Down Expand Up @@ -100,6 +111,11 @@ export default function CreateCeramicNodeModal ({
</div>
Enable Historic Sync
</Checkbox>
<UserEmail
emailStatusChange={stutas =>
setUserEmailVerified(stutas === EmailStatus.VERIFIED)
}
/>
</EditorBox>
<div className='btns'>
<button onClick={closeModal}>Cancel</button>
Expand All @@ -108,14 +124,15 @@ export default function CreateCeramicNodeModal ({
<img src='/loading.gif' alt='' />
</button>
)) || (
<button className='submit' onClick={submit}>
<button className='submit' onClick={submit} disabled={!userEmailVerified}>
Submit
</button>
)}
</div>
</CreateBox>
)
}

const EditorBox = styled.div`
display: flex;
flex-direction: column;
Expand Down
187 changes: 187 additions & 0 deletions packages/client/dashboard/src/components/node/NodeStatus.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,187 @@
import styled from 'styled-components'
import { CeramicStatus } from '../../types.d'
import CircleIcon from '../icons/CircleIcon'
import CheckCircleIcon from '../icons/CheckCircleIcon'

import { ProgressBar, Label } from 'react-aria-components'
import { useEffect, useState } from 'react'

export default function NodeStatus ({
status,
}: {
status: CeramicStatus
}) {
const [prepageingPercentage, setPrepageingPercentage] = useState(0)
const [startingPercentage, setStartingPercentage] = useState(0)

useEffect(() => {
if (status !== CeramicStatus.PREPARING) return
if (prepageingPercentage < 100) {
console.log('set prepare timeout', prepageingPercentage)
setTimeout(() => {
setPrepageingPercentage(prepageingPercentage + 1)
}, 350)
}
}, [prepageingPercentage, status])

useEffect(() => {
if (status !== CeramicStatus.STARTING) return
if (startingPercentage < 100) {
console.log('set start timeout', startingPercentage)
setTimeout(() => {
setStartingPercentage(startingPercentage + 1)
}, 200)
}
}, [startingPercentage, status])

useEffect(() => {
switch (status) {
case CeramicStatus.PREPARING:
setPrepageingPercentage(0)
setStartingPercentage(0)
break
case CeramicStatus.STARTING:
setPrepageingPercentage(100)
setStartingPercentage(0)
break
case CeramicStatus.RUNNING:
setPrepageingPercentage(100)
setStartingPercentage(100)
break
default:
break
}
}, [status])

switch (status) {
case CeramicStatus.PREPARING:
return (
<Box>
<div>
<StepNode percentage={prepageingPercentage} />
<StepProgress percentage={prepageingPercentage} />
<StepNode />
<StepProgress />
<StepNode />
</div>
<div>
<Label className='green'>Preparing</Label>
<Label className='gray'>Start</Label>
<Label className='gray'>Run</Label>
</div>
</Box>
)
case CeramicStatus.STARTING:
return (
<Box>
<div>
<StepNode percentage={100} />
<StepProgress percentage={100} />
<StepNode percentage={startingPercentage} />
<StepProgress percentage={startingPercentage} />
<StepNode />
</div>
<div>
<Label className='green'>Prepared</Label>
<Label className='green'>Starting</Label>
<Label className='gray'>Run</Label>
</div>
</Box>
)
case CeramicStatus.RUNNING:
return (
<Box>
<div>
<StepNode percentage={100} />
<StepProgress percentage={100} />
<StepNode percentage={100} />
<StepProgress percentage={100} />
<StepNode percentage={1} />
</div>
<div>
<Label className='green'>Prepared</Label>
<Label className='green'>Started</Label>
<Label className='green'>Running</Label>
</div>
</Box>
)
default:
return null
}
}

const Box = styled.div`
width: 100%;
display: flex;
flex-direction: column;
gap: 10px;
> div {
width: 100%;
display: flex;
align-items: center;
gap: 10px;
justify-content: space-between;
}
.green {
color: #00b171;
}
.gray {
color: #718096;
}
label {
font-size: 12px;
font-weight: 500;
line-height: 1.2;
letter-spacing: 0.05em;
text-transform: uppercase;
}
.react-aria-ProgressBar {
display: grid;
grid-template-areas: "label value"
"bar bar";
grid-template-columns: 1fr auto;
color: var(--text-color);
flex: 1;
.value {
grid-area: value;
}

.bar {
grid-area: bar;
box-shadow: inset 0px 0px 0px 1px #718096;
forced-color-adjust: none;
height: 2px;
overflow: hidden;
will-change: transform;
}

.fill {
background: #00b171;
height: 100%;
}
}
`
function StepNode ({ percentage = 0 }: { percentage?: number }) {
if (percentage === 0) {
return <CircleIcon bgc='#718096' />
} else if (percentage < 100) {
return <CircleIcon bgc='#00B171' />
} else if (percentage >= 100) {
return <CheckCircleIcon />
}
return null
}
function StepProgress ({ percentage = 0 }: { percentage?: number }) {
return (
<ProgressBar value={percentage}>
{({ percentage, valueText }) => (
<>
{/* <span className='value'>{valueText}</span> */}
<div className='bar'>
<div className='fill' style={{ width: percentage + '%' }} />
</div>
</>
)}
</ProgressBar>
)
}
Loading