From 84842272a6b3f7c244f88f493d8560060079c177 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Germ=C3=A1n=20Saracca?= Date: Mon, 26 Aug 2024 13:17:06 -0300 Subject: [PATCH 1/9] feat: initial work --- public/locales/en/userPanel.json | 12 ++++++ src/Router.tsx | 5 +++ src/sections/Route.enum.ts | 3 +- src/sections/user-panel/ApiTokenSection.tsx | 26 +++++++++++++ src/sections/user-panel/UserPanel.module.scss | 10 +++++ src/sections/user-panel/UserPanel.tsx | 39 +++++++++++++++++++ src/sections/user-panel/UserPanelFactory.tsx | 8 ++++ src/sections/user-panel/UserPanelHelper.ts | 19 +++++++++ 8 files changed, 121 insertions(+), 1 deletion(-) create mode 100644 public/locales/en/userPanel.json create mode 100644 src/sections/user-panel/ApiTokenSection.tsx create mode 100644 src/sections/user-panel/UserPanel.module.scss create mode 100644 src/sections/user-panel/UserPanel.tsx create mode 100644 src/sections/user-panel/UserPanelFactory.tsx create mode 100644 src/sections/user-panel/UserPanelHelper.ts diff --git a/public/locales/en/userPanel.json b/public/locales/en/userPanel.json new file mode 100644 index 000000000..5855f3e96 --- /dev/null +++ b/public/locales/en/userPanel.json @@ -0,0 +1,12 @@ +{ + "pageTitle": "Account - Root", + "tabs": { + "myData": "My data", + "notifications": "Notifications", + "accountInformation": "Account information", + "apiToken": "API token" + }, + "apiToken": { + "helperText": "Your API Token is valid for a year. Check out our API Guide for more information on using your API Token with the Dataverse APIs." + } +} diff --git a/src/Router.tsx b/src/Router.tsx index f6a6426f3..388cd26f0 100644 --- a/src/Router.tsx +++ b/src/Router.tsx @@ -10,6 +10,7 @@ import { UploadDatasetFilesFactory } from './sections/upload-dataset-files/Uploa import { EditDatasetMetadataFactory } from './sections/edit-dataset-metadata/EditDatasetMetadataFactory' import { DatasetNonNumericVersion } from './dataset/domain/models/Dataset' import { CreateCollectionFactory } from './sections/create-collection/CreateCollectionFactory' +import { UserPanelFactory } from './sections/user-panel/UserPanelFactory' const router = createBrowserRouter( [ @@ -49,6 +50,10 @@ const router = createBrowserRouter( { path: Route.FILES, element: FileFactory.create() + }, + { + path: Route.USER_PANEL, + element: UserPanelFactory.create() } ] } diff --git a/src/sections/Route.enum.ts b/src/sections/Route.enum.ts index 6842bcdbe..3dfa54871 100644 --- a/src/sections/Route.enum.ts +++ b/src/sections/Route.enum.ts @@ -9,7 +9,8 @@ export enum Route { EDIT_DATASET_METADATA = '/datasets/edit-metadata', FILES = '/files', COLLECTIONS = '/collections/:collectionId', - CREATE_COLLECTION = '/collections/:ownerCollectionId/create' + CREATE_COLLECTION = '/collections/:ownerCollectionId/create', + USER_PANEL = '/user-panel' } export const RouteWithParams = { diff --git a/src/sections/user-panel/ApiTokenSection.tsx b/src/sections/user-panel/ApiTokenSection.tsx new file mode 100644 index 000000000..2bb06a425 --- /dev/null +++ b/src/sections/user-panel/ApiTokenSection.tsx @@ -0,0 +1,26 @@ +import { Trans, useTranslation } from 'react-i18next' +import styles from './UserPanel.module.scss' + +export const ApiTokenSection = () => { + const { t } = useTranslation('userPanel', { keyPrefix: 'apiToken' }) + + return ( +
+

+ + ) + }} + /> +

