Skip to content

Commit 0fc42ac

Browse files
authored
Merge pull request #2656 from devtron-labs/feat/migrate-activate-license
feat: add activate license page in dashboard
2 parents ad26cb8 + 291464c commit 0fc42ac

File tree

6 files changed

+175
-14
lines changed

6 files changed

+175
-14
lines changed

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
"private": true,
55
"homepage": "/dashboard",
66
"dependencies": {
7-
"@devtron-labs/devtron-fe-common-lib": "1.11.0",
7+
"@devtron-labs/devtron-fe-common-lib": "1.11.1",
88
"@esbuild-plugins/node-globals-polyfill": "0.2.3",
99
"@rjsf/core": "^5.13.3",
1010
"@rjsf/utils": "^5.13.3",

src/App.tsx

Lines changed: 5 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -42,11 +42,11 @@ import {
4242
} from './components/common'
4343
import { UPDATE_AVAILABLE_TOAST_PROGRESS_BG, URLS } from './config'
4444
import { validateToken } from './services/service'
45+
import ActivateLicense from '@Pages/License/ActivateLicense'
4546

4647
const NavigationRoutes = lazy(() => import('./components/common/navigation/NavigationRoutes'))
4748
const Login = lazy(() => import('./components/login/Login'))
4849
const GenericDirectApprovalModal = importComponentFromFELibrary('GenericDirectApprovalModal')
49-
const ActivateLicense = importComponentFromFELibrary('ActivateLicense', null, 'function')
5050

5151
export default function App() {
5252
const onlineToastRef = useRef(null)
@@ -160,7 +160,6 @@ export default function App() {
160160
}
161161

162162
useEffect(() => {
163-
164163
if (navigator.serviceWorker) {
165164
navigator.serviceWorker.addEventListener('controllerchange', handleControllerChange)
166165
}
@@ -328,7 +327,7 @@ export default function App() {
328327
<div className="full-height-width bg__tertiary">
329328
<Reload />
330329
</div>
331-
) : (
330+
) : (
332331
<ErrorBoundary>
333332
<BreadcrumbStore>
334333
<Switch>
@@ -340,11 +339,9 @@ export default function App() {
340339
/>
341340
</Route>
342341
)}
343-
{ActivateLicense && (
344-
<Route path={CommonURLS.LICENSE_AUTH}>
345-
<ActivateLicense />
346-
</Route>
347-
)}
342+
<Route path={CommonURLS.LICENSE_AUTH}>
343+
<ActivateLicense />
344+
</Route>
348345
{!window._env_.K8S_CLIENT && <Route path="/login" component={Login} />}
349346
<Route path="/" render={() => <NavigationRoutes />} />
350347
<Redirect

src/Pages/License/ActivateLicense.tsx

Lines changed: 143 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,143 @@
1+
import {
2+
useTheme,
3+
LicensingErrorCodes,
4+
Button,
5+
ButtonVariantType,
6+
DevtronLicenseCard,
7+
DevtronProgressing,
8+
ENTERPRISE_SUPPORT_LINK,
9+
ErrorScreenManager,
10+
Icon,
11+
InfoBlock,
12+
LoginBanner,
13+
URLS,
14+
useAsync,
15+
getHandleOpenURL,
16+
CONTACT_SUPPORT_LINK,
17+
ActivateLicenseDialog,
18+
ICDevtronWithBorder,
19+
API_STATUS_CODES,
20+
} from '@devtron-labs/devtron-fe-common-lib'
21+
import { useEffect, useState } from 'react'
22+
import { useHistory } from 'react-router-dom'
23+
import { getDevtronLicenseInfo } from './service'
24+
25+
const ActivateLicense = () => {
26+
const history = useHistory()
27+
const [isLoading, licenseData, licenseDataError, reloadLicenseData] = useAsync(getDevtronLicenseInfo, [])
28+
const [showActivateDialog, setShowActivateDialog] = useState<boolean>(false)
29+
const { appTheme } = useTheme()
30+
31+
const redirectToLogin = () => {
32+
history.replace(URLS.LOGIN_SSO)
33+
}
34+
35+
useEffect(() => {
36+
if (isLoading) {
37+
return
38+
}
39+
40+
// licenseDataError.code === 404 means, oss and licensing does not exist
41+
// In case licenseStatusError is null, license is valid
42+
if (licenseDataError?.code === API_STATUS_CODES.NOT_FOUND || !licenseData.licenseStatusError) {
43+
redirectToLogin()
44+
return
45+
}
46+
47+
if (licenseData.licenseStatusError.code === LicensingErrorCodes.LicKeyNotFound) {
48+
setShowActivateDialog(true)
49+
}
50+
}, [isLoading, licenseData])
51+
52+
if (isLoading) {
53+
return <DevtronProgressing parentClasses="bg__primary flex full-height-width" classes="icon-dim-80" />
54+
}
55+
56+
if (licenseDataError) {
57+
return (
58+
<div className="full-height-width bg__tertiary">
59+
<ErrorScreenManager code={licenseDataError?.code} reload={reloadLicenseData} />
60+
</div>
61+
)
62+
}
63+
64+
const handleChangeLicense = () => {
65+
setShowActivateDialog(true)
66+
}
67+
68+
const renderInvalidLicenseDialog = () => (
69+
<div className="flexbox-col p-36 dc__gap-32 w-400 border__primary br-12">
70+
<div className="flexbox-col dc__gap-20">
71+
<ICDevtronWithBorder />
72+
<div className="flexbox-col dc__gap-4">
73+
<div className="fs-20 lh-1-5 fw-7 cn-9 font-merriweather dc__truncate">
74+
{licenseData.enterpriseName}
75+
</div>
76+
<div className="fs-16 lh-1-5 cr-5 fw-4">Your license key is no longer valid</div>
77+
</div>
78+
</div>
79+
{licenseData.licenseStatusError &&
80+
licenseData.licenseStatusError.code !== LicensingErrorCodes.LicenseExpired ? (
81+
<InfoBlock
82+
heading="Need help?"
83+
description={
84+
<span>
85+
For further details mail us at&nbsp;
86+
<a href={`mailto:${ENTERPRISE_SUPPORT_LINK}`}>{ENTERPRISE_SUPPORT_LINK}</a> or contact
87+
Devtron Support
88+
</span>
89+
}
90+
variant="help"
91+
buttonProps={{
92+
text: 'Contact Support',
93+
variant: ButtonVariantType.text,
94+
onClick: getHandleOpenURL(CONTACT_SUPPORT_LINK),
95+
dataTestId: 'contact-support',
96+
startIcon: <Icon name="ic-chat-circle-dots" color="B500" size={16} />,
97+
}}
98+
layout="column"
99+
/>
100+
) : (
101+
<DevtronLicenseCard
102+
enterpriseName={licenseData.enterpriseName}
103+
expiryDate={licenseData.expiryDate}
104+
ttl={licenseData.ttl}
105+
licenseStatus={licenseData.licenseStatus}
106+
isTrial={licenseData.isTrial}
107+
licenseSuffix={licenseData.licenseSuffix}
108+
appTheme={appTheme}
109+
/>
110+
)}
111+
<div className="flex dc__content-space">
112+
<span>Have another license key?</span>
113+
<Button
114+
dataTestId="change-license"
115+
text="Change license"
116+
variant={ButtonVariantType.text}
117+
onClick={handleChangeLicense}
118+
/>
119+
</div>
120+
</div>
121+
)
122+
123+
return (
124+
<div className="full-height-width bg__secondary dc__grid-half">
125+
<div className="flexbox p-16">
126+
<LoginBanner />
127+
</div>
128+
<div className="flex">
129+
{showActivateDialog ? (
130+
<ActivateLicenseDialog
131+
fingerprint={licenseData.fingerprint || ''}
132+
enterpriseName={licenseData.enterpriseName}
133+
handleLicenseActivateSuccess={redirectToLogin}
134+
/>
135+
) : (
136+
renderInvalidLicenseDialog()
137+
)}
138+
</div>
139+
</div>
140+
)
141+
}
142+
143+
export default ActivateLicense

src/Pages/License/service.tsx

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
// NOTE: This API is used to check if the license is valid or not at APP.TSX level
2+
3+
import {
4+
DevtronLicenseDTO,
5+
DevtronLicenseInfo,
6+
get,
7+
parseDevtronLicenseData,
8+
ROUTES,
9+
} from '@devtron-labs/devtron-fe-common-lib'
10+
11+
// Only gives complete response if the license is invalid else return only fingerprint
12+
export const getDevtronLicenseInfo = async (): Promise<DevtronLicenseInfo> => {
13+
const { result } = await get<DevtronLicenseDTO>(ROUTES.LICENSE_DATA, { preventLicenseRedirect: true })
14+
return parseDevtronLicenseData(result)
15+
}

src/components/globalConfigurations/GlobalConfiguration.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -283,7 +283,7 @@ const NavItem = ({ serverMode }) => {
283283
moduleName: ModuleNameMap.NOTIFICATION,
284284
isAvailableInEA: false,
285285
},
286-
...(window._env_.FEATURE_APPLICATION_TEMPLATES_ENABLE
286+
...(window._env_.FEATURE_APPLICATION_TEMPLATES_ENABLE && DevtronAppTemplates
287287
? [
288288
{
289289
name: 'Application Templates',

yarn.lock

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1126,10 +1126,10 @@
11261126
dependencies:
11271127
"@jridgewell/trace-mapping" "0.3.9"
11281128

1129-
"@devtron-labs/[email protected].0":
1130-
version "1.11.0"
1131-
resolved "https://registry.yarnpkg.com/@devtron-labs/devtron-fe-common-lib/-/devtron-fe-common-lib-1.11.0.tgz#1cf1ae310119b5b0c1c8bb3d162cf291951b84bf"
1132-
integrity sha512-JRJEqnuUBcfoqEQ7x/5Oqx+HcYxNmAQAZd/++Rf2F2mvslS1UFsbA8e6irRnGSmzUuksAX5OnARXnM1VOZNIsw==
1129+
"@devtron-labs/[email protected].1":
1130+
version "1.11.1"
1131+
resolved "https://registry.yarnpkg.com/@devtron-labs/devtron-fe-common-lib/-/devtron-fe-common-lib-1.11.1.tgz#7688b6879941c4109e7b35190917fc3f999f67aa"
1132+
integrity sha512-+jio49ygf+Wq2L2Pdp17XtA1IkhNoR34gIe5JyhwDO2QK+ct4eqqeOQejYZxEHZKnAoXME8u3/1sUX6k3i/cxQ==
11331133
dependencies:
11341134
"@codemirror/lang-json" "6.0.1"
11351135
"@codemirror/lang-yaml" "6.1.2"
@@ -1154,6 +1154,7 @@
11541154
jsonpath-plus "^10.3.0"
11551155
marked "^13.0.3"
11561156
nanoid "^3.3.8"
1157+
qrcode.react "^4.2.0"
11571158
react-canvas-confetti "^2.0.7"
11581159
react-dates "^21.8.0"
11591160
react-diff-viewer-continued "^3.4.0"
@@ -7260,6 +7261,11 @@ punycode@^2.1.0:
72607261
resolved "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz"
72617262
integrity sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==
72627263

7264+
qrcode.react@^4.2.0:
7265+
version "4.2.0"
7266+
resolved "https://registry.yarnpkg.com/qrcode.react/-/qrcode.react-4.2.0.tgz#1bce8363f348197d145c0da640929a24c83cbca3"
7267+
integrity sha512-QpgqWi8rD9DsS9EP3z7BT+5lY5SFhsqGjpgW5DY/i3mK4M9DTBNz3ErMi8BWYEfI3L0d8GIbGmcdFAS1uIRGjA==
7268+
72637269
query-string@^7.1.1:
72647270
version "7.1.3"
72657271
resolved "https://registry.npmjs.org/query-string/-/query-string-7.1.3.tgz"

0 commit comments

Comments
 (0)