diff --git a/ui/src/components/connections/ConnectionDeleteModal.tsx b/ui/src/components/connections/ConnectionDeleteModal.tsx index c8df8caa6..f2dcd4b4a 100644 --- a/ui/src/components/connections/ConnectionDeleteModal.tsx +++ b/ui/src/components/connections/ConnectionDeleteModal.tsx @@ -1,4 +1,4 @@ -import { Checkbox, Divider, Modal, Space, Typography, message } from "antd"; +import { App, Checkbox, Divider, Modal, Space, Typography } from "antd"; import { CheckboxChangeEvent } from "antd/es/checkbox"; import { useState } from "react"; @@ -21,8 +21,7 @@ export function ConnectionDeleteModal({ const env = useEnvContext(); const { identifier } = useIdentityContext(); const { notifyChange } = useIssuerStateContext(); - - const [messageAPI, messageContext] = message.useMessage(); + const { message } = App.useApp(); const [revokeCredentials, setRevokeCredentials] = useState(false); const [deleteCredentials, setDeleteCredentials] = useState(false); @@ -38,60 +37,52 @@ export function ConnectionDeleteModal({ void notifyChange("revoke"); } - void messageAPI.success(response.data.message); + void message.success(response.data.message); } else { - void messageAPI.error(response.error.message); + void message.error(response.error.message); } } ); }; return ( - <> - {messageContext} - - } - maskClosable - okButtonProps={{ danger: true }} - okText={DELETE} - onCancel={onClose} - onOk={handleDeleteConnection} - open - title="Are you sure you want to delete this connection?" - > - - Identity will be deleted from your connections. - - - - Would you also like to: - - setRevokeCredentials(checked) - } - > - Revoke all credentials for this connection. - - Revoking must be accompanied by publishing of issuer state in order for the action to - be effective. - - - - setDeleteCredentials(checked) - } - > - Delete all credentials for this connection. - - Credential data will be deleted from the database. - - - - - + } + maskClosable + okButtonProps={{ danger: true }} + okText={DELETE} + onCancel={onClose} + onOk={handleDeleteConnection} + open + title="Are you sure you want to delete this connection?" + > + + Identity will be deleted from your connections. + + + + Would you also like to: + setRevokeCredentials(checked)} + > + Revoke all credentials for this connection. + + Revoking must be accompanied by publishing of issuer state in order for the action to be + effective. + + + setDeleteCredentials(checked)} + > + Delete all credentials for this connection. + + Credential data will be deleted from the database. + + + + ); } diff --git a/ui/src/components/credentials/IssueCredential.tsx b/ui/src/components/credentials/IssueCredential.tsx index cd18f451d..2757508f9 100644 --- a/ui/src/components/credentials/IssueCredential.tsx +++ b/ui/src/components/credentials/IssueCredential.tsx @@ -1,4 +1,4 @@ -import { Card, Space, message } from "antd"; +import { App, Card, Space } from "antd"; import { useCallback, useEffect, useState } from "react"; import { generatePath, useNavigate, useSearchParams } from "react-router-dom"; @@ -50,9 +50,8 @@ export function IssueCredential() { const env = useEnvContext(); const { identifier } = useIdentityContext(); const { notifyChange } = useIssuerStateContext(); - + const { message } = App.useApp(); const navigate = useNavigate(); - const [messageAPI, messageContext] = message.useMessage(); const [searchParams] = useSearchParams(); const schemaID = searchParams.get(SCHEMA_SEARCH_PARAM) || undefined; @@ -150,12 +149,12 @@ export function IssueCredential() { setStep("summary"); } else { setAuthQRCode({ error: authQRResponse.error, status: "failed" }); - void messageAPI.error(authQRResponse.error.message); + void message.error(authQRResponse.error.message); } - void messageAPI.success("Credential link created"); + void message.success("Credential link created"); } else { - void messageAPI.error(linkResponse.error.message); + void message.error(linkResponse.error.message); } } else { notifyParseError(serializedCredentialForm.error); @@ -201,9 +200,9 @@ export function IssueCredential() { void notifyChange("credential"); } - void messageAPI.success("Credential issued"); + void message.success("Credential issued"); } else { - void messageAPI.error(response.error.message); + void message.error(response.error.message); } } else { notifyParseError(serializedCredentialForm.error); @@ -223,96 +222,92 @@ export function IssueCredential() { }, [schemaID]); return ( - <> - {messageContext} - - - {(() => { - switch (step) { - case "issuanceMethod": { - return ( - { - setCredentialFormInput({ ...credentialFormInput, issuanceMethod: values }); - setStep("issueCredential"); - }} - /> - ); - } - - case "issueCredential": { - return ( - - - { - setStep("issuanceMethod"); - }} - onSelectApiSchema={onSelectApiSchema} - onSubmit={({ - apiSchema, - jsonSchema, - values, - }: { - apiSchema: ApiSchema; - jsonSchema: JsonSchema; - values: IssueCredentialFormData; - }) => { - const newCredentialFormInput: CredentialFormInput = { - ...credentialFormInput, - issueCredential: values, - }; - - setCredentialFormInput(newCredentialFormInput); - - const parsedForm = credentialFormParser.safeParse(newCredentialFormInput); - - if (parsedForm.success) { - if (parsedForm.data.type === "credentialLink") { - void createCredentialLink({ - credentialLinkIssuance: parsedForm.data, - jsonSchema, - }); - } else { - void issueCredential({ - apiSchema, - credentialIssuance: parsedForm.data, - jsonSchema, - }); - } + + {(() => { + switch (step) { + case "issuanceMethod": { + return ( + { + setCredentialFormInput({ ...credentialFormInput, issuanceMethod: values }); + setStep("issueCredential"); + }} + /> + ); + } + + case "issueCredential": { + return ( + + + { + setStep("issuanceMethod"); + }} + onSelectApiSchema={onSelectApiSchema} + onSubmit={({ + apiSchema, + jsonSchema, + values, + }: { + apiSchema: ApiSchema; + jsonSchema: JsonSchema; + values: IssueCredentialFormData; + }) => { + const newCredentialFormInput: CredentialFormInput = { + ...credentialFormInput, + issueCredential: values, + }; + + setCredentialFormInput(newCredentialFormInput); + + const parsedForm = credentialFormParser.safeParse(newCredentialFormInput); + + if (parsedForm.success) { + if (parsedForm.data.type === "credentialLink") { + void createCredentialLink({ + credentialLinkIssuance: parsedForm.data, + jsonSchema, + }); } else { - notifyParseError(parsedForm.error); + void issueCredential({ + apiSchema, + credentialIssuance: parsedForm.data, + jsonSchema, + }); } - }} - type={credentialFormInput.issuanceMethod.type} - /> - - - ); - } - - case "summary": { - return ( - isAsyncTaskDataAvailable(authQRCode) && ( - - ) - ); - } + + + ); } - })()} - - + + case "summary": { + return ( + isAsyncTaskDataAvailable(authQRCode) && ( + + ) + ); + } + } + })()} + ); } diff --git a/ui/src/components/credentials/IssueCredentialForm.tsx b/ui/src/components/credentials/IssueCredentialForm.tsx index 9a183c290..4747d3ad6 100644 --- a/ui/src/components/credentials/IssueCredentialForm.tsx +++ b/ui/src/components/credentials/IssueCredentialForm.tsx @@ -3,6 +3,7 @@ import { Ajv2020 } from "ajv/dist/2020"; import addFormats from "ajv-formats"; import applyDraft2019Formats from "ajv-formats-draft2019"; import { + App, Button, Checkbox, Col, @@ -14,7 +15,6 @@ import { Select, Space, Typography, - message, } from "antd"; import { Store } from "antd/es/form/interface"; import dayjs from "dayjs"; @@ -95,9 +95,7 @@ export function IssueCredentialForm({ const env = useEnvContext(); const { identifier } = useIdentityContext(); const [form] = Form.useForm(); - - const [messageAPI, messageContext] = message.useMessage(); - + const { message } = App.useApp(); const [apiSchema, setApiSchema] = useState(); const [apiSchemas, setApiSchemas] = useState>({ status: "pending", @@ -323,11 +321,11 @@ export function IssueCredentialForm({ } else { if (!isAbortedError(response.error)) { setApiSchemas({ error: undefined, status: "failed" }); - void messageAPI.error(response.error.message); + void message.error(response.error.message); } } }, - [env, fetchJsonSchema, initialValues.schemaID, messageAPI, identifier] + [env, fetchJsonSchema, initialValues.schemaID, message, identifier] ); useEffect(() => { @@ -337,226 +335,223 @@ export function IssueCredentialForm({ }, [fetchSchemas]); return ( - <> - {messageContext} -
{ - const jsonSchemaData = isAsyncTaskDataAvailable(jsonSchema) ? jsonSchema.data : undefined; - const credentialSubjectAttributeWithoutId = - jsonSchemaData && extractCredentialSubjectAttributeWithoutId(jsonSchemaData); - - if ( - jsonSchemaData && - credentialSubjectAttributeWithoutId && - values.credentialSubject && - isFormValid(values.credentialSubject, credentialSubjectAttributeWithoutId) && - apiSchema - ) { - onSubmit({ apiSchema, jsonSchema: jsonSchemaData, values }); - } - }} - onValuesChange={(changedValue: Partial) => { - const jsonSchemaData = isAsyncTaskDataAvailable(jsonSchema) ? jsonSchema.data : undefined; - const credentialSubjectAttributeWithoutId = - jsonSchemaData && extractCredentialSubjectAttributeWithoutId(jsonSchemaData); - changedValue.credentialSubject && - credentialSubjectAttributeWithoutId && - isFormValid(changedValue.credentialSubject, credentialSubjectAttributeWithoutId); - }} + { + const jsonSchemaData = isAsyncTaskDataAvailable(jsonSchema) ? jsonSchema.data : undefined; + const credentialSubjectAttributeWithoutId = + jsonSchemaData && extractCredentialSubjectAttributeWithoutId(jsonSchemaData); + + if ( + jsonSchemaData && + credentialSubjectAttributeWithoutId && + values.credentialSubject && + isFormValid(values.credentialSubject, credentialSubjectAttributeWithoutId) && + apiSchema + ) { + onSubmit({ apiSchema, jsonSchema: jsonSchemaData, values }); + } + }} + onValuesChange={(changedValue: Partial) => { + const jsonSchemaData = isAsyncTaskDataAvailable(jsonSchema) ? jsonSchema.data : undefined; + const credentialSubjectAttributeWithoutId = + jsonSchemaData && extractCredentialSubjectAttributeWithoutId(jsonSchemaData); + changedValue.credentialSubject && + credentialSubjectAttributeWithoutId && + isFormValid(changedValue.credentialSubject, credentialSubjectAttributeWithoutId); + }} + > + - { + const schema = + isAsyncTaskDataAvailable(apiSchemas) && + apiSchemas.data.find((schema) => schema.id === id); + if (schema) { + onSelectApiSchema(schema); + setApiSchema(schema); + fetchJsonSchema(schema); + } + }} + placeholder={SCHEMA_TYPE} > - + + + {apiSchema && ( + <> + + + + {SCHEMA_HASH} + + , ] }} + > + {apiSchema.hash} + + + + + + + + {apiSchema.type} + + {(() => { + switch (jsonSchema.status) { + case "pending": + case "loading": + case "reloading": { + return ; } - }} - placeholder={SCHEMA_TYPE} - > - {isAsyncTaskDataAvailable(apiSchemas) && - apiSchemas.data.map(({ id, type }) => ( - - {type} - - ))} - - - - {apiSchema && ( - <> - - - - {SCHEMA_HASH} - - , ] }} - > - {apiSchema.hash} - - - - - - - - {apiSchema.type} - - {(() => { - switch (jsonSchema.status) { - case "pending": - case "loading": - case "reloading": { - return ; - } - case "failed": { - return ; - } + case "failed": { + return ; + } - case "successful": { - const credentialSubjectAttributeWithoutId = - extractCredentialSubjectAttributeWithoutId(jsonSchema.data); + case "successful": { + const credentialSubjectAttributeWithoutId = + extractCredentialSubjectAttributeWithoutId(jsonSchema.data); - return credentialSubjectAttributeWithoutId?.schema.attributes ? ( - <> - {jsonSchema.data.schema.description && ( - - {jsonSchema.data.schema.description} - - )} + return credentialSubjectAttributeWithoutId?.schema.attributes ? ( + <> + {jsonSchema.data.schema.description && ( + + {jsonSchema.data.schema.description} + + )} - - + + + + + + + Signature-based (SIG) + + + Credential signed by the issuer using a BJJ private key. + + + + + Merkle Tree Proof (MTP) + + + Credential will be added to the issuer's state tree. The state + transition involves an on-chain transaction and gas fees. + + + + + + + + - - - - Signature-based (SIG) - - - Credential signed by the issuer using a BJJ private key. - - - - - Merkle Tree Proof (MTP) - - - Credential will be added to the issuer's state tree. The - state transition involves an on-chain transaction and gas fees. - - - - + { + setRefreshServiceChecked(!refreshServiceChecked); + }} + > + Enable + + + + refreshServiceChecked + ? z.string().url().parseAsync(value) + : Promise.resolve(true), + }, + ]} + > + - - - - { - setRefreshServiceChecked(!refreshServiceChecked); - }} - > - Enable - - - - refreshServiceChecked - ? z.string().url().parseAsync(value) - : Promise.resolve(true), - }, - ]} - > - - - - - - refreshServiceChecked - ? dayjsInstanceParser.parseAsync(value) - : Promise.resolve(true), - }, - ]} - > - - - - ) : ( - - ); - } + + + refreshServiceChecked + ? dayjsInstanceParser.parseAsync(value) + : Promise.resolve(true), + }, + ]} + > + + + + ) : ( + + ); } - })()} - - )} - - {jsonSchema.status !== "failed" && ( - <> - - - - - - - - - - - - )} - - + } + })()} + + )} + + {jsonSchema.status !== "failed" && ( + <> + + + + + + + + + + + + )} + ); } diff --git a/ui/src/components/credentials/LinkDeleteModal.tsx b/ui/src/components/credentials/LinkDeleteModal.tsx index 2c4da6881..12f576ab8 100644 --- a/ui/src/components/credentials/LinkDeleteModal.tsx +++ b/ui/src/components/credentials/LinkDeleteModal.tsx @@ -1,4 +1,4 @@ -import { Modal, Typography, message } from "antd"; +import { App, Modal, Typography } from "antd"; import { deleteLink } from "src/adapters/api/credentials"; import IconClose from "src/assets/icons/x.svg?react"; @@ -18,7 +18,7 @@ export function LinkDeleteModal({ const env = useEnvContext(); const { identifier } = useIdentityContext(); - const [messageAPI, messageContext] = message.useMessage(); + const { message } = App.useApp(); const handleDeleteLink = () => { void deleteLink({ env, id, identifier }).then((response) => { @@ -26,35 +26,30 @@ export function LinkDeleteModal({ onClose(); onDelete(); - void messageAPI.success(response.data.message); + void message.success(response.data.message); } else { - void messageAPI.error(response.error.message); + void message.error(response.error.message); } }); }; return ( - <> - {messageContext} - - } - maskClosable - okButtonProps={{ danger: true }} - okText={DELETE} - onCancel={onClose} - onOk={handleDeleteLink} - open - title="Are you sure you want to delete this credential link?" - > - - Users will not be able to receive this credential any longer. This action cannot be - undone. - - - + } + maskClosable + okButtonProps={{ danger: true }} + okText={DELETE} + onCancel={onClose} + onOk={handleDeleteLink} + open + title="Are you sure you want to delete this credential link?" + > + + Users will not be able to receive this credential any longer. This action cannot be undone. + + ); } diff --git a/ui/src/components/credentials/LinkDetails.tsx b/ui/src/components/credentials/LinkDetails.tsx index d938d394e..7dc7d169f 100644 --- a/ui/src/components/credentials/LinkDetails.tsx +++ b/ui/src/components/credentials/LinkDetails.tsx @@ -225,7 +225,7 @@ export function LinkDetails() { { @@ -333,8 +333,6 @@ export function LinksTable() { return ( <> - {messageContext} - diff --git a/ui/src/components/identities/CreateIdentity.tsx b/ui/src/components/identities/CreateIdentity.tsx index fd60653fc..4c63bacfb 100644 --- a/ui/src/components/identities/CreateIdentity.tsx +++ b/ui/src/components/identities/CreateIdentity.tsx @@ -1,4 +1,4 @@ -import { Card, Space, message } from "antd"; +import { App, Card, Space } from "antd"; import { useNavigate } from "react-router-dom"; import { createIdentity } from "src/adapters/api/identities"; import { IdentityFormData } from "src/adapters/parsers/view"; @@ -13,7 +13,7 @@ import { IDENTITY_ADD, IDENTITY_ADD_NEW, IDENTITY_DETAILS } from "src/utils/cons export function CreateIdentity() { const env = useEnvContext(); const { handleChange, identitiesList } = useIdentityContext(); - const [messageAPI, messageContext] = message.useMessage(); + const { message } = App.useApp(); const navigate = useNavigate(); const handleSubmit = (formValues: IdentityFormData) => { @@ -22,7 +22,7 @@ export function CreateIdentity() { !identitiesList.data.some((identity) => identity.displayName === formValues.displayName); if (!isUnique) { - return void messageAPI.error(`${formValues.displayName} is already exists`); + return void message.error(`${formValues.displayName} is already exists`); } return void createIdentity({ env, payload: formValues }).then((response) => { @@ -31,31 +31,27 @@ export function CreateIdentity() { data: { identifier }, } = response; - void messageAPI.success("Identity added successfully"); + void message.success("Identity added successfully"); handleChange(identifier); navigate(ROUTES.identities.path); } else { - void messageAPI.error(response.error.message); + void message.error(response.error.message); } }); }; return ( - <> - {messageContext} - - - - - - - - - + + + + + + + ); } diff --git a/ui/src/components/identities/Identities.tsx b/ui/src/components/identities/Identities.tsx index e48538b0b..1c2a32e89 100644 --- a/ui/src/components/identities/Identities.tsx +++ b/ui/src/components/identities/Identities.tsx @@ -1,4 +1,4 @@ -import { Button, Divider, Space, message } from "antd"; +import { Button, Divider, Space } from "antd"; import { useCallback, useEffect } from "react"; import { useNavigate } from "react-router-dom"; import IconPlus from "src/assets/icons/plus.svg?react"; @@ -12,7 +12,6 @@ import { IDENTITIES, IDENTITY_ADD } from "src/utils/constants"; export function Identities() { const { fetchIdentities } = useIdentityContext(); - const [, messageContext] = message.useMessage(); const navigate = useNavigate(); const fetchData = useCallback(() => { @@ -25,27 +24,23 @@ export function Identities() { }, [fetchData]); return ( - <> - {messageContext} - - } - onClick={() => navigate(ROUTES.createIdentity.path)} - type="primary" - > - {IDENTITY_ADD} - - } - title={IDENTITIES} - > - - - navigate(ROUTES.createIdentity.path)} /> - - - + } + onClick={() => navigate(ROUTES.createIdentity.path)} + type="primary" + > + {IDENTITY_ADD} + + } + title={IDENTITIES} + > + + + navigate(ROUTES.createIdentity.path)} /> + + ); } diff --git a/ui/src/components/identities/Identity.tsx b/ui/src/components/identities/Identity.tsx index 01e35400c..f0e294be7 100644 --- a/ui/src/components/identities/Identity.tsx +++ b/ui/src/components/identities/Identity.tsx @@ -1,4 +1,4 @@ -import { Button, Card, Flex, Form, Input, Space, message } from "antd"; +import { App, Button, Card, Flex, Form, Input, Space } from "antd"; import { useCallback, useEffect, useState } from "react"; import { useParams } from "react-router-dom"; import { useIdentityContext } from "../../contexts/Identity"; @@ -31,7 +31,7 @@ export function Identity() { const { fetchIdentities, identitiesList } = useIdentityContext(); const [displayNameEditable, setDisplayNameEditable] = useState(false); - const [messageAPI, messageContext] = message.useMessage(); + const { message } = App.useApp(); const [form] = Form.useForm(); const { identityID: identifier } = useParams(); @@ -78,7 +78,7 @@ export function Identity() { ); if (!isUnique) { - return void messageAPI.error(`${formValues.displayName} is already exists`); + return void message.error(`${formValues.displayName} is already exists`); } return void updateIdentityDisplayName({ @@ -90,111 +90,108 @@ export function Identity() { void fetchIdentity().then(() => { setDisplayNameEditable(false); makeRequestAbortable(fetchIdentities); - void messageAPI.success("Identity edited successfully"); + void message.success("Identity edited successfully"); }); } else { - void messageAPI.error(response.error.message); + void message.error(response.error.message); } }); }; return ( - <> - {messageContext} - - {(() => { - if (hasAsyncTaskFailed(identity)) { - return ( - - - - ); - } else if (isAsyncTaskStarting(identity)) { - return ( - - - - ); - } else { - const [, method = "", blockchain = "", network = ""] = identifier.split(":"); - return ( - - {displayNameEditable ? ( -
- - - - - - - - - - - ) - ); - } - })()} - - ); + {Object.values(Method).map((method) => ( + + {method} + + ))} + + + + The protocol or system used to create, resolve, and manage the DID. + + + + + + + + + + + + + + + + + + + + + Identity signing key's credential status is checked by clients to generate + zero-knowledge proofs using signed credentials. + + + + <> + + + + + + + + + ) + ); + } } diff --git a/ui/src/components/identities/Onboarding.tsx b/ui/src/components/identities/Onboarding.tsx index 5deb4786f..8558a2448 100644 --- a/ui/src/components/identities/Onboarding.tsx +++ b/ui/src/components/identities/Onboarding.tsx @@ -1,4 +1,4 @@ -import { Avatar, Card, Divider, Flex, Grid, Typography, message } from "antd"; +import { App, Avatar, Card, Divider, Flex, Grid, Typography } from "antd"; import React from "react"; import { useNavigate } from "react-router-dom"; import { createIdentity } from "../../adapters/api/identities"; @@ -38,7 +38,7 @@ export function Onboarding() { const env = useEnvContext(); const { handleChange } = useIdentityContext(); const navigate = useNavigate(); - const [messageAPI, messageContext] = message.useMessage(); + const { message } = App.useApp(); const { lg } = Grid.useBreakpoint(); @@ -48,109 +48,105 @@ export function Onboarding() { const { data: { identifier }, } = response; - void messageAPI.success("Identity added successfully"); + void message.success("Identity added successfully"); handleChange(identifier); navigate(ROUTES.schemas.path); } else { - void messageAPI.error(response.error.message); + void message.error(response.error.message); } }); return ( - <> - {messageContext} - - - - } - size={48} - style={{ marginBottom: 16 }} - /> + + + } + size={48} + style={{ marginBottom: 16 }} + /> - - You successfully installed Issuer Node - - - Here's what you're going to be able to do with the issuer node, once you - finalize your setup - - + + You successfully installed Issuer Node + + + Here's what you're going to be able to do with the issuer node, once you + finalize your setup + + - - {cards.map(({ icon, text, title }, index) => { - const isLastCard = index + 1 === cards.length; - return ( - - - - + + {cards.map(({ icon, text, title }, index) => { + const isLastCard = index + 1 === cards.length; + return ( + + + + - - - {title} - - - {text} - - + + + {title} + + + {text} + - - {!isLastCard && lg &&
} - - ); - })} - + + + {!isLastCard && lg &&
} + + ); + })} + - + - - - Finalize the setup by adding a new identity - + + + Finalize the setup by adding a new identity + - - Add new identity - - You will be able to add more identities later on. - - - } - > - - - + + Add new identity + + You will be able to add more identities later on. + + + } + > + + - + ); } diff --git a/ui/src/components/issuer-state/IssuerState.tsx b/ui/src/components/issuer-state/IssuerState.tsx index d337c2eca..a4fc8df4f 100644 --- a/ui/src/components/issuer-state/IssuerState.tsx +++ b/ui/src/components/issuer-state/IssuerState.tsx @@ -1,4 +1,5 @@ import { + App, Avatar, Button, Card, @@ -10,7 +11,6 @@ import { Tag, Tooltip, Typography, - message, } from "antd"; import { useCallback, useEffect, useMemo, useState } from "react"; @@ -59,7 +59,7 @@ export function IssuerState() { status: "pending", }); - const [messageAPI, messageContext] = message.useMessage(); + const { message } = App.useApp(); const transactionsList = useMemo( () => (isAsyncTaskDataAvailable(transactions) ? transactions.data : []), [transactions] @@ -96,9 +96,9 @@ export function IssuerState() { void functionToExecute({ env, identifier }).then((response) => { if (response.success) { - void messageAPI.success(PUBLISHED_MESSAGE); + void message.success(PUBLISHED_MESSAGE); } else { - void messageAPI.error(response.error.message); + void message.error(response.error.message); } void refreshStatus(); @@ -265,115 +265,111 @@ export function IssuerState() { }, [fetchTransactions, transactionsList]); return ( - <> - {messageContext} - - - - - - - - {disablePublishState ? ( - - ) : ( - } /> - ) - } - description={ - failedTransaction - ? "Please try again." - : "You can publish issuer state now or bulk publish with other actions." - } - title={ - failedTransaction - ? "Transaction failed to publish" - : "Pending actions to be published" - } - /> - )} - - - - - - } size={48} /> - - No transactions - - - Published transactions will be listed here - - - } - isLoading={isAsyncTaskStarting(transactions)} - showDefaultContents={ - transactions.status === "successful" && transactionsList.length === 0 - } - table={ - ({ - title: ( - - <>{title} - - ), - ...column, - }))} - dataSource={transactionsList} - locale={{ - emptyText: transactions.status === "failed" && ( - - ), - }} - onChange={({ current, pageSize, total }, _, sorters) => { - setPaginationTotal(total || DEFAULT_PAGINATION_TOTAL); - const parsedSorters = tableSorterParser.safeParse(sorters); - updateUrlParams({ - maxResults: pageSize, - page: current, - sorters: parsedSorters.success ? parsedSorters.data : [], - }); - }} - pagination={{ - current: paginationPage, - hideOnSinglePage: true, - pageSize: paginationMaxResults, - position: ["bottomRight"], - total: paginationTotal, - }} - rowKey="id" - showSorterTooltip - sortDirections={["ascend", "descend"]} + + + + + + + {disablePublishState ? ( + + ) : ( + } /> + ) + } + description={ + failedTransaction + ? "Please try again." + : "You can publish issuer state now or bulk publish with other actions." + } + title={ + failedTransaction + ? "Transaction failed to publish" + : "Pending actions to be published" + } /> - } - title={ - - - - - {transactionsList.length} - - - } - /> - - - + )} + + + + + + } size={48} /> + + No transactions + + + Published transactions will be listed here + + + } + isLoading={isAsyncTaskStarting(transactions)} + showDefaultContents={ + transactions.status === "successful" && transactionsList.length === 0 + } + table={ +
({ + title: ( + + <>{title} + + ), + ...column, + }))} + dataSource={transactionsList} + locale={{ + emptyText: transactions.status === "failed" && ( + + ), + }} + onChange={({ current, pageSize, total }, _, sorters) => { + setPaginationTotal(total || DEFAULT_PAGINATION_TOTAL); + const parsedSorters = tableSorterParser.safeParse(sorters); + updateUrlParams({ + maxResults: pageSize, + page: current, + sorters: parsedSorters.success ? parsedSorters.data : [], + }); + }} + pagination={{ + current: paginationPage, + hideOnSinglePage: true, + pageSize: paginationMaxResults, + position: ["bottomRight"], + total: paginationTotal, + }} + rowKey="id" + showSorterTooltip + sortDirections={["ascend", "descend"]} + /> + } + title={ + + + + + {transactionsList.length} + + + } + /> + + ); } diff --git a/ui/src/components/schemas/DownloadSchema.tsx b/ui/src/components/schemas/DownloadSchema.tsx index f2dc21377..6dc557298 100644 --- a/ui/src/components/schemas/DownloadSchema.tsx +++ b/ui/src/components/schemas/DownloadSchema.tsx @@ -1,4 +1,4 @@ -import { Row, Typography, message } from "antd"; +import { App, Row, Typography } from "antd"; import { downloadJsonFromUrl } from "src/adapters/json"; import { Env } from "src/domain"; @@ -12,7 +12,7 @@ export function DownloadSchema({ fileName: string; url: string; }) { - const [messageAPI, messageContext] = message.useMessage(); + const { message } = App.useApp(); const handleDownload = () => { downloadJsonFromUrl({ @@ -21,22 +21,18 @@ export function DownloadSchema({ url, }) .then(() => { - void messageAPI.success("Schema downloaded successfully."); + void message.success("Schema downloaded successfully."); }) .catch(() => { - void messageAPI.error("An error occurred while downloading the schema. Please try again."); + void message.error("An error occurred while downloading the schema. Please try again."); }); }; return ( - <> - {messageContext} + + Download - - Download - - JSON Schema - - + JSON Schema + ); } diff --git a/ui/src/components/schemas/ImportSchema.tsx b/ui/src/components/schemas/ImportSchema.tsx index 1eac250ed..121e94a62 100644 --- a/ui/src/components/schemas/ImportSchema.tsx +++ b/ui/src/components/schemas/ImportSchema.tsx @@ -1,4 +1,4 @@ -import { message } from "antd"; +import { App } from "antd"; import { useState } from "react"; import { useNavigate } from "react-router-dom"; @@ -26,7 +26,7 @@ export function ImportSchema() { const { identifier } = useIdentityContext(); const navigate = useNavigate(); - const [messageAPI, messageContext] = message.useMessage(); + const { message } = App.useApp(); const [step, setStep] = useState({ type: "form" }); @@ -52,48 +52,44 @@ export function ImportSchema() { if (response.success) { navigate(ROUTES.schemas.path); - void messageAPI.success("Schema successfully imported"); + void message.success("Schema successfully imported"); } else { - void messageAPI.error(response.error.message); + void message.error(response.error.message); } }); return ( - <> - {messageContext} - - - {step.type === "form" ? ( - { - setStep({ - formData, - type: "preview", - }); - }} - /> - ) : ( - { - setStep({ formData: step.formData, type: "form" }); - }} - onImport={() => { - onSchemaImport(step.formData); - }} - url={step.formData.schemaUrl} - /> - )} - - + + {step.type === "form" ? ( + { + setStep({ + formData, + type: "preview", + }); + }} + /> + ) : ( + { + setStep({ formData: step.formData, type: "form" }); + }} + onImport={() => { + onSchemaImport(step.formData); + }} + url={step.formData.schemaUrl} + /> + )} + ); } diff --git a/ui/src/components/shared/CredentialDeleteModal.tsx b/ui/src/components/shared/CredentialDeleteModal.tsx index 2e4da87b3..67c8b3f59 100644 --- a/ui/src/components/shared/CredentialDeleteModal.tsx +++ b/ui/src/components/shared/CredentialDeleteModal.tsx @@ -1,4 +1,4 @@ -import { Alert, Button, Flex, Modal, Space, Typography, message } from "antd"; +import { Alert, App, Button, Flex, Modal, Space, Typography } from "antd"; import { useState } from "react"; import { deleteCredential, revokeCredential } from "src/adapters/api/credentials"; @@ -23,7 +23,7 @@ export function CredentialDeleteModal({ const { identifier } = useIdentityContext(); const { notifyChange } = useIssuerStateContext(); - const [messageAPI, messageContext] = message.useMessage(); + const { message } = App.useApp(); const [isLoading, setIsLoading] = useState(false); @@ -37,9 +37,9 @@ export function CredentialDeleteModal({ onClose(); onDelete(); - void messageAPI.success(response.data.message); + void message.success(response.data.message); } else { - void messageAPI.error(response.error.message); + void message.error(response.error.message); } setIsLoading(false); @@ -57,63 +57,59 @@ export function CredentialDeleteModal({ } else { setIsLoading(false); - void messageAPI.error(response.error.message); + void message.error(response.error.message); } }); }; return ( - <> - {messageContext} - - } - footer={ - - - - - - {!revoked && ( - - )} - - } - maskClosable - onCancel={onClose} - open - title="Are you sure you want to delete this credential?" - > - - - Credential data will be deleted from the database. - + } + footer={ + + + + {!revoked && ( - - Revoking requires publishing the issuer state. This action cannot be undone. - - } - icon={} - message={ - - If a credential is deleted but not revoked, it can still be used by end users. - - } - showIcon - type="warning" - /> + )} - - - + + } + maskClosable + onCancel={onClose} + open + title="Are you sure you want to delete this credential?" + > + + + Credential data will be deleted from the database. + + + {!revoked && ( + + Revoking requires publishing the issuer state. This action cannot be undone. + + } + icon={} + message={ + + If a credential is deleted but not revoked, it can still be used by end users. + + } + showIcon + type="warning" + /> + )} + + ); } diff --git a/ui/src/components/shared/CredentialRevokeModal.tsx b/ui/src/components/shared/CredentialRevokeModal.tsx index 41133760a..8eb43ec34 100644 --- a/ui/src/components/shared/CredentialRevokeModal.tsx +++ b/ui/src/components/shared/CredentialRevokeModal.tsx @@ -1,4 +1,4 @@ -import { Modal, Space, Typography, message } from "antd"; +import { App, Modal, Space, Typography } from "antd"; import { useState } from "react"; import { useSearchParams } from "react-router-dom"; @@ -23,7 +23,7 @@ export function CredentialRevokeModal({ const { identifier } = useIdentityContext(); const { notifyChange } = useIssuerStateContext(); - const [messageAPI, messageContext] = message.useMessage(); + const { message } = App.useApp(); const [isLoading, setIsLoading] = useState(false); const [, setSearchParams] = useSearchParams(); @@ -43,39 +43,35 @@ export function CredentialRevokeModal({ return params; }); void notifyChange("revoke"); - void messageAPI.success(response.data.message); + void message.success(response.data.message); } else { setIsLoading(false); - void messageAPI.error(response.error.message); + void message.error(response.error.message); } }); }; return ( - <> - {messageContext} - - } - maskClosable - okButtonProps={{ danger: true, loading: isLoading }} - okText={REVOKE} - onCancel={onClose} - onOk={handleRevokeCredential} - open - title="Are you sure you want to revoke this credential?" - > - - - Revoking of a credential must be accompanied by publishing of issuer state in order for - the action to be effective. This action cannot be undone. - - - - + } + maskClosable + okButtonProps={{ danger: true, loading: isLoading }} + okText={REVOKE} + onCancel={onClose} + onOk={handleRevokeCredential} + open + title="Are you sure you want to revoke this credential?" + > + + + Revoking of a credential must be accompanied by publishing of issuer state in order for + the action to be effective. This action cannot be undone. + + + ); } diff --git a/ui/src/components/shared/Detail.tsx b/ui/src/components/shared/Detail.tsx index ca4e01225..40473a85a 100644 --- a/ui/src/components/shared/Detail.tsx +++ b/ui/src/components/shared/Detail.tsx @@ -1,4 +1,4 @@ -import { Button, Col, Flex, Grid, Row, Tag, TagProps, Typography, message } from "antd"; +import { App, Button, Col, Flex, Grid, Row, Tag, TagProps, Typography } from "antd"; import copy from "copy-to-clipboard"; import { useRef } from "react"; @@ -10,7 +10,7 @@ import { DownloadQRLink } from "src/components/shared/DownloadQRLink"; export function Detail({ copyable, copyableText, - donwloadLink, + downloadLink, ellipsisPosition, href, label, @@ -19,7 +19,7 @@ export function Detail({ }: { copyable?: boolean; copyableText?: string; - donwloadLink?: boolean; + downloadLink?: boolean; ellipsisPosition?: number; href?: string; label: string; @@ -27,8 +27,8 @@ export function Detail({ text: string; }) { const { sm } = Grid.useBreakpoint(); - const [messageAPI, messageContext] = message.useMessage(); - const donwloadLinkRef = useRef(null); + const { message } = App.useApp(); + const downloadLinkRef = useRef(null); const onCopyToClipboard = (link: string) => { const hasCopied = copy(link, { @@ -36,9 +36,9 @@ export function Detail({ }); if (hasCopied) { - void messageAPI.success("Link copied to clipboard."); + void message.success("Link copied to clipboard."); } else { - void messageAPI.error("Couldn't copy link. Please try again."); + void message.error("Couldn't copy link. Please try again."); } }; const value = ellipsisPosition ? text.slice(0, text.length - ellipsisPosition) : text; @@ -64,58 +64,55 @@ export function Detail({ ); return ( - <> - {messageContext} - - - {label} - - - {(() => { - if (donwloadLink && href) { - return ( - - } - iconPosition="end" - ref={donwloadLinkRef} - style={{ height: "auto", padding: 0 }} - type="link" - > - Download QR - - } - fileName={label} - hidden - link={href} - /> - {copyable && ( + + + {label} + + + {(() => { + if (downloadLink && href) { + return ( + + } + icon={} iconPosition="end" - onClick={() => onCopyToClipboard(href)} + ref={downloadLinkRef} style={{ height: "auto", padding: 0 }} type="link" > - Copy link + Download QR - )} - - ); - } else if (href) { - return ( - - {element} - - ); - } else { - return element; - } - })()} - - - + } + fileName={label} + hidden + link={href} + /> + {copyable && ( + + )} + + ); + } else if (href) { + return ( + + {element} + + ); + } else { + return element; + } + })()} + + ); } diff --git a/ui/src/components/shared/DownloadQRLink.tsx b/ui/src/components/shared/DownloadQRLink.tsx index 9fdec0a6f..3763decd8 100644 --- a/ui/src/components/shared/DownloadQRLink.tsx +++ b/ui/src/components/shared/DownloadQRLink.tsx @@ -1,4 +1,4 @@ -import { Flex, Space, message } from "antd"; +import { App, Flex, Space } from "antd"; import { QRCodeCanvas } from "qrcode.react"; import { useRef } from "react"; import { downloadQRCanvas } from "src/utils/browser"; @@ -15,30 +15,27 @@ export function DownloadQRLink({ link: string; }) { const ref = useRef(null); - const [messageAPI, messageContext] = message.useMessage(); + const { message } = App.useApp(); const onDownload = () => { const canvas = ref.current?.querySelector("canvas"); if (canvas) { downloadQRCanvas(canvas, fileName); - void messageAPI.success("QR code downloaded successfully."); + void message.success("QR code downloaded successfully."); } }; return ( - <> - {messageContext} - - - {button} - - + + + {button} + ); } diff --git a/ui/src/components/shared/HighlightLink.tsx b/ui/src/components/shared/HighlightLink.tsx index 40756c617..db2a1d3d0 100644 --- a/ui/src/components/shared/HighlightLink.tsx +++ b/ui/src/components/shared/HighlightLink.tsx @@ -1,11 +1,11 @@ -import { Button, Card, Flex, Typography, message, theme } from "antd"; +import { App, Button, Card, Flex, Typography, theme } from "antd"; import copy from "copy-to-clipboard"; import IconCopy from "src/assets/icons/copy-01.svg?react"; import IconLink from "src/assets/icons/link-external-01.svg?react"; export function HighlightLink({ link, openable }: { link: string; openable: boolean }) { const { token } = theme.useToken(); - const [messageAPI, messageContext] = message.useMessage(); + const { message } = App.useApp(); const onCopyToClipboard = () => { const hasCopied = copy(link, { @@ -13,43 +13,40 @@ export function HighlightLink({ link, openable }: { link: string; openable: bool }); if (hasCopied) { - void messageAPI.success("Link copied to clipboard."); + void message.success("Link copied to clipboard."); } else { - void messageAPI.error("Couldn't copy link. Please try again."); + void message.error("Couldn't copy link. Please try again."); } }; return ( - <> - {messageContext} - - - - {openable && ( -