diff --git a/app/app.ts b/app/app.ts index 090b170b..830e8db3 100644 --- a/app/app.ts +++ b/app/app.ts @@ -6,6 +6,7 @@ import { join } from 'path'; import Problem from 'api-problem'; import querystring from 'querystring'; +import { name as appName, version as appVersion } from './package.json'; import { getLogger, httpLogger } from './src/components/log'; import { getGitRevision, readIdpList } from './src/components/utils'; @@ -49,7 +50,7 @@ appRouter.get('/config', (_req: Request, res: Response, next: (err: unknown) => ...config.get('frontend'), gitRev: state.gitRev, idpList: state.idpList, - version: process.env.npm_package_version + version: appVersion }); } catch (err) { next(err); @@ -64,9 +65,9 @@ appRouter.get('/api', (_req: Request, res: Response): void => { res.status(200).json({ app: { gitRev: state.gitRev, - name: process.env.npm_package_name, + name: appName, nodeVersion: process.version, - version: process.env.npm_package_version + version: appVersion }, endpoints: ['/api/v1'], versions: [1] @@ -91,7 +92,7 @@ app.use((err: Problem, _req: Request, res: Response, _next: () => void): void => err.send(res, null); } else { new Problem(500, 'Server Error', { - detail: (err.message) ? err.message : err + detail: err.message ? err.message : err }).send(res); } }); diff --git a/app/tsconfig.json b/app/tsconfig.json index bbb05680..e5ca9a50 100644 --- a/app/tsconfig.json +++ b/app/tsconfig.json @@ -32,7 +32,7 @@ // "types": [], /* Specify type package names to be included without being referenced in a source file. */ // "allowUmdGlobalAccess": true, /* Allow accessing UMD globals from modules. */ // "moduleSuffixes": [], /* List of file name suffixes to search when resolving a module. */ - // "resolveJsonModule": true, /* Enable importing .json files. */ + "resolveJsonModule": true, /* Enable importing .json files. */ // "noResolve": true, /* Disallow 'import's, 'require's or '<reference>'s from expanding the number of files TypeScript should add to a project. */ /* JavaScript Support */ // "allowJs": true, /* Allow JavaScript files to be a part of your program. Use the 'checkJS' option to get errors from these files. */ diff --git a/frontend/package-lock.json b/frontend/package-lock.json index 22cb29e3..283dab19 100644 --- a/frontend/package-lock.json +++ b/frontend/package-lock.json @@ -21,7 +21,7 @@ "pinia-plugin-persistedstate": "^3.2.0", "primeflex": "^3.3.1", "primeicons": "^6.0.1", - "primevue": "~3.34.1", + "primevue": "^3.40.1", "qrcode.vue": "^3.4.1", "vee-validate": "^4.11.8", "vue": "^3.3.7", @@ -5472,9 +5472,9 @@ "integrity": "sha512-KDeO94CbWI4pKsPnYpA1FPjo79EsY9I+M8ywoPBSf9XMXoe/0crjbUK7jcQEDHuc0ZMRIZsxH3TYLv4TUtHmAA==" }, "node_modules/primevue": { - "version": "3.34.1", - "resolved": "https://registry.npmjs.org/primevue/-/primevue-3.34.1.tgz", - "integrity": "sha512-5QPy8I+TMYSQgC0Bs/9vINsOVjgCOQFAr6uz49Wzcj8u04qJ2mG/z6OhAana+f4yKTTHVwHLVnuGkrIp/nI9DA==", + "version": "3.40.1", + "resolved": "https://registry.npmjs.org/primevue/-/primevue-3.40.1.tgz", + "integrity": "sha512-TIFjoSUDiTmlxwQddaWckzcPIpj0F8a6ZMnm0tpAD/ieyUIHnNpbAi5de8LQf8eF0b+x5EkOkdjdngSlD+iPCw==", "peerDependencies": { "vue": "^3.0.0" } @@ -10983,9 +10983,9 @@ "integrity": "sha512-KDeO94CbWI4pKsPnYpA1FPjo79EsY9I+M8ywoPBSf9XMXoe/0crjbUK7jcQEDHuc0ZMRIZsxH3TYLv4TUtHmAA==" }, "primevue": { - "version": "3.34.1", - "resolved": "https://registry.npmjs.org/primevue/-/primevue-3.34.1.tgz", - "integrity": "sha512-5QPy8I+TMYSQgC0Bs/9vINsOVjgCOQFAr6uz49Wzcj8u04qJ2mG/z6OhAana+f4yKTTHVwHLVnuGkrIp/nI9DA==", + "version": "3.40.1", + "resolved": "https://registry.npmjs.org/primevue/-/primevue-3.40.1.tgz", + "integrity": "sha512-TIFjoSUDiTmlxwQddaWckzcPIpj0F8a6ZMnm0tpAD/ieyUIHnNpbAi5de8LQf8eF0b+x5EkOkdjdngSlD+iPCw==", "requires": {} }, "property-expr": { diff --git a/frontend/package.json b/frontend/package.json index 41137823..f7ffd692 100644 --- a/frontend/package.json +++ b/frontend/package.json @@ -36,7 +36,7 @@ "pinia-plugin-persistedstate": "^3.2.0", "primeflex": "^3.3.1", "primeicons": "^6.0.1", - "primevue": "~3.34.1", + "primevue": "^3.40.1", "qrcode.vue": "^3.4.1", "vee-validate": "^4.11.8", "vue": "^3.3.7", diff --git a/frontend/src/App.vue b/frontend/src/App.vue index 1400ec50..04abafb9 100644 --- a/frontend/src/App.vue +++ b/frontend/src/App.vue @@ -44,15 +44,28 @@ onErrorCaptured((e: Error) => { </script> <template> - <ConfirmDialog /> - <ProgressLoader v-if="getIsLoading" /> - <Toast /> - <AppLayout> - <template #nav> - <Navbar /> - </template> - <template #main> - <RouterView v-if="ready" /> - </template> - </AppLayout> + <div class="container"> + <ConfirmDialog /> + <ProgressLoader v-if="getIsLoading" /> + <Toast /> + + <AppLayout> + <template #nav> + <Navbar /> + </template> + <template #main> + <RouterView v-if="ready" /> + </template> + </AppLayout> + </div> </template> + +<style scoped> +.container { + display: flex; + align-items: center; + justify-content: center; + min-height: 100vh; + width: 100%; +} +</style> diff --git a/frontend/src/assets/base.css b/frontend/src/assets/base.css deleted file mode 100644 index e910a752..00000000 --- a/frontend/src/assets/base.css +++ /dev/null @@ -1,86 +0,0 @@ -/* color palette from <https://github.com/vuejs/theme> */ -:root { - --vt-c-white: #ffffff; - --vt-c-white-soft: #f8f8f8; - --vt-c-white-mute: #f2f2f2; - - --vt-c-black: #181818; - --vt-c-black-soft: #222222; - --vt-c-black-mute: #282828; - - --vt-c-indigo: #2c3e50; - - --vt-c-divider-light-1: rgba(60, 60, 60, 0.29); - --vt-c-divider-light-2: rgba(60, 60, 60, 0.12); - --vt-c-divider-dark-1: rgba(84, 84, 84, 0.65); - --vt-c-divider-dark-2: rgba(84, 84, 84, 0.48); - - --vt-c-text-light-1: var(--vt-c-indigo); - --vt-c-text-light-2: rgba(60, 60, 60, 0.66); - --vt-c-text-dark-1: var(--vt-c-white); - --vt-c-text-dark-2: rgba(235, 235, 235, 0.64); -} - -/* semantic color variables for this project */ -:root { - --color-background: var(--vt-c-white); - --color-background-soft: var(--vt-c-white-soft); - --color-background-mute: var(--vt-c-white-mute); - - --color-border: var(--vt-c-divider-light-2); - --color-border-hover: var(--vt-c-divider-light-1); - - --color-heading: var(--vt-c-text-light-1); - --color-text: var(--vt-c-text-light-1); - - --section-gap: 160px; -} - -/* @media (prefers-color-scheme: dark) { - :root { - --color-background: var(--vt-c-black); - --color-background-soft: var(--vt-c-black-soft); - --color-background-mute: var(--vt-c-black-mute); - - --color-border: var(--vt-c-divider-dark-2); - --color-border-hover: var(--vt-c-divider-dark-1); - - --color-heading: var(--vt-c-text-dark-1); - --color-text: var(--vt-c-text-dark-2); - } -} */ - -*, -*::before, -*::after { - box-sizing: border-box; - margin: 0; - font-weight: normal; -} - -body { - min-height: 100vh; - color: var(--color-text); - background: var(--color-background); - transition: - color 0.5s, - background-color 0.5s; - line-height: 1.6; - font-family: - BCSans, - Inter, - -apple-system, - BlinkMacSystemFont, - 'Segoe UI', - Roboto, - Oxygen, - Ubuntu, - Cantarell, - 'Fira Sans', - 'Droid Sans', - 'Helvetica Neue', - sans-serif; - text-rendering: optimizeLegibility; - -webkit-font-smoothing: antialiased; - -moz-osx-font-smoothing: grayscale; -} diff --git a/frontend/src/assets/main.scss b/frontend/src/assets/main.scss index 13ba55d4..3f32eeb0 100644 --- a/frontend/src/assets/main.scss +++ b/frontend/src/assets/main.scss @@ -1,13 +1,75 @@ -@import './base.css'; -@import './primevue.scss'; -@import './variables.scss'; +:root { + font-size: 16px; +} + +body, +body::before, +body::after { + box-sizing: border-box; + margin: 0; +} -#app { - margin: 0 auto; +body { + min-height: 100vh; + color: var(--text-color); + background: white; + transition: + color 0.5s, + background-color 0.5s; + font-family: + BCSans, + Inter, + -apple-system, + BlinkMacSystemFont, + "Segoe UI", + Roboto, + Oxygen, + Ubuntu, + Cantarell, + "Fira Sans", + "Droid Sans", + "Helvetica Neue", + sans-serif; + line-height: 1.6; font-weight: normal; + text-rendering: optimizeLegibility; + -webkit-font-smoothing: antialiased; + -moz-osx-font-smoothing: grayscale; +} + +/* text */ +h1, +h2, +h3, +h4, +h5, +h6 { + margin: 0; + padding: 0; + font-weight: 600; + // line-height: 1.2em; +} + +h1 { + font-size: 2.074rem; +} +h2 { + font-size: 1.728rem; +} +h3 { + font-size: 1.44rem; +} +h4 { + font-size: 1.2rem; +} +h5 { + font-size: 1.1rem; +} + +p { + margin-top: 0; } -// ----- links and buttons: a, a:visited { color: $bcbox-link-text; @@ -17,20 +79,14 @@ a:visited { } } -.p-button, -.p-inputswitch-slider { - &:hover { - opacity: 0.8; - } -} -// underline button text -.p-button:hover { - text-decoration: underline; -} -// don't underline button icons -.p-button .p-button-icon:before { - text-decoration: none; +.wrap-block { display: inline-block; + overflow-wrap: break-word; + width: 100%; + + td { + width: inherit; + } } .truncate { @@ -47,130 +103,155 @@ a:visited { text-indent: 0 !important; } -// -------- layout - -.content-center { - text-align: center !important; -} - -.content-right { - text-align: right !important; -} - -.permissions-modal { - width: 800px; +.drop-shadow { + box-shadow: 0 6px 6px -1px rgb(145, 145, 145); } -// details page / sidebar -.details-grid { - h2 { - margin-bottom: 1rem; +/* layout */ +.layout-main { + margin: 1rem; + @media screen and (min-width: 992px) { + margin: 1rem 5rem 1rem 5rem; } - .col-fixed { - width: 150px; // label column + @media screen and (min-width: 1600px) { + margin: 1rem 15% 1rem 15%; } - // make datatable look like grid - .p-datatable { - thead th { - padding-top: 0; +} + +/* footer */ +.gov-footer { + background-color: #003366 !important; + border-top: 2px solid #fcba19; + a { + display: inline-block; + padding: 0.5rem 1rem; + color: #ffffff; + font-size: 1rem; + text-decoration: none; + &:hover { + text-decoration: underline; } - // highlight the row for the currently selected version - tr.selected-row { - background-color: $bcbox-highlight-background !important; + &:focus { + outline: none; } - td { - padding: 0.5rem; + &:visited { + color: #ffffff; } - th:first-child, - td:first-child { - padding-left: 0; + } + + & > div:last-child { + order: 1; + } + .version { + color: #ffffff; + float: right; + } +} + +/* buttons */ +.p-button:hover { + text-decoration: underline; + opacity: 0.8; +} +.p-button .p-button-icon:before { + text-decoration: none; + display: inline-block; +} + +.p-button { + border-width: 2px; + &:not(.p-button-secondary, .p-button-success, .p-button-info, .p-button-warning, .p-button-help, .p-button-danger) { + color: $bcbox-primary; + &:not(.p-button-outlined, .p-button-text) { + background-color: $bcbox-primary; + border-color: $bcbox-primary; + color: $bcbox-outline-on-primary; } } } -.details-value-column { - width: 40rem; + +.p-button-outlined { + border-width: 2px; } -.sidebar .details-value-column { - width: 20rem; +.p-confirm-dialog-reject { + border: 2px solid $bcbox-primary; } -// eof details page / sidebar -// wrap text -.wrap-block { - display: inline-block; - overflow-wrap: break-word; - width: 100%; +/* checkboxes, radios, input switches */ +.p-checkbox-checked .p-checkbox-box, +.p-checkbox-box.p-highlight, +.p-radiobutton-checked .p-radiobutton-box, +.p-inputswitch-checked .p-inputswitch-slider:not(.p-disabled) { + background-color: $bcbox-primary; + border-color: $bcbox-primary; + &:hover { + opacity: 0.8; + } } -td .wrap-block { - width: inherit; +.p-tag { + background-color: $bcbox-primary; + font-size: 1rem; + padding: 0.25rem 0.75rem; + font-weight: 400; } -// --------- Info/settings dialog modals -.bcbox-info-dialog { - &.p-dialog { - .p-dialog-header { - padding-bottom: 0; - - .svg-inline--fa { - color: $bcbox-primary; - font-size: 1.8rem; - padding-right: 0.75rem; - padding-top: 0.15rem; - } +/* datatable */ +.p-datatable, +.p-treetable { + .p-datatable-loading-overlay, + .p-treetable-loading-overlay { + background: white; + opacity: 0.8; + } - .p-dialog-title { - flex-grow: 1; - font-size: 1.8rem; - font-weight: bold; - } - } + thead > tr > th { + background-color: transparent !important; + } - .bcbox-info-dialog-subhead { - font-weight: normal; - margin-bottom: 1.5rem; - padding-left: 3.1rem; - @extend .wrap-block; + &.p-datatable-striped tbody > tr { + &:nth-child(even) { + background-color: $bcbox-table-stripe-background; } } -} - -.drop-shadow { - box-shadow: 0 6px 6px -1px rgb(145, 145, 145); -} - -.gov-footer { - background-color: #003366 !important; - border-top: 2px solid #fcba19; - flex-shrink: 0; - min-height: 2.5rem; - min-width: 100%; - padding-bottom: 0; - padding-top: 0; - a { - color: #ffffff; - font-size: 1rem; - text-decoration: none; - &:focus { - outline: none; + tbody { + tr { + &.p-highlight, + &.selected-row { + background: $bcbox-highlight-background !important; + } + &:focus { + outline: none !important; + } } } - .button > span { - color: #ffffff; - font-size: 1rem; - font-weight: normal; - text-decoration: none; - text-transform: none; + .p-column-title { + font-weight: bold; } -} -// ---------- datatables + .p-paginator { + justify-content: right; + } -.p-datatable { - .p-datatable-loading-overlay { - background: white; - opacity: 0.8; + .header-center .p-column-header-content { + justify-content: center; + } + .content-center { + text-align: center !important; + } + .header-right .p-column-header-content { + justify-content: right; + } + .action-buttons { + text-align: right; + // width: 150px; + } + + .action-buttons .p-button { + padding: 0; + margin-left: 1rem; + font-size: 1.25rem; } } @@ -180,7 +261,99 @@ td .wrap-block { cursor: pointer; } } + .p-input-icon-clear-right { position: absolute !important; right: 0rem; } + +/* modals */ +.bcbox-info-dialog { + width: 800px; + .p-dialog-header { + padding-bottom: 0; + + .svg-inline--fa { + color: $bcbox-primary; + font-size: 1.8rem; + padding-right: 0.75rem; + border: 0; + } + + .p-dialog-title { + flex-grow: 1; + @extend h2; + } + } + + .bcbox-info-dialog-subhead { + font-weight: normal; + margin-bottom: 1.5rem; + padding-left: 3.1rem; + @extend .wrap-block; + } +} + +.p-confirm-dialog { + max-width: 50%; +} + +.p-dialog-footer { + display: flex; + flex-direction: row-reverse; + justify-content: left; +} + +.p-tabview-header.p-disabled .p-tabview-nav-link { + color: gray; +} +.p-tabview-header:not(.p-disabled) .p-tabview-nav-link { + border-color: $bcbox-link-text; +} + +/* side panel */ + +.side-panel { + .panel-header { + margin-bottom: 1.5rem; + + & > .svg-inline--fa { + color: $bcbox-primary; + margin-top: 0.4rem; + font-size: 1.7rem; + } + .p-button .svg-inline--fa { + margin-top: 0.5rem; + font-size: 1.2rem; + } + } + h1 { + font-size: 1.728rem; + } + h2 { + font-size: 1.44rem; + margin-bottom: 0.5rem; + } +} + +/* details grid */ + +.details-grid { + h2 { + margin-bottom: 1rem; + } + .col-fixed { + width: 150px; // label column + } + .details-value-column { + width: 40rem; + } + .sidebar .details-value-column { + width: 20rem; + } +} + +/* share modal */ +a.p-tabview-header-action { + text-decoration: none; +} diff --git a/frontend/src/assets/primevue.scss b/frontend/src/assets/primevue.scss deleted file mode 100644 index af598ab2..00000000 --- a/frontend/src/assets/primevue.scss +++ /dev/null @@ -1,170 +0,0 @@ -.header-center .p-column-header-content { - justify-content: center; -} - -// For datatables -.header-right .p-column-header-content { - justify-content: right; -} - -// For treetables -.header-right .p-column-title { - display: flex; - justify-content: right; -} - -.p-dialog-footer { - display: flex; - flex-direction: row-reverse; -} - -.p-datatable { - .p-datatable-thead > tr > th { - background-color: transparent !important; - } - - &.p-datatable-striped .p-datatable-tbody > tr { - &:nth-child(even) { - background-color: $bcbox-table-stripe-background; - } - } - - tbody { - tr { - &.p-highlight { - background: $bcbox-highlight-background !important; - } - - &:focus { - outline: none !important; - } - } - } - - .p-checkbox { - .p-checkbox-box.p-highlight { - background-color: $bcbox-primary; - border-color: $bcbox-primary !important; - - &:hover { - background-color: darken($bcbox-primary, 20%) !important; - } - } - } - - .p-column-title { - font-weight: bold; - } - - .p-paginator { - justify-content: right; - } - - .action-buttons .p-button.p-button-lg { - padding: 0; - margin-left: 1rem; - } -} - -.p-treetable { - .p-treetable-thead > tr > th { - background-color: transparent !important; - } - - tbody { - tr { - &.p-highlight { - background: $bcbox-highlight-background !important; - } - - &:focus { - outline: none !important; - } - } - } - - .p-checkbox { - .p-checkbox-box.p-highlight { - background-color: $bcbox-primary; - border-color: $bcbox-primary !important; - - &:hover { - background-color: darken($bcbox-primary, 20%) !important; - } - } - } - - .p-column-title { - font-weight: bold; - } - - .p-paginator { - justify-content: right; - } - - .action-buttons .p-button.p-button-lg { - padding: 0; - margin-left: 1rem; - } -} - -// Primary color overrides for buttons and action items (checkboxes etc) -// Note this could be eventually replaced by a custom themeing (which has JUST been introduced in Primevue) -// once it is more settled implementation-wise -.p-button { - &:not(.p-button-secondary, .p-button-success, .p-button-info, .p-button-warning, .p-button-help, .p-button-danger) { - color: $bcbox-primary !important; - - &:not(.p-button-outlined, .p-button-text) { - background-color: $bcbox-primary; - border-color: $bcbox-primary; - color: $bcbox-outline-on-primary !important; - } - } -} - -.p-checkbox, -.p-radiobutton { - &.p-checkbox-checked, - &.p-radiobutton-checked { - .p-checkbox-box, - .p-radiobutton-box { - background-color: $bcbox-primary; - border-color: $bcbox-primary !important; - - &:hover { - background-color: darken($bcbox-primary, 20%) !important; - } - } - } -} - -.p-inputswitch.p-inputswitch-checked { - .p-inputswitch-slider { - background-color: $bcbox-primary; - } - - &:not(.p-disabled) { - &:hover { - .p-inputswitch-slider { - background-color: darken($bcbox-primary, 10%) !important; - } - } - } -} - -.p-tag { - background-color: $bcbox-primary; - font-size: 1rem; - padding: 0.25rem 0.75rem; - font-weight: normal; -} - -h1, -h2, -h3, -h4, -h5 { - font-weight: 600; - line-height: 1.2em; -} diff --git a/frontend/src/assets/variables.scss b/frontend/src/assets/variables.scss index de191499..a7c46cdb 100644 --- a/frontend/src/assets/variables.scss +++ b/frontend/src/assets/variables.scss @@ -1,9 +1,17 @@ -// General font/etc colors +/* --------- variable overrides for primevue--------- */ +// ref: https://primevue.org/colors/ +:root { + --text-color: #495057; + --primary-color: #036; +} + +/* -------- custom css variables --------- */ +// buttons, links $bcbox-primary: #036; $bcbox-link-text: #1a5a96; $bcbox-link-text-hover: #00f; $bcbox-outline-on-primary: #fff; -// Panel/row/etc backgrounds +// highlighted sections, table rows $bcbox-highlight-background: #d9e1e8; $bcbox-table-stripe-background: #f2f2f2; diff --git a/frontend/src/components/bucket/BucketList.vue b/frontend/src/components/bucket/BucketList.vue index 711c2039..df21cb33 100644 --- a/frontend/src/components/bucket/BucketList.vue +++ b/frontend/src/components/bucket/BucketList.vue @@ -46,29 +46,30 @@ onMounted(async () => { </script> <template> - <div> - <div> - <h1>Select a bucket</h1> - <h2>Buckets are containers for storing objects.</h2> - <Message - v-if="getConfig?.notificationBanner" - severity="warn" - > - {{ getConfig?.notificationBanner }} - </Message> + <Message + v-if="getConfig?.notificationBanner" + severity="warn" + > + {{ getConfig?.notificationBanner }} + </Message> + + <div class="flex flex-wrap"> + <div class="flex-grow-1"> + <h1 class="">Select a bucket</h1> + <h4 class="mb-4">Buckets are containers for storing objects.</h4> </div> - <div class="flex justify-content-end"> + + <div class="flex-none align-items-right"> <Button v-if="usePermissionStore().isUserElevatedRights()" - label="Primary" - class="p-button-outlined mt-4" + label="Connect bucket to BCBox" + class="p-button-outlined my-4" data-test="connect-bucket" aria-label="Configure bucket" + icon="pi pi-plus" @click="showBucketConfig()" - > - <font-awesome-icon icon="fa-solid fa-plus" /> - Connect bucket to BCBox - </Button> + /> + <!-- Bucket config dialog --> <Dialog class="bcbox-info-dialog" @@ -113,29 +114,22 @@ onMounted(async () => { /> </Dialog> </div> - <div class="flex"> - <div class="flex-grow-1"> - <BucketTable - @show-sidebar-info="showSidebarInfo" - @show-bucket-config="showBucketConfig" - /> - </div> - <div - v-if="sidebarInfo" - class="flex-shrink-0 ml-3" - style="max-width: 33%; min-width: 33%" - > - <BucketSidebar - :sidebar-info="sidebarInfo" - @close-sidebar-info="closeSidebarInfo" - /> - </div> + </div> + <div class="flex"> + <div class="flex-grow-1"> + <BucketTable + @show-sidebar-info="showSidebarInfo" + @show-bucket-config="showBucketConfig" + /> + </div> + <div + v-if="sidebarInfo" + class="flex-shrink-0 w-4 pl-4 max-w-28rem" + > + <BucketSidebar + :sidebar-info="sidebarInfo" + @close-sidebar-info="closeSidebarInfo" + /> </div> </div> </template> - -<style lang="scss" scoped> -button { - text-indent: 10px; -} -</style> diff --git a/frontend/src/components/bucket/BucketSidebar.vue b/frontend/src/components/bucket/BucketSidebar.vue index 513b34fd..1b3011b5 100644 --- a/frontend/src/components/bucket/BucketSidebar.vue +++ b/frontend/src/components/bucket/BucketSidebar.vue @@ -65,32 +65,25 @@ watch(props, () => { </script> <template> - <div class="flex justify-content-start"> - <div class="flex col align-items-center pl-0"> - <font-awesome-icon - icon="fa-solid fa-circle-info" - style="font-size: 2rem" - /> - <h1>Bucket details</h1> - </div> - <div class="col-fixed align-items-center"> + <div class="side-panel pl-4"> + <div class="flex panel-header align-items-start"> + <font-awesome-icon icon="fa-solid fa-circle-info" /> + <h1 class="mt-0 ml-3 flex-grow-1">Bucket details</h1> <Button - class="p-button-lg p-button-rounded p-button-text black" + class="p-button-text pt-0" @click="closeSidebarInfo" > - <font-awesome-icon icon="fa-solid fa-xmark" /> + <font-awesome-icon icon="fa-xmark" /> </Button> </div> - </div> - <div class="pl-2 sidebar"> <div class="grid details-grid grid-nogutter"> <div class="col-12"> <h2>Properties</h2> </div> <div class="grid overflow-hidden"> <div class="col-fixed">Bucket Name:</div> - <div class="col wrap-block w-6"> + <div class="col wrap-block"> {{ props.sidebarInfo?.bucketName }} </div> </div> @@ -114,17 +107,3 @@ watch(props, () => { </div> </div> </template> - -<style lang="scss" scoped> -h1 { - padding-left: 1rem; -} - -h2 { - font-weight: bold; -} - -.black { - color: black; -} -</style> diff --git a/frontend/src/components/bucket/BucketTable.vue b/frontend/src/components/bucket/BucketTable.vue index 42be96f2..e42d110e 100644 --- a/frontend/src/components/bucket/BucketTable.vue +++ b/frontend/src/components/bucket/BucketTable.vue @@ -242,138 +242,136 @@ watch(getBuckets, () => { </script> <template> - <div> - <TreeTable - :loading="getIsLoading" - :value="treeData" - :expanded-keys="expandedKeys" - data-key="bucketId" - class="p-treetable-sm" - responsive-layout="scroll" - :paginator="true" - :rows="10" - paginator-template="RowsPerPageDropdown CurrentPageReport PrevPageLink NextPageLink " - current-page-report-template="{first}-{last} of {totalRecords}" - :rows-per-page-options="[10, 20, 50]" - sort-field="bucketName" - :sort-order="1" + <TreeTable + :loading="getIsLoading" + :value="treeData" + :expanded-keys="expandedKeys" + data-key="bucketId" + class="p-treetable-sm" + responsive-layout="scroll" + :paginator="true" + :rows="10" + paginator-template="RowsPerPageDropdown CurrentPageReport PrevPageLink NextPageLink " + current-page-report-template="{first}-{last} of {totalRecords}" + :rows-per-page-options="[10, 20, 50]" + sort-field="bucketName" + :sort-order="1" + > + <template #empty> + <div + v-if="!getIsLoading" + class="flex justify-content-center" + > + <h3>There are no buckets associated with your account.</h3> + </div> + </template> + <template #loadingicon> + <Spinner /> + </template> + <Column + field="bucketName" + header="Bucket Name" + header-style="padding-left: 50px" + body-class="truncate" + expander > - <template #empty> - <div - v-if="!getIsLoading" - class="flex justify-content-center" + <template #body="{ node }"> + <span class="row-head mr-2"> + <font-awesome-icon + v-if="!node.data.dummy" + icon="fa-solid fa-box-open" + /> + <font-awesome-icon + v-else + icon="fa-solid fa-folder" + /> + </span> + <span + v-if="node.data.bucketName.length > 150" + v-tooltip.bottom="{ value: node.data.bucketName }" > - <h3>There are no buckets associated with your account.</h3> - </div> - </template> - <template #loadingicon> - <Spinner /> + <BucketTableBucketName :node="node" /> + </span> + <span v-else> + <BucketTableBucketName :node="node" /> + </span> </template> - <Column - field="bucketName" - header="Bucket Name" - header-style="padding-left: 50px" - body-class="truncate" - expander - > - <template #body="{ node }"> - <span class="row-head mr-2"> - <font-awesome-icon - v-if="!node.data.dummy" - icon="fa-solid fa-box-open" - /> - <font-awesome-icon - v-else - icon="fa-solid fa-folder" - /> - </span> - <span - v-if="node.data.bucketName.length > 150" - v-tooltip.bottom="{ value: node.data.bucketName }" - > - <BucketTableBucketName :node="node" /> - </span> - <span v-else> - <BucketTableBucketName :node="node" /> - </span> - </template> - </Column> - <Column - header="Actions" - header-style="width: 250px" - header-class="header-right" - body-class="content-right action-buttons" - > - <template #body="{ node }"> - <span v-if="!node.data.dummy"> - <Button - v-if="permissionStore.isBucketActionAllowed(node.data.bucketId, getUserId, Permissions.UPDATE)" - v-tooltip.bottom="'Configure bucket'" - class="p-button-lg p-button-text" - aria-label="Configure bucket" - @click="showBucketConfig(node.data)" - > - <font-awesome-icon icon="fas fa-cog" /> - </Button> - <Button - v-if="permissionStore.isBucketActionAllowed(node.data.bucketId, getUserId, Permissions.MANAGE)" - v-tooltip.bottom="'Bucket permissions'" - class="p-button-lg p-button-text" - aria-label="Bucket permissions" - @click="showPermissions(node.data.bucketId, node.data.bucketName)" - > - <font-awesome-icon icon="fa-solid fa-users" /> - </Button> - <SyncButton - label-text="Synchronize bucket" - :bucket-id="node.data.bucketId" - /> - <Button - v-if="permissionStore.isBucketActionAllowed(node.data.bucketId, getUserId, Permissions.READ)" - v-tooltip.bottom="'Bucket details'" - class="p-button-lg p-button-rounded p-button-text" - aria-label="Bucket details" - @click="showSidebarInfo(node.data.bucketId)" - > - <font-awesome-icon icon="fa-solid fa-circle-info" /> - </Button> - <Button - v-if="permissionStore.isBucketActionAllowed(node.data.bucketId, getUserId, Permissions.DELETE)" - v-tooltip.bottom="'Delete bucket'" - class="p-button-lg p-button-text p-button-danger" - aria-label="Delete bucket" - @click="confirmDeleteBucket(node.data.bucketId)" - > - <font-awesome-icon icon="fa-solid fa-trash" /> - </Button> - </span> - </template> - </Column> - </TreeTable> - - <!-- eslint-disable vue/no-v-model-argument --> - <Dialog - v-model:visible="permissionsVisible" - :draggable="false" - :modal="true" - class="bcbox-info-dialog permissions-modal" + </Column> + <Column + header="Actions" + header-class="text-right" + body-class="action-buttons" + style="width: 250px" > - <!-- eslint-enable vue/no-v-model-argument --> - <template #header> - <font-awesome-icon - icon="fas fa-users" - fixed-width - /> - <span class="p-dialog-title">Bucket Permissions</span> + <template #body="{ node }"> + <span v-if="!node.data.dummy"> + <Button + v-if="permissionStore.isBucketActionAllowed(node.data.bucketId, getUserId, Permissions.UPDATE)" + v-tooltip.bottom="'Configure bucket'" + class="p-button-lg p-button-text" + aria-label="Configure bucket" + @click="showBucketConfig(node.data)" + > + <font-awesome-icon icon="fas fa-cog" /> + </Button> + <Button + v-if="permissionStore.isBucketActionAllowed(node.data.bucketId, getUserId, Permissions.MANAGE)" + v-tooltip.bottom="'Bucket permissions'" + class="p-button-lg p-button-text" + aria-label="Bucket permissions" + @click="showPermissions(node.data.bucketId, node.data.bucketName)" + > + <font-awesome-icon icon="fa-solid fa-users" /> + </Button> + <SyncButton + label-text="Synchronize bucket" + :bucket-id="node.data.bucketId" + /> + <Button + v-if="permissionStore.isBucketActionAllowed(node.data.bucketId, getUserId, Permissions.READ)" + v-tooltip.bottom="'Bucket details'" + class="p-button-lg p-button-rounded p-button-text" + aria-label="Bucket details" + @click="showSidebarInfo(node.data.bucketId)" + > + <font-awesome-icon icon="fa-solid fa-circle-info" /> + </Button> + <Button + v-if="permissionStore.isBucketActionAllowed(node.data.bucketId, getUserId, Permissions.DELETE)" + v-tooltip.bottom="'Delete bucket'" + class="p-button-lg p-button-text p-button-danger" + aria-label="Delete bucket" + @click="confirmDeleteBucket(node.data.bucketId)" + > + <font-awesome-icon icon="fa-solid fa-trash" /> + </Button> + </span> </template> - - <h3 class="bcbox-info-dialog-subhead"> - {{ permissionBucketName }} - </h3> - - <BucketPermission :bucket-id="permissionsBucketId" /> - </Dialog> - </div> + </Column> + </TreeTable> + + <!-- eslint-disable vue/no-v-model-argument --> + <Dialog + v-model:visible="permissionsVisible" + :draggable="false" + :modal="true" + class="bcbox-info-dialog" + > + <!-- eslint-enable vue/no-v-model-argument --> + <template #header> + <font-awesome-icon + icon="fas fa-users" + fixed-width + /> + <span class="p-dialog-title">Bucket Permissions</span> + </template> + + <h3 class="bcbox-info-dialog-subhead"> + {{ permissionBucketName }} + </h3> + + <BucketPermission :bucket-id="permissionsBucketId" /> + </Dialog> </template> <style scoped lang="scss"> diff --git a/frontend/src/components/layout/AppLayout.vue b/frontend/src/components/layout/AppLayout.vue index 0b8f2e7c..d1af21ed 100644 --- a/frontend/src/components/layout/AppLayout.vue +++ b/frontend/src/components/layout/AppLayout.vue @@ -3,7 +3,7 @@ import { Header, Footer } from '@/components/layout'; </script> <template> - <div class="layout-app"> + <div class="w-full min-h-screen flex flex-column"> <!-- Header/Nav --> <div class="layout-head"> <Header /> @@ -11,37 +11,13 @@ import { Header, Footer } from '@/components/layout'; </div> <!-- Main views --> - <main class="layout-container"> + <main class="layout-main pt-3 flex-auto"> <slot name="main" /> </main> <!-- Footer --> - <footer class="layout-footer"> + <footer class="flex-shrink-0"> <Footer /> </footer> </div> </template> - -<style scoped lang="scss"> -.layout-app { - display: flex; - flex-direction: column; - align-items: flex-start; - min-height: 100vh; - width: 100%; - .layout-head { - flex: 0; - width: 100%; - } - .layout-container { - flex: 1; - padding-top: 20px; - padding-left: 100px; - padding-right: 100px; - width: 100%; - } - .layout-footer { - width: 100%; - } -} -</style> diff --git a/frontend/src/components/layout/Footer.vue b/frontend/src/components/layout/Footer.vue index a2c1972c..0f166636 100644 --- a/frontend/src/components/layout/Footer.vue +++ b/frontend/src/components/layout/Footer.vue @@ -1,7 +1,6 @@ <script setup lang="ts"> import { storeToRefs } from 'pinia'; -import { Button } from '@/lib/primevue'; import { useConfigStore } from '@/store'; // Store @@ -11,68 +10,54 @@ const { getConfig } = storeToRefs(useConfigStore()); <template> <div class="gov-footer flex justify-content-between"> <div> - <Button id="footer-home"> - <a - href="https://www.gov.bc.ca/" - target="_blank" - > - Home - </a> - </Button> - <Button id="footer-about"> - <a - href="https://www2.gov.bc.ca/gov/content/about-gov-bc-ca" - target="_blank" - > - About gov.bc.ca - </a> - </Button> - <Button id="footer-disclaimer"> - <a - href="http://gov.bc.ca/disclaimer" - target="_blank" - > - Disclaimer - </a> - </Button> - <Button id="footer-privacy"> - <a - href="http://gov.bc.ca/privacy" - target="_blank" - > - Privacy - </a> - </Button> - <Button id="footer-accessibility"> - <a - href="http://gov.bc.ca/webaccessibility" - target="_blank" - > - Accessibility - </a> - </Button> - <Button id="footer-copyright"> - <a - href="http://gov.bc.ca/copyright" - target="_blank" - > - Copyright - </a> - </Button> - <Button id="footer-contact"> - <a - href="https://www2.gov.bc.ca/gov/content/home/contact-us" - target="_blank" - > - Contact Us - </a> - </Button> + <a + href="https://www.gov.bc.ca/" + target="_blank" + > + Home + </a> + <a + href="https://www2.gov.bc.ca/gov/content/about-gov-bc-ca" + target="_blank" + > + About gov.bc.ca + </a> + <a + href="http://gov.bc.ca/disclaimer" + target="_blank" + > + Disclaimer + </a> + <a + href="http://gov.bc.ca/privacy" + target="_blank" + > + Privacy + </a> + <a + href="http://gov.bc.ca/webaccessibility" + target="_blank" + > + Accessibility + </a> + <a + href="http://gov.bc.ca/copyright" + target="_blank" + > + Copyright + </a> + <a + href="https://www2.gov.bc.ca/gov/content/home/contact-us" + target="_blank" + > + Contact Us + </a> </div> <div v-if="getConfig" - class="flex align-items-center justify-content-center text-white mr-3" + class="version px-3 py-2" > - v{{ getConfig.version }}-{{ getConfig.gitRev.substring(0, 8) }} + v{{ getConfig.version }}{{ getConfig.gitRev ? '-' + getConfig.gitRev.substring(0, 8) : '' }} </div> </div> </template> diff --git a/frontend/src/components/layout/Header.vue b/frontend/src/components/layout/Header.vue index 1c4a26c6..bdcd3d11 100644 --- a/frontend/src/components/layout/Header.vue +++ b/frontend/src/components/layout/Header.vue @@ -5,9 +5,12 @@ import { LoginButton } from '@/components/layout'; <template> <header> <nav id="header-branding"> - <div class="grid align-items-center justify-content-center"> - <div class="col-fixed"> - <a href="https://www2.gov.bc.ca"> + <div class="flex flex-row flex-wrap align-items-center py-3 lg:px-7"> + <div class="flex flex-none"> + <a + href="https://www2.gov.bc.ca" + class="pl-1" + > <img src="@/assets/images/bc_logo.svg" width="181" @@ -16,15 +19,10 @@ import { LoginButton } from '@/components/layout'; /> </a> </div> - <div class="col"> - <div - id="title-branding" - class="justify-content-left" - > - <span>BCBox</span> - </div> + <div class="flex flex-grow-1 ml-2"> + <h2 class="m-0">BCBox</h2> </div> - <div class="col-fixed"> + <div class="flex flex-none mx-3"> <LoginButton /> </div> </div> @@ -35,24 +33,14 @@ import { LoginButton } from '@/components/layout'; <style lang="scss" scoped> #header-branding { background-color: #003366; - font-size: 13px; color: white; - padding: 0.5rem 3rem 0rem 3rem; white-space: nowrap; box-shadow: 0 6px 8px -4px #b3b1b3; -webkit-box-shadow: 0 6px 8px -4px #b3b1b3; -moz-box-shadow: 0 6px 8px -4px #b3b1b3; + @media not print { border-bottom: 2px solid #fcba19; } } - -#title-branding { - padding-left: 10px; - font-size: 20px; - > span { - font-weight: 600; - font-size: 1.5em; - } -} </style> diff --git a/frontend/src/components/layout/Navbar.vue b/frontend/src/components/layout/Navbar.vue index 4bb4289e..58f19c55 100644 --- a/frontend/src/components/layout/Navbar.vue +++ b/frontend/src/components/layout/Navbar.vue @@ -10,7 +10,7 @@ const { getIsAuthenticated } = storeToRefs(useAuthStore()); </script> <template> - <nav class="navigation-main"> + <nav class="navigation-main lg:px-7"> <Toolbar> <template #start> <ol class="list-none m-0 p-0 flex flex-row align-items-center font-semibold"> @@ -58,7 +58,6 @@ const { getIsAuthenticated } = storeToRefs(useAuthStore()); background-color: #38598a; color: #fcba19; display: flex; - padding: 0rem 3rem 0rem 3rem; width: 100%; box-shadow: 0 6px 8px -4px #b3b1b3; -webkit-box-shadow: 0 6px 8px -4px #b3b1b3; diff --git a/frontend/src/components/layout/ProgressLoader.vue b/frontend/src/components/layout/ProgressLoader.vue index 6fb748a7..179b0b36 100644 --- a/frontend/src/components/layout/ProgressLoader.vue +++ b/frontend/src/components/layout/ProgressLoader.vue @@ -22,6 +22,7 @@ const { getLoadingMode, getLoadingValue } = storeToRefs(appStore); <style lang="scss" scoped> .app-loader { position: fixed; + top: 0; width: 100%; z-index: 999; diff --git a/frontend/src/components/object/DownloadObjectButton.vue b/frontend/src/components/object/DownloadObjectButton.vue index 98e6cca0..1c0d6e89 100644 --- a/frontend/src/components/object/DownloadObjectButton.vue +++ b/frontend/src/components/object/DownloadObjectButton.vue @@ -65,6 +65,7 @@ const download = () => { </Button> <Button v-else + v-tooltip.bottom="'Download object'" class="mr-2" outlined :disabled="props.disabled" diff --git a/frontend/src/components/object/ObjectFileDetails.vue b/frontend/src/components/object/ObjectFileDetails.vue index 8787e50b..ececa986 100644 --- a/frontend/src/components/object/ObjectFileDetails.vue +++ b/frontend/src/components/object/ObjectFileDetails.vue @@ -138,17 +138,17 @@ watch([props, getObjects], async () => { <template> <div v-if="obj"> - <div class="grid pol-0"> + <div class="grid grid-nogutter"> <div class="col-12"> - <h1 class="pl-1 heading">File details</h1> + <h1 class="heading">File details</h1> </div> <div class="flex col justify-content-start"> <div class="flex col align-items-center heading"> <font-awesome-icon icon="fa-solid fa-circle-info" - style="font-size: 2rem" + class="text-3xl pr-3" /> - <h2 class="pl-1"> + <h2 class=""> {{ obj.name }} </h2> </div> @@ -200,7 +200,7 @@ watch([props, getObjects], async () => { /> </div> <Divider layout="vertical" /> - <div class="flex flex-column w-6 gap-3 py-5"> + <div class="flex flex-column w-6 gap-4 xl:pl-3 py-5"> <div class="flex flex-row-reverse"> <ObjectUploadBasic v-if="permissionStore.isObjectActionAllowed(props.objectId, getUserId, Permissions.UPDATE, bucketId)" @@ -229,7 +229,7 @@ watch([props, getObjects], async () => { v-model:visible="permissionsVisible" :draggable="false" :modal="true" - class="bcbox-info-dialog permissions-modal" + class="bcbox-info-dialog" > <!-- eslint-enable vue/no-v-model-argument --> <template #header> diff --git a/frontend/src/components/object/ObjectList.vue b/frontend/src/components/object/ObjectList.vue index dcddd191..f845dce3 100644 --- a/frontend/src/components/object/ObjectList.vue +++ b/frontend/src/components/object/ObjectList.vue @@ -91,6 +91,7 @@ onMounted(async () => { <div> <Button v-if="permissionStore.isBucketActionAllowed(props.bucketId as string, getUserId, Permissions.CREATE)" + v-tooltip.bottom="'Upload object'" class="mr-2" :disabled="displayUpload" aria-label="Show object" @@ -127,8 +128,7 @@ onMounted(async () => { </div> <div v-if="objectInfoId" - class="flex-shrink-0 ml-3" - style="max-width: 33%; min-width: 33%" + class="flex-shrink-1 w-4" > <ObjectSidebar :object-id="objectInfoId" diff --git a/frontend/src/components/object/ObjectMetadata.vue b/frontend/src/components/object/ObjectMetadata.vue index 1d28d8a5..3ff773b6 100644 --- a/frontend/src/components/object/ObjectMetadata.vue +++ b/frontend/src/components/object/ObjectMetadata.vue @@ -128,7 +128,7 @@ watch([props, tsGetMetadata, vsGetMetadata], () => { v-model:visible="editing" :draggable="false" :modal="true" - class="bcbox-info-dialog permissions-modal" + class="bcbox-info-dialog" > <!-- eslint-enable vue/no-v-model-argument --> <template #header> diff --git a/frontend/src/components/object/ObjectMetadataTagForm.vue b/frontend/src/components/object/ObjectMetadataTagForm.vue index b1d55b22..c4bf53fd 100644 --- a/frontend/src/components/object/ObjectMetadataTagForm.vue +++ b/frontend/src/components/object/ObjectMetadataTagForm.vue @@ -190,13 +190,13 @@ onBeforeMount(() => { </span> <Button - class="mt-5" + class="mt-5 mr-2" label="Save" type="submit" icon="pi pi-check" /> <Button - class="p-button-text mt-2" + class="p-button-outlined mt-2" label="Cancel" icon="pi pi-times" @click="onCancel" diff --git a/frontend/src/components/object/ObjectSidebar.vue b/frontend/src/components/object/ObjectSidebar.vue index 3ede4bcf..d8105b06 100644 --- a/frontend/src/components/object/ObjectSidebar.vue +++ b/frontend/src/components/object/ObjectSidebar.vue @@ -46,25 +46,18 @@ watch( </script> <template> - <div class="flex justify-content-start"> - <div class="flex col align-items-center heading"> - <font-awesome-icon - icon="fa-solid fa-circle-info" - style="font-size: 2rem" - /> - <h1>File details</h1> - </div> - <div> + <div class="side-panel pl-4 pt-2"> + <div class="flex panel-header align-items-start"> + <font-awesome-icon icon="fa-solid fa-circle-info" /> + <h1 class="mt-0 flex-grow-1">File details</h1> <Button - class="black" - icon="pi pi-times" - text - rounded + class="p-button-rounded p-button-text pt-0 mt-0" @click="closeObjectInfo" - /> + > + <font-awesome-icon icon="fa-xmark" /> + </Button> </div> - </div> - <div class="pl-2 sidebar"> + <ObjectProperties :object-id="props.objectId" :full-view="false" diff --git a/frontend/src/components/object/ObjectTable.vue b/frontend/src/components/object/ObjectTable.vue index 4ea3dec7..cab09394 100644 --- a/frontend/src/components/object/ObjectTable.vue +++ b/frontend/src/components/object/ObjectTable.vue @@ -101,7 +101,7 @@ const filters = ref({ </script> <template> - <div> + <div class="object-table"> <DataTable v-model:selection="objectStore.selectedObjects" v-model:filters="filters" @@ -171,7 +171,7 @@ const filters = ref({ field="name" :sortable="true" header="Name" - header-style="width: 25%" + header-style="min-width: 25%" body-class="truncate" > <template #body="{ data }"> @@ -184,6 +184,7 @@ const filters = ref({ field="id" :sortable="true" header="Object ID" + style="width: 150px" > <template #body="{ data }"> <div v-tooltip.bottom="{ value: data.id }"> @@ -194,6 +195,7 @@ const filters = ref({ <Column field="lastUpdatedDate" header="Updated date" + style="width: 300px" :sortable="true" :hidden="props.objectInfoId ? true : false" > @@ -204,6 +206,7 @@ const filters = ref({ <Column field="publicSharing" header="Public" + style="width: 100px" > <template #body="{ data }"> <ObjectPublicToggle @@ -217,9 +220,9 @@ const filters = ref({ </Column> <Column header="Actions" - header-style="width: 250px" + header-style="min-width: 270px" header-class="header-right" - body-class="content-right action-buttons" + body-class="action-buttons" > <template #body="{ data }"> <ShareObjectButton :id="data.id" /> @@ -275,7 +278,7 @@ const filters = ref({ v-model:visible="permissionsVisible" :draggable="false" :modal="true" - class="bcbox-info-dialog permissions-modal" + class="bcbox-info-dialog" > <!-- eslint-enable vue/no-v-model-argument --> <template #header> diff --git a/frontend/src/components/object/ObjectTag.vue b/frontend/src/components/object/ObjectTag.vue index 7ec024d4..c9843a0e 100644 --- a/frontend/src/components/object/ObjectTag.vue +++ b/frontend/src/components/object/ObjectTag.vue @@ -129,7 +129,7 @@ watch([props, tsGetTagging, vsGetTagging], () => { v-model:visible="editing" :draggable="false" :modal="true" - class="bcbox-info-dialog permissions-modal" + class="bcbox-info-dialog" > <!-- eslint-enable vue/no-v-model-argument --> <template #header> diff --git a/frontend/src/components/object/ObjectUploadBasic.vue b/frontend/src/components/object/ObjectUploadBasic.vue index dd87dfa0..feb8d91a 100644 --- a/frontend/src/components/object/ObjectUploadBasic.vue +++ b/frontend/src/components/object/ObjectUploadBasic.vue @@ -42,10 +42,9 @@ const confirm = useConfirm(); const toast = useToast(); const confirmUpdate = () => { - let confirmMessage = 'Please confirm that you want to upload a new version.'; + let confirmMessage = 'Please confirm that you want to upload a new version.'; if (versionStore.findS3VersionByObjectId(props.objectId) === null) { - confirmMessage = 'This is a non-versioned bucket. ' + - 'Uploading a new version will overwrite the current version.'; + confirmMessage = 'This is a non-versioned bucket. ' + 'Uploading a new version will overwrite the current version.'; } confirm.require({ message: confirmMessage, @@ -139,7 +138,7 @@ const closeModal = () => { v-model:visible="editing" :draggable="false" :modal="true" - class="bcbox-info-dialog permissions-modal" + class="bcbox-info-dialog" > <!-- eslint-enable vue/no-v-model-argument --> <template #header> diff --git a/frontend/src/components/object/ObjectUploadFile.vue b/frontend/src/components/object/ObjectUploadFile.vue index bc4ea57a..d7a6d7b8 100644 --- a/frontend/src/components/object/ObjectUploadFile.vue +++ b/frontend/src/components/object/ObjectUploadFile.vue @@ -108,7 +108,7 @@ const closeModal = () => { v-model:visible="editing" :draggable="false" :modal="true" - class="bcbox-info-dialog permissions-modal" + class="bcbox-info-dialog" > <!-- eslint-enable vue/no-v-model-argument --> <template #header> diff --git a/frontend/src/components/object/ObjectVersion.vue b/frontend/src/components/object/ObjectVersion.vue index 21fdd6d8..7ce2a9bc 100644 --- a/frontend/src/components/object/ObjectVersion.vue +++ b/frontend/src/components/object/ObjectVersion.vue @@ -91,7 +91,7 @@ watch(getVersions, async () => { </script> <template> - <div class="grid details-grid grid-nogutter mb-2"> + <div class="grid grid-nogutter mb-2"> <div class="col-12"> <h2>Versions</h2> </div> @@ -120,8 +120,8 @@ watch(getVersions, async () => { <Column field="versionNumber" header="Version" - header-style="width: 3em" - body-class="content-center" + header-style="width: 5em" + body-style="text-align: center" > <template #body="{ data }"> {{ data.versionNumber }} @@ -130,7 +130,6 @@ watch(getVersions, async () => { <Column field="updatedAt" header="Creation date" - header-style="width: 33%" > <template #body="{ data }"> <div> @@ -143,7 +142,6 @@ watch(getVersions, async () => { <Column field="createdBy" header="Created by" - header-style="width: 33%" > <template #body="{ data }"> <div> @@ -153,10 +151,13 @@ watch(getVersions, async () => { </Column> <Column header="Actions" - header-style="width: 34%" header-class="header-right" - body-class="content-right action-buttons" + body-class="action-buttons" > + <!-- header-class="header-right flex justify-content-end" + body-class="content-right action-buttons justify-content-end" + header-style="width: 8em" +--> <template #body="{ data }"> <DownloadObjectButton v-if=" @@ -183,8 +184,12 @@ watch(getVersions, async () => { ) " :to="{ name: RouteNames.DETAIL_OBJECTS, query: { objectId: props.objectId, versionId: data.id } }" + class="action-link" > - <Button class="p-button-lg p-button-rounded p-button-text"> + <Button + v-tooltip.bottom="'Version details'" + class="p-button-lg p-button-rounded p-button-text" + > <font-awesome-icon icon="fa-solid fa-circle-info" /> </Button> </router-link> diff --git a/frontend/src/components/object/share/ShareLinkContent.vue b/frontend/src/components/object/share/ShareLinkContent.vue index 229ff2fe..9c5b4ace 100644 --- a/frontend/src/components/object/share/ShareLinkContent.vue +++ b/frontend/src/components/object/share/ShareLinkContent.vue @@ -30,7 +30,7 @@ const copyLinkToClipboard = () => { :value="props.shareLink" /> <Button - class="p-button-outlined p-button-secondary" + class="p-button-outlined p-button-primary" @click="copyLinkToClipboard" > <font-awesome-icon diff --git a/frontend/src/components/object/share/ShareObjectButton.vue b/frontend/src/components/object/share/ShareObjectButton.vue index 69412085..6beba50e 100644 --- a/frontend/src/components/object/share/ShareObjectButton.vue +++ b/frontend/src/components/object/share/ShareObjectButton.vue @@ -90,7 +90,7 @@ onMounted(() => { <Button v-tooltip.bottom="'Share object'" - class="p-button-lg p-button-text" + class="p-button-lg p-button-text primary" aria-label="Share object" @click="displayShareDialog = true" > diff --git a/frontend/src/views/HomeView.vue b/frontend/src/views/HomeView.vue index 8c6d9951..c02f1bde 100644 --- a/frontend/src/views/HomeView.vue +++ b/frontend/src/views/HomeView.vue @@ -12,19 +12,16 @@ const { getConfig } = storeToRefs(useConfigStore()); </script> <template> - <Message - v-if="getConfig?.notificationBanner" - severity="warn" - > - {{ getConfig?.notificationBanner }} - </Message> - - <div class="flex flex-column mr-8 ml-8"> - <div class="flex justify-content-center mb-5"> - <h1>Store and share files in BCBox</h1> - </div> - <div class="flex justify-content-center mb-5"> - <p class="text-xl text-center"> + <div class="grid"> + <div class="text-center"> + <Message + v-if="getConfig?.notificationBanner" + severity="warn" + > + {{ getConfig?.notificationBanner }} + </Message> + <h1 class="mb-4">Store and share files in BCBox</h1> + <p class="text-xl"> This website uses the <a href="https://bcgov.github.io/common-service-showcase/services/coms.html"> Common Object Management Service @@ -50,49 +47,36 @@ const { getConfig } = storeToRefs(useConfigStore()); If you already have a bucket from outside of BCBox, you can't yet work on existing files from that bucket in BCBox, but we are currently working to make this possible through synchronization. </p> - </div> - <div class="flex justify-content-center mb-5"> - <router-link - :to="{ name: RouteNames.LIST_BUCKETS }" - class="no-underline" - > - <Button> - {{ getIsAuthenticated ? 'Go to My Buckets' : 'Log in to get started' }} - </Button> - </router-link> - </div> - <div class="flex justify-content-center mb-8"> - <img - src="@/assets/images/home_1.png" - class="border-1 drop-shadow" - width="60%" - alt="Screenshot of BCBox's file list interface: + + <div class="flex flex-column justify-content-center align-items-center mb-4"> + <router-link :to="{ name: RouteNames.LIST_BUCKETS }"> + <Button> + {{ getIsAuthenticated ? 'Go to My Buckets' : 'Log in to get started' }} + </Button> + </router-link> + + <img + src="@/assets/images/home_1.png" + class="border-1 drop-shadow w-8 sm:col-10 mt-5 mb-8 flex align-items-center" + alt="Screenshot of BCBox's file list interface: a list of example files and possible actions including Upload, Download and Delete." - /> - </div> - <div class="flex justify-content-center mb-5"> - <h2>Ongoing feature enhancements</h2> - </div> - <div class="flex justify-content-center mb-8 text-xl"> - <ul> - <li> + /> + <h2 class="mb-4">Ongoing feature enhancements</h2> + + <p class="text-xl"> BCBox is constantly improving! See BCBox's <a href="https://github.com/bcgov/bcbox/wiki">Help</a> for more information, a link to our Product Roadmap, and documentation of features as they are implemented. - </li> - </ul> - </div> - <div class="grid mb-8"> - <div class="col-6 pr-5"> - <div class="flex align-items-left mb-2"> - <h2>Upload and download objects</h2> - </div> - <div class="flex align-items-left"> + </p> + </div> + + <div class="grid mb-8 text-left"> + <div class="col-6 pr-5"> + <h3 class="mb-3">Upload and download objects</h3> <p class="text-xl">With BCBox, you can use low-cost object storage for your files, images and documents.</p> </div> - </div> - <div class="col-6 pl-5"> - <div class="flex align-items-center"> + + <div class="col-6"> <img src="@/assets/images/home_2.png" class="border-1 drop-shadow" @@ -101,13 +85,10 @@ const { getConfig } = storeToRefs(useConfigStore()); /> </div> </div> - </div> - <div class="grid mb-8"> - <div class="col-6 pr-5"> - <div class="flex align-items-left mb-2"> - <h2>Manage access and share</h2> - </div> - <div class="flex align-items-left"> + + <div class="grid mb-4 text-left"> + <div class="col-6 pr-5"> + <h3 class="mb-3">Manage access and share</h3> <p class="text-xl"> You can assign custom permissions to other users through IDIR or BCeID authentication. <br /> @@ -117,24 +98,20 @@ const { getConfig } = storeToRefs(useConfigStore()); information without the consent of your Ministry Privacy Officer. </p> </div> - </div> - <div class="col-6 pl-5"> - <div class="flex"> + <div class="col-6"> <img src="@/assets/images/home_3.png" class="border-1 drop-shadow" alt="Screenshot of BCBox's share interface, - demonstrating a share link and QR code." + demonstrating a share link and QR code." /> </div> </div> - </div> - <div class="flex justify-content-center mb-5"> - <h2>Versioning, metadata, tagging, syncing with existing buckets and more</h2> - </div> - <div class="flex justify-content-center mb-8 text-xl"> - <ul> - <li> + + <div class="flex flex-column justify-content-center align-items-center"> + <h3 class="mb-4">Versioning, metadata, tagging, syncing with existing buckets and more</h3> + + <p class="text-xl"> Contact <a href="https://apps.nrs.gov.bc.ca/int/jira/servicedesk/customer/portal/1/create/701" @@ -143,82 +120,77 @@ const { getConfig } = storeToRefs(useConfigStore()); NRIDS Optimization </a> or your ministry's service desk. You will need a bucket to get started. - </li> - </ul> - </div> - <div class="flex justify-content-center mb-8"> - <router-link - :to="{ name: RouteNames.LIST_BUCKETS }" - class="no-underline" - > - <Button> - {{ getIsAuthenticated ? 'Go to My Buckets' : 'Log in to get started' }} - </Button> - </router-link> - </div> - <div class="flex justify-content-center mb-5"> - <h2>Terms of Use</h2> - </div> - <div class="flex justify-content-left mb-5 text-xl"> - <ul> - <li> - It is your responsibility to comply with the - <a - href="https://www.bclaws.gov.bc.ca/civix/document/id/complete/statreg/96165_03#part3" - target="_blank" - > - Freedom of Information and Protection of Privacy Act - </a> - governing the collection, use and disclosure of personally identifiable information - </li> - <li> - Access to this tool does not inherently grant permission to collect, use or disclose any personally - identifiable information - </li> - <li> - It is your responsibility to provide a Collection Notice to individuals before collecting personally - identifiable information, as required by law - </li> - <li> - Before uploading and distributing files you are required to discuss your privacy intentions with your - <a - href="https://www2.gov.bc.ca/gov/content/governments/services-for-government/information-management-technology/privacy/resources/privacy-officers" - target="_blank" - > - Ministry Privacy Officer - </a> - and to complete assessments as required - </li> - <li> - If you intend to advise users to access with BCeID, please send an email to the - <a href="mailto:IDIM.Consulting@gov.bc.ca">Provincial Identity Information Management Program</a> - indicating your BCeID-related intentions - </li> - <li> - All other inquiries around getting or using buckets should be directed to - <a - href="https://apps.nrs.gov.bc.ca/int/jira/servicedesk/customer/portal/1/create/701" - target="_blank" - > - NRIDS Optimization - </a> - (Natural Resource ministries) or your ministry's service desk - </li> - <li> - Storage and custodianship of metadata and tags (not the objects themselves in your bucket) is maintained by - Natural Resource Information & Digital Services - </li> - <li> - You will refer to and adhere to - <a - href="https://www2.gov.bc.ca/gov/content/data/about-data-management/databc" - target="_blank" - > - DataBC - </a> - requirements for public file sharing - </li> - </ul> + </p> + + <router-link :to="{ name: RouteNames.LIST_BUCKETS }"> + <Button> + {{ getIsAuthenticated ? 'Go to My Buckets' : 'Log in to get started' }} + </Button> + </router-link> + + <h2 class="mt-8 mb-4">Terms of Use</h2> + <div class="text-left text-xl"> + <ul> + <li> + It is your responsibility to comply with the + <a + href="https://www.bclaws.gov.bc.ca/civix/document/id/complete/statreg/96165_03#part3" + target="_blank" + > + Freedom of Information and Protection of Privacy Act + </a> + governing the collection, use and disclosure of personally identifiable information + </li> + <li> + Access to this tool does not inherently grant permission to collect, use or disclose any personally + identifiable information + </li> + <li> + It is your responsibility to provide a Collection Notice to individuals before collecting personally + identifiable information, as required by law + </li> + <li> + Before uploading and distributing files you are required to discuss your privacy intentions with your + <a + href="https://www2.gov.bc.ca/gov/content/governments/services-for-government/information-management-technology/privacy/resources/privacy-officers" + target="_blank" + > + Ministry Privacy Officer + </a> + and to complete assessments as required + </li> + <li> + If you intend to advise users to access with BCeID, please send an email to the + <a href="mailto:IDIM.Consulting@gov.bc.ca">Provincial Identity Information Management Program</a> + indicating your BCeID-related intentions + </li> + <li> + All other inquiries around getting or using buckets should be directed to + <a + href="https://apps.nrs.gov.bc.ca/int/jira/servicedesk/customer/portal/1/create/701" + target="_blank" + > + NRIDS Optimization + </a> + (Natural Resource ministries) or your ministry's service desk + </li> + <li> + Storage and custodianship of metadata and tags (not the objects themselves in your bucket) is maintained + by Natural Resource Information & Digital Services + </li> + <li> + You will refer to and adhere to + <a + href="https://www2.gov.bc.ca/gov/content/data/about-data-management/databc" + target="_blank" + > + DataBC + </a> + requirements for public file sharing + </li> + </ul> + </div> + </div> </div> </div> </template> @@ -227,4 +199,7 @@ const { getConfig } = storeToRefs(useConfigStore()); img { max-width: 100%; } +ul li { + margin-bottom: 1rem; +} </style> diff --git a/frontend/tests/unit/components/layout/Footer.spec.ts b/frontend/tests/unit/components/layout/Footer.spec.ts index 1a8548b5..140755e7 100644 --- a/frontend/tests/unit/components/layout/Footer.spec.ts +++ b/frontend/tests/unit/components/layout/Footer.spec.ts @@ -40,14 +40,14 @@ describe('Footer.vue', () => { expect(wrapper).toBeTruthy(); }); - it('contains 7 buttons', () => { + it('contains 7 links', () => { const wrapper = mount(Footer, { global: { plugins: [createTestingPinia(), PrimeVue] } }); - const btn = wrapper.findAll('button'); - expect(btn).toHaveLength(7); + const links = wrapper.findAll('a'); + expect(links).toHaveLength(7); }); });