-
-
Notifications
You must be signed in to change notification settings - Fork 728
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
wip: license checker for self-hosted
- Loading branch information
Showing
7 changed files
with
274 additions
and
1 deletion.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,140 @@ | ||
import { PageContent } from 'component/common/PageContent/PageContent'; | ||
import { PageHeader } from 'component/common/PageHeader/PageHeader'; | ||
import { Box, Button, Grid, TextField, styled } from '@mui/material'; | ||
import useUiConfig from 'hooks/api/getters/useUiConfig/useUiConfig'; | ||
import { useLicense, useLicenseCheck } from 'hooks/api/getters/useLicense/useLicense'; | ||
import { formatDateYMD } from 'utils/formatDate'; | ||
import { useLocationSettings } from 'hooks/useLocationSettings'; | ||
import { useState } from 'react'; | ||
import useToast from 'hooks/useToast'; | ||
import { formatUnknownError } from 'utils/formatUnknownError'; | ||
import useUpdateLicenseKeyApi from 'hooks/api/actions/useLicenseAPI/useLicenseApi'; | ||
|
||
|
||
const StyledBox = styled(Box)(({ theme }) => ({ | ||
display: 'grid', | ||
gap: theme.spacing(4), | ||
})); | ||
|
||
const StyledDataCollectionPropertyRow = styled('div')(() => ({ | ||
display: 'table-row', | ||
})); | ||
|
||
const StyledPropertyName = styled('p')(({ theme }) => ({ | ||
display: 'table-cell', | ||
fontWeight: theme.fontWeight.bold, | ||
paddingTop: theme.spacing(2), | ||
})); | ||
|
||
const StyledPropertyDetails = styled('p')(({ theme }) => ({ | ||
display: 'table-cell', | ||
paddingTop: theme.spacing(2), | ||
paddingLeft: theme.spacing(4), | ||
})); | ||
|
||
|
||
|
||
|
||
|
||
export const License = () => { | ||
const { setToastData, setToastApiError } = useToast(); | ||
const { license, error, refetchLicense } = useLicense(); | ||
const { reCheckLicense } = useLicenseCheck(); | ||
const { loading } = useUiConfig(); | ||
const { locationSettings } = useLocationSettings(); | ||
const [token, setToken] = useState(''); | ||
const { updateLicenseKey } = useUpdateLicenseKeyApi(); | ||
|
||
const updateToken = (event: React.ChangeEvent<HTMLInputElement>) => { | ||
setToken(event.target.value.trim()); | ||
}; | ||
|
||
if (loading || !license) { | ||
return null; | ||
} | ||
|
||
const onSubmit = async (event: React.SyntheticEvent) => { | ||
event.preventDefault(); | ||
|
||
try { | ||
await updateLicenseKey(token); | ||
setToastData({ | ||
title: 'License key updated', | ||
type: 'success', | ||
}); | ||
refetchLicense(); | ||
reCheckLicense (); | ||
} catch (error: unknown) { | ||
setToastApiError(formatUnknownError(error)); | ||
} | ||
}; | ||
|
||
return ( | ||
<PageContent header={<PageHeader title='Unleash Enterprise License' />}> | ||
<StyledBox> | ||
{license.token ? <div> | ||
<StyledDataCollectionPropertyRow> | ||
<StyledPropertyName>Customer</StyledPropertyName> | ||
<StyledPropertyDetails> | ||
{license?.customer} | ||
</StyledPropertyDetails> | ||
</StyledDataCollectionPropertyRow> | ||
<StyledDataCollectionPropertyRow> | ||
<StyledPropertyName>Plan</StyledPropertyName> | ||
<StyledPropertyDetails> | ||
{license?.plan} | ||
</StyledPropertyDetails> | ||
</StyledDataCollectionPropertyRow> | ||
<StyledDataCollectionPropertyRow> | ||
<StyledPropertyName>Seats</StyledPropertyName> | ||
<StyledPropertyDetails> | ||
{license?.seats} | ||
</StyledPropertyDetails> | ||
</StyledDataCollectionPropertyRow> | ||
<StyledDataCollectionPropertyRow> | ||
<StyledPropertyName>Expire at</StyledPropertyName> | ||
<StyledPropertyDetails> | ||
{formatDateYMD(license.expireAt, locationSettings.locale)} | ||
</StyledPropertyDetails> | ||
</StyledDataCollectionPropertyRow> | ||
</div>: <p>You do not have a registered Unleash Enterprise License.</p>} | ||
|
||
|
||
<form onSubmit={onSubmit}> | ||
<TextField | ||
onChange={updateToken} | ||
label='New License Key' | ||
name='licenseKey' | ||
value={token} | ||
style={{ width: '100%' }} | ||
variant='outlined' | ||
size='small' | ||
multiline | ||
rows={6} | ||
required | ||
/> | ||
<br /><br /> | ||
|
||
<Grid container spacing={3}> | ||
<Grid item md={5}> | ||
<Button | ||
variant='contained' | ||
color='primary' | ||
type='submit' | ||
disabled={loading} | ||
> | ||
Update License Key | ||
</Button>{' '} | ||
<p> | ||
<small style={{ color: 'red' }}> | ||
{error?.message} | ||
</small> | ||
</p> | ||
</Grid> | ||
</Grid> | ||
</form> | ||
|
||
</StyledBox> | ||
</PageContent> | ||
); | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
37 changes: 37 additions & 0 deletions
37
frontend/src/hooks/api/actions/useLicenseAPI/useLicenseApi.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,37 @@ | ||
import { Dispatch, SetStateAction } from 'react'; | ||
import useAPI from '../useApi/useApi'; | ||
|
||
export const handleBadRequest = async ( | ||
setErrors?: Dispatch<SetStateAction<{}>>, | ||
res?: Response, | ||
) => { | ||
if (!setErrors) return; | ||
if (res) { | ||
const data = await res.json(); | ||
setErrors({ message: data.message }); | ||
throw new Error(data.message); | ||
} | ||
|
||
throw new Error(); | ||
}; | ||
|
||
const useUpdateLicenseKeyApi = () => { | ||
const { makeRequest, createRequest, errors, loading } = useAPI({ | ||
propagateErrors: true, | ||
handleBadRequest, | ||
}); | ||
|
||
const updateLicenseKey = async (token: string): Promise<void> => { | ||
const path = `api/admin/license`; | ||
const req = createRequest(path, { | ||
method: 'POST', | ||
body: JSON.stringify({ token }), | ||
}); | ||
|
||
await makeRequest(req.caller, req.id); | ||
}; | ||
|
||
return { updateLicenseKey, errors, loading }; | ||
}; | ||
|
||
export default useUpdateLicenseKeyApi; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,70 @@ | ||
import useSWR from 'swr'; | ||
import { useMemo } from 'react'; | ||
import { formatApiPath } from 'utils/formatPath'; | ||
import handleErrorResponses from '../httpErrorResponseHandler'; | ||
import useUiConfig from '../useUiConfig/useUiConfig'; | ||
import { useConditionalSWR } from '../useConditionalSWR/useConditionalSWR'; | ||
import { useEnterpriseSWR } from '../useEnterpriseSWR/useEnterpriseSWR'; | ||
|
||
export interface LicenseInfo { | ||
isValid: boolean; | ||
message?: string; | ||
loading: boolean; | ||
reCheckLicense: () => void; | ||
error?: Error; | ||
} | ||
|
||
const fallback = { | ||
isValid: true, | ||
message: '', | ||
loading: false, | ||
}; | ||
|
||
export interface License { | ||
license?: { | ||
token: string; | ||
customer: string; | ||
plan: string; | ||
seats: number; | ||
expireAt: Date; | ||
}; | ||
loading: boolean; | ||
refetchLicense: () => void; | ||
error?: Error; | ||
} | ||
|
||
export const useLicenseCheck = (): LicenseInfo => { | ||
const { data, error, mutate } = useEnterpriseSWR( | ||
fallback, | ||
formatApiPath(`api/admin/license/check`), | ||
fetcher, | ||
); | ||
|
||
return { | ||
isValid: data?.isValid, | ||
message: data?.message, | ||
loading: !error && !data, | ||
reCheckLicense: () => mutate(), | ||
error, | ||
}; | ||
}; | ||
|
||
export const useLicense = (): License => { | ||
const { data, error, mutate } = useSWR( | ||
formatApiPath(`api/admin/license`), | ||
fetcher, | ||
); | ||
|
||
return { | ||
license: { ...data }, | ||
loading: !error && !data, | ||
refetchLicense: () => mutate(), | ||
error, | ||
}; | ||
}; | ||
|
||
const fetcher = (path: string) => { | ||
return fetch(path) | ||
.then(handleErrorResponses('License')) | ||
.then((res) => res.json()); | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters