-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
RS-180: Web console shows license information (#64)
* license component and alert with sample data * refactor usage statistics in seperated component * add tabs to seperate usage and license * update tablist default value * update helper function to convert bigInt * remove sample and show real license details * show license expiryDate in local format * test license display * test usage statistics and big int number * update reduct-js to 1.9.2 * update changelog * license alert with over-time or over-quota * update license details * test license information * add alert icon in tab when license expires
- Loading branch information
1 parent
86f4f7e
commit 2ede59f
Showing
19 changed files
with
6,368 additions
and
17,427 deletions.
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
Large diffs are not rendered by default.
Oops, something went wrong.
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,23 @@ | ||
import React from "react"; | ||
import {render, screen} from "@testing-library/react"; | ||
import LicenseAlert from "./LicenseAlert"; | ||
|
||
describe("LicenseAlert", () => { | ||
it("renders without crashing", () => { | ||
render(<LicenseAlert />); | ||
expect(screen.getByRole("alert")).toBeInTheDocument(); | ||
}); | ||
|
||
it("contains the correct links", () => { | ||
render(<LicenseAlert />); | ||
const buslLink = screen.getByRole("link", {name: /Business Source License \(BUSL\)/i}); | ||
expect(buslLink).toHaveAttribute("href", "https://github.com/reductstore/reductstore/blob/main/LICENSE"); | ||
expect(buslLink).toHaveAttribute("target", "_blank"); | ||
expect(buslLink).toHaveAttribute("rel", "noopener noreferrer"); | ||
|
||
const pricingPageLink = screen.getByRole("link", {name: /pricing page/i}); | ||
expect(pricingPageLink).toHaveAttribute("href", "https://www.reduct.store/pricing"); | ||
expect(pricingPageLink).toHaveAttribute("target", "_blank"); | ||
expect(pricingPageLink).toHaveAttribute("rel", "noopener noreferrer"); | ||
}); | ||
}); |
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,26 @@ | ||
import React from "react"; | ||
import {Alert} from "antd"; | ||
|
||
interface LicenseAlertProps { | ||
alertMessage?: React.ReactNode; | ||
} | ||
|
||
const LicenseAlert: React.FC<LicenseAlertProps> = ({alertMessage}) => ( | ||
<Alert | ||
type="warning" | ||
message={ | ||
alertMessage || ( | ||
<span> | ||
Please review the <strong> | ||
<a href="https://github.com/reductstore/reductstore/blob/main/LICENSE" target="_blank" rel="noopener noreferrer"> | ||
Business Source License (BUSL) | ||
</a></strong> for ReductStore and consult our <strong> | ||
<a href="https://www.reduct.store/pricing" target="_blank" rel="noopener noreferrer"> | ||
pricing page | ||
</a></strong> for more information on licensing options. | ||
</span> | ||
)} | ||
/> | ||
); | ||
|
||
export default LicenseAlert; |
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,15 @@ | ||
.licenseDescriptions .ant-descriptions-item-label { | ||
font-weight: bold; | ||
} | ||
|
||
.overQuota .ant-descriptions-item-content { | ||
color: red; | ||
} | ||
|
||
.expired .ant-descriptions-item-content { | ||
color: red; | ||
} | ||
|
||
.licenseAlert { | ||
margin-bottom: 20px; | ||
} |
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,94 @@ | ||
import React from "react"; | ||
import {render, screen} from "@testing-library/react"; | ||
import LicenseDetails from "./LicenseDetails"; | ||
import {LicenseInfo} from "reduct-js"; | ||
import {mockJSDOM} from "../../Helpers/TestHelpers"; | ||
|
||
describe("LicenseDetails", () => { | ||
const mockLicenseInfo: LicenseInfo = { | ||
plan: "Pro", | ||
licensee: "Acme Corp", | ||
invoice: "INV-123", | ||
expiryDate: 1735689600000, | ||
deviceNumber: 100, | ||
diskQuota: 1, | ||
fingerprint: "unique-fingerprint" | ||
}; | ||
|
||
const mockLicenseInfoExpired: LicenseInfo = { | ||
plan: "Pro", | ||
licensee: "Acme Corp", | ||
invoice: "INV-123", | ||
expiryDate: 1614556800000, | ||
deviceNumber: 100, | ||
diskQuota: 1, | ||
fingerprint: "unique-fingerprint" | ||
}; | ||
|
||
beforeEach(() => { | ||
jest.clearAllMocks(); | ||
mockJSDOM(); | ||
}); | ||
|
||
it("renders without crashing", () => { | ||
render(<LicenseDetails license={mockLicenseInfo} usage={0n} />); | ||
expect(screen.getByText("Plan")).toBeInTheDocument(); | ||
}); | ||
|
||
it("renders license details correctly", () => { | ||
render(<LicenseDetails license={mockLicenseInfo} usage={0n} />); | ||
const expiryDate = new Date(mockLicenseInfo.expiryDate).toLocaleDateString( | ||
undefined, | ||
{ | ||
year: "numeric", | ||
month: "long", | ||
day: "numeric", | ||
} | ||
); | ||
|
||
expect(screen.getByText("Plan")).toBeInTheDocument(); | ||
expect(screen.getByText("Pro")).toBeInTheDocument(); | ||
|
||
expect(screen.getByText("Licensee")).toBeInTheDocument(); | ||
expect(screen.getByText("Acme Corp")).toBeInTheDocument(); | ||
|
||
expect(screen.getByText("Invoice")).toBeInTheDocument(); | ||
expect(screen.getByText("INV-123")).toBeInTheDocument(); | ||
|
||
expect(screen.getByText("Expiry Date")).toBeInTheDocument(); | ||
expect(screen.getByText(expiryDate)).toBeInTheDocument(); | ||
|
||
expect(screen.getByText("Device Number")).toBeInTheDocument(); | ||
expect(screen.getByText("100")).toBeInTheDocument(); | ||
|
||
expect(screen.getByText("Disk Quota")).toBeInTheDocument(); | ||
expect(screen.getByText(/^1 TB/)).toBeInTheDocument(); | ||
|
||
expect(screen.getByText("Fingerprint")).toBeInTheDocument(); | ||
expect(screen.getByText("unique-fingerprint")).toBeInTheDocument(); | ||
}); | ||
|
||
it("does not render license alert when license is valid and disk quota is not exceeded", () => { | ||
render(<LicenseDetails license={mockLicenseInfo} usage={0n} />); | ||
const regex = /Your license has expired\./i; | ||
expect(screen.queryByText(regex)).not.toBeInTheDocument(); | ||
}); | ||
|
||
it("renders license alert when license has expired", () => { | ||
render(<LicenseDetails license={mockLicenseInfoExpired} usage={0n} />); | ||
const regex = /Your license has expired\./i; | ||
expect(screen.getByText(regex)).toBeInTheDocument(); | ||
}); | ||
|
||
it("renders license alert when disk quota exceeded", () => { | ||
render(<LicenseDetails license={mockLicenseInfo} usage={BigInt(1e12 + 1)} />); | ||
const regex = /disk quota has been exceeded\./i; | ||
expect(screen.getByText(regex)).toBeInTheDocument(); | ||
}); | ||
|
||
it("renders license alert when license has expired and disk quota exceeded", () => { | ||
render(<LicenseDetails license={mockLicenseInfoExpired} usage={2n} />); | ||
const regex = /Your license has expired\./i; | ||
expect(screen.getByText(regex)).toBeInTheDocument(); | ||
}); | ||
}); |
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,55 @@ | ||
import React from "react"; | ||
import {Descriptions} from "antd"; | ||
import {LicenseInfo} from "reduct-js"; | ||
import "./LicenseDetails.css"; | ||
import LicenseAlert from "../LicenseAlert/LicenseAlert"; | ||
// @ts-ignore | ||
import prettierBytes from "prettier-bytes"; | ||
import {bigintToNumber} from "../../Helpers/NumberUtils"; | ||
import {checkLicenseStatus} from "../../Helpers/licenseUtils"; | ||
|
||
interface LicenseDetailsProps { | ||
license: LicenseInfo; | ||
usage: bigint; | ||
} | ||
|
||
const LicenseDetails: React.FC<LicenseDetailsProps> = ({license, usage}) => { | ||
const {isValid, hasExpired, isOverQuota, usageInTB} = checkLicenseStatus(license, usage); | ||
const isUnlimited = license.diskQuota === 0; | ||
const usagePercentage = isUnlimited ? "N/A" : `${((usageInTB / Number(license.diskQuota)) * 100).toFixed(2)}%`; | ||
const expiryDate = new Date(license.expiryDate).toLocaleDateString(undefined, | ||
{ | ||
year: "numeric", | ||
month: "long", | ||
day: "numeric", | ||
} | ||
); | ||
const alertMessage = ( | ||
<span> | ||
Your license {hasExpired ? "has expired" : "disk quota has been exceeded"}. | ||
Please <strong><a href="https://www.reduct.store/contact" target="_blank" rel="noopener noreferrer">contact us</a> | ||
</strong> to {hasExpired ? "renew your license" : "increase your disk quota"} at your earliest convenience. | ||
</span> | ||
); | ||
return ( | ||
<> | ||
{!isValid && <div className="licenseAlert"><LicenseAlert alertMessage={alertMessage} /></div>} | ||
<Descriptions size="default" column={1} className="licenseDescriptions"> | ||
<Descriptions.Item label="Licensee">{license.licensee}</Descriptions.Item> | ||
<Descriptions.Item label="Plan">{license.plan}</Descriptions.Item> | ||
<Descriptions.Item label="Invoice">{license.invoice}</Descriptions.Item> | ||
<Descriptions.Item label="Device Number">{license.deviceNumber}</Descriptions.Item> | ||
<Descriptions.Item label="Expiry Date" className={hasExpired ? "expired" : ""} | ||
>{expiryDate}</Descriptions.Item> | ||
<Descriptions.Item label="Disk Quota" className={isOverQuota ? "overQuota" : ""}> | ||
{isUnlimited ? "Unlimited" : | ||
`${license.diskQuota} TB (Used: ${prettierBytes(bigintToNumber(usage))}, ${usagePercentage} of quota)`} | ||
</Descriptions.Item> | ||
<Descriptions.Item label="Fingerprint">{license.fingerprint}</Descriptions.Item> | ||
|
||
</Descriptions> | ||
</> | ||
); | ||
}; | ||
|
||
export default LicenseDetails; |
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
Oops, something went wrong.