+
+ ) +} diff --git a/src/sections/user-panel/UserPanel.module.scss b/src/sections/user-panel/UserPanel.module.scss new file mode 100644 index 000000000..e76e0535b --- /dev/null +++ b/src/sections/user-panel/UserPanel.module.scss @@ -0,0 +1,10 @@ +@import 'node_modules/@iqss/dataverse-design-system/src/lib/assets/styles/design-tokens/colors.module'; + +.tab-container { + padding: 1rem; +} + +.helper-text { + color: $dv-subtext-color; + font-size: 14px; +} diff --git a/src/sections/user-panel/UserPanel.tsx b/src/sections/user-panel/UserPanel.tsx new file mode 100644 index 000000000..b28e354d3 --- /dev/null +++ b/src/sections/user-panel/UserPanel.tsx @@ -0,0 +1,39 @@ +import { useTranslation } from 'react-i18next' +import { useSearchParams } from 'react-router-dom' +import { Tabs } from '@iqss/dataverse-design-system' +import { UserPanelHelper } from './UserPanelHelper' +import { ApiTokenSection } from './ApiTokenSection' +import styles from './UserPanel.module.scss' + +const tabsKeys = UserPanelHelper.USER_PANEL_TABS_KEYS + +export const UserPanel = () => { + const { t } = useTranslation('userPanel') + const [searchParams] = useSearchParams() + const defaultActiveTabKey = UserPanelHelper.defineSelectedTabKey(searchParams) + + return ( +
+
+

{t('pageTitle')}

+
+ + + +
My Data here.
+
+ +
Notifications here.
+
+ +
Account Information.
+
+ +
+ +
+
+
+
+ ) +} diff --git a/src/sections/user-panel/UserPanelFactory.tsx b/src/sections/user-panel/UserPanelFactory.tsx new file mode 100644 index 000000000..91abc86ad --- /dev/null +++ b/src/sections/user-panel/UserPanelFactory.tsx @@ -0,0 +1,8 @@ +import { ReactElement } from 'react' +import { UserPanel } from './UserPanel' + +export class UserPanelFactory { + static create(): ReactElement { + return + } +} diff --git a/src/sections/user-panel/UserPanelHelper.ts b/src/sections/user-panel/UserPanelHelper.ts new file mode 100644 index 000000000..58cbc87c5 --- /dev/null +++ b/src/sections/user-panel/UserPanelHelper.ts @@ -0,0 +1,19 @@ +export class UserPanelHelper { + static USER_PANEL_TABS_KEYS = { + myData: 'myData', + notifications: 'notifications', + accountInformation: 'accountInformation', + apiToken: 'apiToken' + } + + static USER_PANEL_TAB_QUERY_KEY = 'tab' + + public static defineSelectedTabKey(searchParams: URLSearchParams): string { + const tabValue = searchParams.get(this.USER_PANEL_TAB_QUERY_KEY) + + return ( + this.USER_PANEL_TABS_KEYS[tabValue as keyof typeof this.USER_PANEL_TABS_KEYS] ?? + this.USER_PANEL_TABS_KEYS.myData + ) + } +} From d6a43278688437eae9f1250288360daa7647baf6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Germ=C3=A1n=20Saracca?= Date: Wed, 4 Sep 2024 11:01:05 -0300 Subject: [PATCH 2/9] feat: change files name to account, routing etc --- .../en/{userPanel.json => account.json} | 2 +- src/Router.tsx | 6 ++--- src/sections/Route.enum.ts | 2 +- .../Account.module.scss} | 0 .../UserPanel.tsx => account/Account.tsx} | 23 +++++++++++++------ src/sections/account/AccountFactory.tsx | 8 +++++++ src/sections/account/AccountHelper.ts | 19 +++++++++++++++ .../ApiTokenSection.module.scss | 15 ++++++++++++ .../ApiTokenSection}/ApiTokenSection.tsx | 14 +++++++---- src/sections/user-panel/UserPanelFactory.tsx | 8 ------- src/sections/user-panel/UserPanelHelper.ts | 19 --------------- 11 files changed, 72 insertions(+), 44 deletions(-) rename public/locales/en/{userPanel.json => account.json} (91%) rename src/sections/{user-panel/UserPanel.module.scss => account/Account.module.scss} (100%) rename src/sections/{user-panel/UserPanel.tsx => account/Account.tsx} (58%) create mode 100644 src/sections/account/AccountFactory.tsx create mode 100644 src/sections/account/AccountHelper.ts create mode 100644 src/sections/account/ApiTokenSection/ApiTokenSection.module.scss rename src/sections/{user-panel => account/ApiTokenSection}/ApiTokenSection.tsx (54%) delete mode 100644 src/sections/user-panel/UserPanelFactory.tsx delete mode 100644 src/sections/user-panel/UserPanelHelper.ts diff --git a/public/locales/en/userPanel.json b/public/locales/en/account.json similarity index 91% rename from public/locales/en/userPanel.json rename to public/locales/en/account.json index 5855f3e96..6ce0c6c52 100644 --- a/public/locales/en/userPanel.json +++ b/public/locales/en/account.json @@ -1,5 +1,5 @@ { - "pageTitle": "Account - Root", + "pageTitle": "Account", "tabs": { "myData": "My data", "notifications": "Notifications", diff --git a/src/Router.tsx b/src/Router.tsx index 388cd26f0..0cfa19960 100644 --- a/src/Router.tsx +++ b/src/Router.tsx @@ -10,7 +10,7 @@ import { UploadDatasetFilesFactory } from './sections/upload-dataset-files/Uploa import { EditDatasetMetadataFactory } from './sections/edit-dataset-metadata/EditDatasetMetadataFactory' import { DatasetNonNumericVersion } from './dataset/domain/models/Dataset' import { CreateCollectionFactory } from './sections/create-collection/CreateCollectionFactory' -import { UserPanelFactory } from './sections/user-panel/UserPanelFactory' +import { AccountFactory } from './sections/account/AccountFactory' const router = createBrowserRouter( [ @@ -52,8 +52,8 @@ const router = createBrowserRouter( element: FileFactory.create() }, { - path: Route.USER_PANEL, - element: UserPanelFactory.create() + path: Route.ACCOUNT, + element: AccountFactory.create() } ] } diff --git a/src/sections/Route.enum.ts b/src/sections/Route.enum.ts index 3dfa54871..f7d9b6f5d 100644 --- a/src/sections/Route.enum.ts +++ b/src/sections/Route.enum.ts @@ -10,7 +10,7 @@ export enum Route { FILES = '/files', COLLECTIONS = '/collections/:collectionId', CREATE_COLLECTION = '/collections/:ownerCollectionId/create', - USER_PANEL = '/user-panel' + ACCOUNT = '/account' } export const RouteWithParams = { diff --git a/src/sections/user-panel/UserPanel.module.scss b/src/sections/account/Account.module.scss similarity index 100% rename from src/sections/user-panel/UserPanel.module.scss rename to src/sections/account/Account.module.scss diff --git a/src/sections/user-panel/UserPanel.tsx b/src/sections/account/Account.tsx similarity index 58% rename from src/sections/user-panel/UserPanel.tsx rename to src/sections/account/Account.tsx index b28e354d3..05a0281e3 100644 --- a/src/sections/user-panel/UserPanel.tsx +++ b/src/sections/account/Account.tsx @@ -1,19 +1,28 @@ import { useTranslation } from 'react-i18next' import { useSearchParams } from 'react-router-dom' import { Tabs } from '@iqss/dataverse-design-system' -import { UserPanelHelper } from './UserPanelHelper' -import { ApiTokenSection } from './ApiTokenSection' -import styles from './UserPanel.module.scss' +import { AccountHelper } from './AccountHelper' +import { ApiTokenSection } from './ApiTokenSection/ApiTokenSection' +import { BreadcrumbsGenerator } from '../shared/hierarchy/BreadcrumbsGenerator' +import { UpwardHierarchyNodeMother } from '../../../tests/component/shared/hierarchy/domain/models/UpwardHierarchyNodeMother' +import styles from './Account.module.scss' -const tabsKeys = UserPanelHelper.USER_PANEL_TABS_KEYS +const tabsKeys = AccountHelper.ACCOUNT_PANEL_TABS_KEYS -export const UserPanel = () => { - const { t } = useTranslation('userPanel') +export const Account = () => { + const { t } = useTranslation('account') const [searchParams] = useSearchParams() - const defaultActiveTabKey = UserPanelHelper.defineSelectedTabKey(searchParams) + const defaultActiveTabKey = AccountHelper.defineSelectedTabKey(searchParams) + + const rootHierarchy = UpwardHierarchyNodeMother.createCollection({ + name: 'Root', + id: 'root' + }) return (
+ +

{t('pageTitle')}

diff --git a/src/sections/account/AccountFactory.tsx b/src/sections/account/AccountFactory.tsx new file mode 100644 index 000000000..891050ef3 --- /dev/null +++ b/src/sections/account/AccountFactory.tsx @@ -0,0 +1,8 @@ +import { ReactElement } from 'react' +import { Account } from './Account' + +export class AccountFactory { + static create(): ReactElement { + return + } +} diff --git a/src/sections/account/AccountHelper.ts b/src/sections/account/AccountHelper.ts new file mode 100644 index 000000000..991d1f8cd --- /dev/null +++ b/src/sections/account/AccountHelper.ts @@ -0,0 +1,19 @@ +export class AccountHelper { + static ACCOUNT_PANEL_TABS_KEYS = { + myData: 'myData', + notifications: 'notifications', + accountInformation: 'accountInformation', + apiToken: 'apiToken' + } + + static ACCOUNT_PANEL_TAB_QUERY_KEY = 'tab' + + public static defineSelectedTabKey(searchParams: URLSearchParams): string { + const tabValue = searchParams.get(this.ACCOUNT_PANEL_TAB_QUERY_KEY) + + return ( + this.ACCOUNT_PANEL_TABS_KEYS[tabValue as keyof typeof this.ACCOUNT_PANEL_TABS_KEYS] ?? + this.ACCOUNT_PANEL_TABS_KEYS.myData + ) + } +} diff --git a/src/sections/account/ApiTokenSection/ApiTokenSection.module.scss b/src/sections/account/ApiTokenSection/ApiTokenSection.module.scss new file mode 100644 index 000000000..09b71bea3 --- /dev/null +++ b/src/sections/account/ApiTokenSection/ApiTokenSection.module.scss @@ -0,0 +1,15 @@ +.exp-date { + display: flex; + gap: 1.5rem; + align-items: center; + padding-left: 0.5rem; + font-weight: bold; + + time { + font-weight: normal; + } + + @media (min-width: 768px) { + gap: 3rem; + } +} diff --git a/src/sections/user-panel/ApiTokenSection.tsx b/src/sections/account/ApiTokenSection/ApiTokenSection.tsx similarity index 54% rename from src/sections/user-panel/ApiTokenSection.tsx rename to src/sections/account/ApiTokenSection/ApiTokenSection.tsx index 2bb06a425..12009927b 100644 --- a/src/sections/user-panel/ApiTokenSection.tsx +++ b/src/sections/account/ApiTokenSection/ApiTokenSection.tsx @@ -1,12 +1,13 @@ import { Trans, useTranslation } from 'react-i18next' -import styles from './UserPanel.module.scss' +import accountStyles from '../Account.module.scss' +import styles from './ApiTokenSection.module.scss' export const ApiTokenSection = () => { - const { t } = useTranslation('userPanel', { keyPrefix: 'apiToken' }) + const { t } = useTranslation('account', { keyPrefix: 'apiToken' }) return ( -
-

+ <> +

{ }} />

-
+

+ Expiration Date +

+ ) } diff --git a/src/sections/user-panel/UserPanelFactory.tsx b/src/sections/user-panel/UserPanelFactory.tsx deleted file mode 100644 index 91abc86ad..000000000 --- a/src/sections/user-panel/UserPanelFactory.tsx +++ /dev/null @@ -1,8 +0,0 @@ -import { ReactElement } from 'react' -import { UserPanel } from './UserPanel' - -export class UserPanelFactory { - static create(): ReactElement { - return - } -} diff --git a/src/sections/user-panel/UserPanelHelper.ts b/src/sections/user-panel/UserPanelHelper.ts deleted file mode 100644 index 58cbc87c5..000000000 --- a/src/sections/user-panel/UserPanelHelper.ts +++ /dev/null @@ -1,19 +0,0 @@ -export class UserPanelHelper { - static USER_PANEL_TABS_KEYS = { - myData: 'myData', - notifications: 'notifications', - accountInformation: 'accountInformation', - apiToken: 'apiToken' - } - - static USER_PANEL_TAB_QUERY_KEY = 'tab' - - public static defineSelectedTabKey(searchParams: URLSearchParams): string { - const tabValue = searchParams.get(this.USER_PANEL_TAB_QUERY_KEY) - - return ( - this.USER_PANEL_TABS_KEYS[tabValue as keyof typeof this.USER_PANEL_TABS_KEYS] ?? - this.USER_PANEL_TABS_KEYS.myData - ) - } -} From 9f3fed4a1b7277ce37fdd715aa0a05f250d5190d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Germ=C3=A1n=20Saracca?= Date: Wed, 4 Sep 2024 14:54:07 -0300 Subject: [PATCH 3/9] feat: ui panel work done --- public/locales/en/account.json | 6 ++- src/sections/account/Account.tsx | 2 +- .../ApiTokenSection.module.scss | 15 ------ .../ApiTokenSection/ApiTokenSection.tsx | 30 ----------- .../ApiTokenSection.module.scss | 31 ++++++++++++ .../api-token-section/ApiTokenSection.tsx | 50 +++++++++++++++++++ 6 files changed, 87 insertions(+), 47 deletions(-) delete mode 100644 src/sections/account/ApiTokenSection/ApiTokenSection.module.scss delete mode 100644 src/sections/account/ApiTokenSection/ApiTokenSection.tsx create mode 100644 src/sections/account/api-token-section/ApiTokenSection.module.scss create mode 100644 src/sections/account/api-token-section/ApiTokenSection.tsx diff --git a/public/locales/en/account.json b/public/locales/en/account.json index 6ce0c6c52..b7768f780 100644 --- a/public/locales/en/account.json +++ b/public/locales/en/account.json @@ -7,6 +7,10 @@ "apiToken": "API token" }, "apiToken": { - "helperText": "Your API Token is valid for a year. Check out our API Guide for more information on using your API Token with the Dataverse APIs." + "helperText": "Your API Token is valid for a year. Check out our API Guide for more information on using your API Token with the Dataverse APIs.", + "expirationDate": "Expiration date", + "copyToClipboard": "Copy to Clipboard", + "recreateToken": "Recreate Token", + "revokeToken": "Revoke Token" } } diff --git a/src/sections/account/Account.tsx b/src/sections/account/Account.tsx index 05a0281e3..5a472dd3b 100644 --- a/src/sections/account/Account.tsx +++ b/src/sections/account/Account.tsx @@ -2,7 +2,7 @@ import { useTranslation } from 'react-i18next' import { useSearchParams } from 'react-router-dom' import { Tabs } from '@iqss/dataverse-design-system' import { AccountHelper } from './AccountHelper' -import { ApiTokenSection } from './ApiTokenSection/ApiTokenSection' +import { ApiTokenSection } from './api-token-section/ApiTokenSection' import { BreadcrumbsGenerator } from '../shared/hierarchy/BreadcrumbsGenerator' import { UpwardHierarchyNodeMother } from '../../../tests/component/shared/hierarchy/domain/models/UpwardHierarchyNodeMother' import styles from './Account.module.scss' diff --git a/src/sections/account/ApiTokenSection/ApiTokenSection.module.scss b/src/sections/account/ApiTokenSection/ApiTokenSection.module.scss deleted file mode 100644 index 09b71bea3..000000000 --- a/src/sections/account/ApiTokenSection/ApiTokenSection.module.scss +++ /dev/null @@ -1,15 +0,0 @@ -.exp-date { - display: flex; - gap: 1.5rem; - align-items: center; - padding-left: 0.5rem; - font-weight: bold; - - time { - font-weight: normal; - } - - @media (min-width: 768px) { - gap: 3rem; - } -} diff --git a/src/sections/account/ApiTokenSection/ApiTokenSection.tsx b/src/sections/account/ApiTokenSection/ApiTokenSection.tsx deleted file mode 100644 index 12009927b..000000000 --- a/src/sections/account/ApiTokenSection/ApiTokenSection.tsx +++ /dev/null @@ -1,30 +0,0 @@ -import { Trans, useTranslation } from 'react-i18next' -import accountStyles from '../Account.module.scss' -import styles from './ApiTokenSection.module.scss' - -export const ApiTokenSection = () => { - const { t } = useTranslation('account', { keyPrefix: 'apiToken' }) - - return ( - <> -

- - ) - }} - /> -

-

- Expiration Date -

- - ) -} diff --git a/src/sections/account/api-token-section/ApiTokenSection.module.scss b/src/sections/account/api-token-section/ApiTokenSection.module.scss new file mode 100644 index 000000000..b6927fe53 --- /dev/null +++ b/src/sections/account/api-token-section/ApiTokenSection.module.scss @@ -0,0 +1,31 @@ +@import 'node_modules/@iqss/dataverse-design-system/src/lib/assets/styles/design-tokens/colors.module'; + +.exp-date { + display: flex; + gap: 1.5rem; + align-items: center; + padding-left: 0.5rem; + font-weight: bold; + + time { + font-weight: normal; + } + + @media (min-width: 768px) { + gap: 3rem; + } +} + +.api-token { + padding: 0.5rem 1rem; + background-color: #f7f7f9; + border: solid 1px $dv-border-color; + border-radius: 4px; +} + +.btns-wrapper { + display: flex; + gap: 0.5rem; + align-items: center; + padding-top: 1rem; +} diff --git a/src/sections/account/api-token-section/ApiTokenSection.tsx b/src/sections/account/api-token-section/ApiTokenSection.tsx new file mode 100644 index 000000000..66fcdce0a --- /dev/null +++ b/src/sections/account/api-token-section/ApiTokenSection.tsx @@ -0,0 +1,50 @@ +import { Trans, useTranslation } from 'react-i18next' +import accountStyles from '../Account.module.scss' +import styles from './ApiTokenSection.module.scss' +import { Button } from '@iqss/dataverse-design-system' + +export const ApiTokenSection = () => { + const { t } = useTranslation('account', { keyPrefix: 'apiToken' }) + + const apiToken = '999fff-666rrr-12kfd54-123123' + const expirationDate = '2025-09-04' + + const copyToClipboard = () => { + navigator.clipboard.writeText(apiToken).catch((error) => { + console.error('Failed to copy text:', error) + }) + } + + return ( + <> +

+ + ) + }} + /> +

+

+ {t('expirationDate')} +

+
+ {apiToken} +
+
+ + + +
+ + ) +} From 4ed835deeaabef4fa160047dcd2b32d73aaab829 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Germ=C3=A1n=20Saracca?= Date: Thu, 5 Sep 2024 10:06:01 -0300 Subject: [PATCH 4/9] feat: header link to account api token tab --- public/locales/en/header.json | 3 ++- src/sections/account/Account.tsx | 20 +++++++++++++++---- .../ApiTokenSection.module.scss | 1 + .../api-token-section/ApiTokenSection.tsx | 10 +++++++--- .../layout/header/LoggedInHeaderActions.tsx | 6 ++++++ 5 files changed, 32 insertions(+), 8 deletions(-) diff --git a/public/locales/en/header.json b/public/locales/en/header.json index 0a7d4df8e..b9313292b 100644 --- a/public/locales/en/header.json +++ b/public/locales/en/header.json @@ -7,6 +7,7 @@ "navigation": { "addData": "Add Data", "newCollection": "New Collection", - "newDataset": "New Dataset" + "newDataset": "New Dataset", + "apiToken": "API Token" } } diff --git a/src/sections/account/Account.tsx b/src/sections/account/Account.tsx index 5a472dd3b..2b68ac971 100644 --- a/src/sections/account/Account.tsx +++ b/src/sections/account/Account.tsx @@ -1,6 +1,6 @@ import { useTranslation } from 'react-i18next' import { useSearchParams } from 'react-router-dom' -import { Tabs } from '@iqss/dataverse-design-system' +import { Alert, Tabs } from '@iqss/dataverse-design-system' import { AccountHelper } from './AccountHelper' import { ApiTokenSection } from './api-token-section/ApiTokenSection' import { BreadcrumbsGenerator } from '../shared/hierarchy/BreadcrumbsGenerator' @@ -29,13 +29,25 @@ export const Account = () => { -
My Data here.
+
+ + Work in progress + +
-
Notifications here.
+
+ + Work in progress + +
-
Account Information.
+
+ + Work in progress + +
diff --git a/src/sections/account/api-token-section/ApiTokenSection.module.scss b/src/sections/account/api-token-section/ApiTokenSection.module.scss index b6927fe53..292eb1829 100644 --- a/src/sections/account/api-token-section/ApiTokenSection.module.scss +++ b/src/sections/account/api-token-section/ApiTokenSection.module.scss @@ -25,6 +25,7 @@ .btns-wrapper { display: flex; + flex-wrap: wrap; gap: 0.5rem; align-items: center; padding-top: 1rem; diff --git a/src/sections/account/api-token-section/ApiTokenSection.tsx b/src/sections/account/api-token-section/ApiTokenSection.tsx index 66fcdce0a..5ea4669c0 100644 --- a/src/sections/account/api-token-section/ApiTokenSection.tsx +++ b/src/sections/account/api-token-section/ApiTokenSection.tsx @@ -1,7 +1,7 @@ import { Trans, useTranslation } from 'react-i18next' +import { Button } from '@iqss/dataverse-design-system' import accountStyles from '../Account.module.scss' import styles from './ApiTokenSection.module.scss' -import { Button } from '@iqss/dataverse-design-system' export const ApiTokenSection = () => { const { t } = useTranslation('account', { keyPrefix: 'apiToken' }) @@ -42,8 +42,12 @@ export const ApiTokenSection = () => { - - + +
) diff --git a/src/sections/layout/header/LoggedInHeaderActions.tsx b/src/sections/layout/header/LoggedInHeaderActions.tsx index 031bf4338..0fc30205c 100644 --- a/src/sections/layout/header/LoggedInHeaderActions.tsx +++ b/src/sections/layout/header/LoggedInHeaderActions.tsx @@ -7,6 +7,7 @@ import { Route, RouteWithParams } from '../../Route.enum' import { User } from '../../../users/domain/models/User' import { CollectionRepository } from '../../../collection/domain/repositories/CollectionRepository' import { ROOT_COLLECTION_ALIAS } from '../../../collection/domain/models/Collection' +import { AccountHelper } from '../../account/AccountHelper' const currentPage = 0 @@ -56,6 +57,11 @@ export const LoggedInHeaderActions = ({ + + {t('navigation.apiToken')} + {t('logOut')} From 37e55e65c13906b022604f21f648f5a0750bf157 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Germ=C3=A1n=20Saracca?= Date: Thu, 5 Sep 2024 10:29:29 -0300 Subject: [PATCH 5/9] feat(design system): add disabled prop to tab --- packages/design-system/CHANGELOG.md | 1 + .../src/lib/components/tabs/Tab.tsx | 5 +++-- .../src/lib/stories/tabs/Tabs.stories.tsx | 16 ++++++++++++++++ 3 files changed, 20 insertions(+), 2 deletions(-) diff --git a/packages/design-system/CHANGELOG.md b/packages/design-system/CHANGELOG.md index 992bef245..51ec69460 100644 --- a/packages/design-system/CHANGELOG.md +++ b/packages/design-system/CHANGELOG.md @@ -48,6 +48,7 @@ See [Conventional Commits](https://conventionalcommits.org) for commit guideline - **Stack:** NEW Stack element to manage layouts. - **TransferList:** NEW TransferList component to transfer items between two list, also sortable. - **Table:** extend Props Interface to accept `bordered` prop to add or remove borders on all sides of the table and cells. Defaults to true. +- **Tab:** extend Props Interface to accept `disabled` prop to disable the tab. # [1.1.0](https://github.com/IQSS/dataverse-frontend/compare/@iqss/dataverse-design-system@1.0.1...@iqss/dataverse-design-system@1.1.0) (2024-03-12) diff --git a/packages/design-system/src/lib/components/tabs/Tab.tsx b/packages/design-system/src/lib/components/tabs/Tab.tsx index 5f1ef3cbb..9ba07a6a1 100644 --- a/packages/design-system/src/lib/components/tabs/Tab.tsx +++ b/packages/design-system/src/lib/components/tabs/Tab.tsx @@ -4,11 +4,12 @@ import { Tab as TabBS } from 'react-bootstrap' export interface TabProps { title: string eventKey: string + disabled?: boolean } -export function Tab({ title, eventKey, children }: PropsWithChildren) { +export function Tab({ title, eventKey, disabled = false, children }: PropsWithChildren) { return ( - + {children} ) diff --git a/packages/design-system/src/lib/stories/tabs/Tabs.stories.tsx b/packages/design-system/src/lib/stories/tabs/Tabs.stories.tsx index e9f8a5708..8cb7c1adf 100644 --- a/packages/design-system/src/lib/stories/tabs/Tabs.stories.tsx +++ b/packages/design-system/src/lib/stories/tabs/Tabs.stories.tsx @@ -43,3 +43,19 @@ export const Default: Story = {
) } + +export const SomeTabDisabled: Story = { + render: () => ( + + + + + + + + + + + + ) +} From 820f40d461b0424863c569a735cdb7173afd52ec Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Germ=C3=A1n=20Saracca?= Date: Thu, 5 Sep 2024 11:42:34 -0300 Subject: [PATCH 6/9] feat: add tests and case when there is no token created --- public/locales/en/account.json | 4 +- src/sections/account/Account.tsx | 36 ++++++----- .../api-token-section/ApiTokenSection.tsx | 59 ++++++++++++------- .../sections/account/Account.spec.tsx | 14 +++++ .../sections/account/ApiTokenSection.spec.tsx | 24 ++++++++ 5 files changed, 96 insertions(+), 41 deletions(-) create mode 100644 tests/component/sections/account/Account.spec.tsx create mode 100644 tests/component/sections/account/ApiTokenSection.spec.tsx diff --git a/public/locales/en/account.json b/public/locales/en/account.json index b7768f780..88de9cad5 100644 --- a/public/locales/en/account.json +++ b/public/locales/en/account.json @@ -8,9 +8,11 @@ }, "apiToken": { "helperText": "Your API Token is valid for a year. Check out our API Guide for more information on using your API Token with the Dataverse APIs.", + "notCreatedApiToken": "API Token for Dataverse Admin has not been created.", "expirationDate": "Expiration date", "copyToClipboard": "Copy to Clipboard", "recreateToken": "Recreate Token", - "revokeToken": "Revoke Token" + "revokeToken": "Revoke Token", + "createToken": "Create Token" } } diff --git a/src/sections/account/Account.tsx b/src/sections/account/Account.tsx index 2b68ac971..4e6afd1b2 100644 --- a/src/sections/account/Account.tsx +++ b/src/sections/account/Account.tsx @@ -1,16 +1,19 @@ import { useTranslation } from 'react-i18next' import { useSearchParams } from 'react-router-dom' -import { Alert, Tabs } from '@iqss/dataverse-design-system' +import { Tabs } from '@iqss/dataverse-design-system' +import { useLoading } from '../loading/LoadingContext' import { AccountHelper } from './AccountHelper' import { ApiTokenSection } from './api-token-section/ApiTokenSection' import { BreadcrumbsGenerator } from '../shared/hierarchy/BreadcrumbsGenerator' import { UpwardHierarchyNodeMother } from '../../../tests/component/shared/hierarchy/domain/models/UpwardHierarchyNodeMother' import styles from './Account.module.scss' +import { useEffect } from 'react' const tabsKeys = AccountHelper.ACCOUNT_PANEL_TABS_KEYS export const Account = () => { const { t } = useTranslation('account') + const { setIsLoading } = useLoading() const [searchParams] = useSearchParams() const defaultActiveTabKey = AccountHelper.defineSelectedTabKey(searchParams) @@ -19,6 +22,10 @@ export const Account = () => { id: 'root' }) + useEffect(() => { + setIsLoading(false) + }, [setIsLoading]) + return (
@@ -28,26 +35,17 @@ export const Account = () => { - -
- - Work in progress - -
+ +
- -
- - Work in progress - -
+ +
- -
- - Work in progress - -
+ +
diff --git a/src/sections/account/api-token-section/ApiTokenSection.tsx b/src/sections/account/api-token-section/ApiTokenSection.tsx index 5ea4669c0..a6a5e24c2 100644 --- a/src/sections/account/api-token-section/ApiTokenSection.tsx +++ b/src/sections/account/api-token-section/ApiTokenSection.tsx @@ -6,13 +6,15 @@ import styles from './ApiTokenSection.module.scss' export const ApiTokenSection = () => { const { t } = useTranslation('account', { keyPrefix: 'apiToken' }) - const apiToken = '999fff-666rrr-12kfd54-123123' + const apiToken = '999fff-666rrr-this-is-not-a-real-token-123456' const expirationDate = '2025-09-04' const copyToClipboard = () => { - navigator.clipboard.writeText(apiToken).catch((error) => { - console.error('Failed to copy text:', error) - }) + navigator.clipboard.writeText(apiToken).catch( + /* istanbul ignore next */ (error) => { + console.error('Failed to copy text:', error) + } + ) } return ( @@ -32,23 +34,38 @@ export const ApiTokenSection = () => { }} />

-

- {t('expirationDate')} -

-
- {apiToken} -
-
- - - -
+ {apiToken ? ( + <> +

+ {t('expirationDate')} +

+
+ {apiToken} +
+
+ + + +
+ + ) : ( + <> +
+ {t('notCreatedApiToken')} +
+
+ +
+ + )} ) } diff --git a/tests/component/sections/account/Account.spec.tsx b/tests/component/sections/account/Account.spec.tsx new file mode 100644 index 000000000..77fc048eb --- /dev/null +++ b/tests/component/sections/account/Account.spec.tsx @@ -0,0 +1,14 @@ +import { Account } from '../../../../src/sections/account/Account' + +describe('Account', () => { + it('should render the correct breadcrumbs', () => { + cy.mountAuthenticated() + + cy.findByRole('link', { name: 'Root' }).should('exist') + + cy.get('li[aria-current="page"]') + .should('exist') + .should('have.text', 'Account') + .should('have.class', 'active') + }) +}) diff --git a/tests/component/sections/account/ApiTokenSection.spec.tsx b/tests/component/sections/account/ApiTokenSection.spec.tsx new file mode 100644 index 000000000..26ff3220b --- /dev/null +++ b/tests/component/sections/account/ApiTokenSection.spec.tsx @@ -0,0 +1,24 @@ +import { ApiTokenSection } from '../../../../src/sections/account/api-token-section/ApiTokenSection' + +describe('ApiTokenSection', () => { + beforeEach(() => { + cy.mountAuthenticated() + }) + + it('should copy the api token to the clipboard', () => { + cy.window().then((win) => { + cy.stub(win.navigator.clipboard, 'writeText').resolves() + + cy.findByRole('button', { name: /Copy to Clipboard/ }).click() + + cy.get('[data-testid="api-token"]').then(($element) => { + const textToCopy = $element.text() + + // eslint-disable-next-line @typescript-eslint/unbound-method + cy.wrap(win.navigator.clipboard.writeText).should('be.calledWith', textToCopy) + }) + }) + }) + + // TODO: When we get the api token from the use case, we could mock the response and test more things. +}) From ef679735b512fca27b99645340eb630cc3df9d12 Mon Sep 17 00:00:00 2001 From: German Gonzalo Saracca Date: Fri, 6 Sep 2024 16:04:29 +0200 Subject: [PATCH 7/9] Update public/locales/en/account.json Co-authored-by: Philip Durbin --- public/locales/en/account.json | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/public/locales/en/account.json b/public/locales/en/account.json index 88de9cad5..41b74e884 100644 --- a/public/locales/en/account.json +++ b/public/locales/en/account.json @@ -1,10 +1,10 @@ { "pageTitle": "Account", "tabs": { - "myData": "My data", + "myData": "My Data", "notifications": "Notifications", - "accountInformation": "Account information", - "apiToken": "API token" + "accountInformation": "Account Information", + "apiToken": "API Token" }, "apiToken": { "helperText": "Your API Token is valid for a year. Check out our API Guide for more information on using your API Token with the Dataverse APIs.", From 1d98d459d0276795749cac8133797f684a6906ec Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Germ=C3=A1n=20Saracca?= Date: Fri, 13 Sep 2024 08:57:32 -0300 Subject: [PATCH 8/9] feat: add story --- src/sections/account/Account.tsx | 13 +++++++------ src/sections/account/AccountFactory.tsx | 11 ++++++++++- src/sections/account/AccountHelper.ts | 7 +++++-- src/stories/account/Account.stories.tsx | 22 ++++++++++++++++++++++ 4 files changed, 44 insertions(+), 9 deletions(-) create mode 100644 src/stories/account/Account.stories.tsx diff --git a/src/sections/account/Account.tsx b/src/sections/account/Account.tsx index 4e6afd1b2..eaa4090b2 100644 --- a/src/sections/account/Account.tsx +++ b/src/sections/account/Account.tsx @@ -1,21 +1,22 @@ +import { useEffect } from 'react' import { useTranslation } from 'react-i18next' -import { useSearchParams } from 'react-router-dom' import { Tabs } from '@iqss/dataverse-design-system' import { useLoading } from '../loading/LoadingContext' -import { AccountHelper } from './AccountHelper' +import { AccountHelper, AccountPanelTabKey } from './AccountHelper' import { ApiTokenSection } from './api-token-section/ApiTokenSection' import { BreadcrumbsGenerator } from '../shared/hierarchy/BreadcrumbsGenerator' import { UpwardHierarchyNodeMother } from '../../../tests/component/shared/hierarchy/domain/models/UpwardHierarchyNodeMother' import styles from './Account.module.scss' -import { useEffect } from 'react' const tabsKeys = AccountHelper.ACCOUNT_PANEL_TABS_KEYS -export const Account = () => { +interface AccountProps { + defaultActiveTabKey: AccountPanelTabKey +} + +export const Account = ({ defaultActiveTabKey }: AccountProps) => { const { t } = useTranslation('account') const { setIsLoading } = useLoading() - const [searchParams] = useSearchParams() - const defaultActiveTabKey = AccountHelper.defineSelectedTabKey(searchParams) const rootHierarchy = UpwardHierarchyNodeMother.createCollection({ name: 'Root', diff --git a/src/sections/account/AccountFactory.tsx b/src/sections/account/AccountFactory.tsx index 891050ef3..0ecbab6b5 100644 --- a/src/sections/account/AccountFactory.tsx +++ b/src/sections/account/AccountFactory.tsx @@ -1,8 +1,17 @@ import { ReactElement } from 'react' +import { useSearchParams } from 'react-router-dom' +import { AccountHelper } from './AccountHelper' import { Account } from './Account' export class AccountFactory { static create(): ReactElement { - return + return } } + +function AccountWithSearchParams() { + const [searchParams] = useSearchParams() + const defaultActiveTabKey = AccountHelper.defineSelectedTabKey(searchParams) + + return +} diff --git a/src/sections/account/AccountHelper.ts b/src/sections/account/AccountHelper.ts index 991d1f8cd..799a0bc5f 100644 --- a/src/sections/account/AccountHelper.ts +++ b/src/sections/account/AccountHelper.ts @@ -4,11 +4,11 @@ export class AccountHelper { notifications: 'notifications', accountInformation: 'accountInformation', apiToken: 'apiToken' - } + } as const static ACCOUNT_PANEL_TAB_QUERY_KEY = 'tab' - public static defineSelectedTabKey(searchParams: URLSearchParams): string { + public static defineSelectedTabKey(searchParams: URLSearchParams): AccountPanelTabKey { const tabValue = searchParams.get(this.ACCOUNT_PANEL_TAB_QUERY_KEY) return ( @@ -17,3 +17,6 @@ export class AccountHelper { ) } } + +export type AccountPanelTabKey = + (typeof AccountHelper.ACCOUNT_PANEL_TABS_KEYS)[keyof typeof AccountHelper.ACCOUNT_PANEL_TABS_KEYS] diff --git a/src/stories/account/Account.stories.tsx b/src/stories/account/Account.stories.tsx new file mode 100644 index 000000000..b19475721 --- /dev/null +++ b/src/stories/account/Account.stories.tsx @@ -0,0 +1,22 @@ +import { Meta, StoryObj } from '@storybook/react' +import { Account } from '../../sections/account/Account' +import { WithI18next } from '../WithI18next' +import { WithLayout } from '../WithLayout' +import { WithLoggedInUser } from '../WithLoggedInUser' +import { AccountHelper } from '../../sections/account/AccountHelper' + +const meta: Meta = { + title: 'Pages/Account', + component: Account, + decorators: [WithI18next, WithLayout, WithLoggedInUser], + parameters: { + // Sets the delay for all stories. + chromatic: { delay: 15000, pauseAnimationAtEnd: true } + } +} +export default meta +type Story = StoryObj + +export const APITokenTab: Story = { + render: () => +} From b31b1ab821d104f051bc7211a91aacee20284f6e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Germ=C3=A1n=20Saracca?= Date: Fri, 13 Sep 2024 09:56:56 -0300 Subject: [PATCH 9/9] chore: update upload-artifact to v3 --- .github/workflows/test.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 848e3fa76..17c3bf460 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -143,7 +143,7 @@ jobs: github-token: ${{ secrets.GITHUB_TOKEN }} - name: Upload Cypress screenshots - uses: actions/upload-artifact@v2 + uses: actions/upload-artifact@v3 if: failure() with: name: cypress-screenshots