From 0190b08eddfd8aebc9650a9d85d7cf1b87a87380 Mon Sep 17 00:00:00 2001 From: tblivet Date: Mon, 25 Nov 2024 14:14:33 +0100 Subject: [PATCH 1/6] feat: logs rework --- _dev/src/scss/_variables.scss | 4 + _dev/src/scss/components/_index.scss | 1 + _dev/src/scss/components/_logs.scss | 126 ++++++++++++------ _dev/src/scss/components/_progress.scss | 1 + _dev/src/scss/components/_scrollbar.scss | 21 +++ _dev/src/scss/layouts/_layout.scss | 4 + _dev/src/scss/layouts/_logs-pages.scss | 1 + _dev/src/ts/components/LogsViewer.ts | 42 +----- _dev/tests/components/LogsViewer.test.ts | 3 +- .../components/logs-templates.html.twig | 28 ++-- 10 files changed, 143 insertions(+), 88 deletions(-) create mode 100644 _dev/src/scss/components/_scrollbar.scss diff --git a/_dev/src/scss/_variables.scss b/_dev/src/scss/_variables.scss index f71678775..96216552b 100644 --- a/_dev/src/scss/_variables.scss +++ b/_dev/src/scss/_variables.scss @@ -16,6 +16,7 @@ $cdk-prefix: "cdk-"; --#{$ua-prefix}primary-600: var(--#{$cdk-prefix}primary-600, #5e5e5e); --#{$ua-prefix}primary-500: var(--#{$cdk-prefix}primary-500, #bbbbbb); --#{$ua-prefix}primary-400: var(--#{$cdk-prefix}primary-400, #dddddd); + --#{$ua-prefix}primary-300: var(--#{$cdk-prefix}primary-300, #eeeeee); --#{$ua-prefix}primary-200: var(--#{$cdk-prefix}primary-200, #f7f7f7); --#{$ua-prefix}purple-500: var(--#{$cdk-prefix}purple-500, #decde7); --#{$ua-prefix}purple-50: var(--#{$cdk-prefix}purple-50, #f8f0f7); @@ -57,6 +58,9 @@ $cdk-prefix: "cdk-"; --#{$ua-prefix}header-offset: 10rem; --#{$ua-prefix}bo-background-color: var(--#{$ua-prefix}primary-200); --#{$ua-prefix}error-img-filter: none; + --#{$ua-prefix}scrollbar-thumb: var(--#{$ua-prefix}primary-500); + --#{$ua-prefix}scrollbar-thumb-hover: var(--#{$ua-prefix}primary-600); + --#{$ua-prefix}scrollbar-track: var(--#{$ua-prefix}primary-400); } // Update variable at body level diff --git a/_dev/src/scss/components/_index.scss b/_dev/src/scss/components/_index.scss index 30abd82a8..59b8b1280 100644 --- a/_dev/src/scss/components/_index.scss +++ b/_dev/src/scss/components/_index.scss @@ -14,4 +14,5 @@ @use "privacy"; @use "progress"; @use "radio-card"; +@use "scrollbar"; @use "stepper"; diff --git a/_dev/src/scss/components/_logs.scss b/_dev/src/scss/components/_logs.scss index 585bbd620..f35205cbf 100644 --- a/_dev/src/scss/components/_logs.scss +++ b/_dev/src/scss/components/_logs.scss @@ -11,17 +11,6 @@ $e-logs: ".logs"; } #{$e-logs} { - --#{$ua-prefix}logs-height: 14rem; - --#{$ua-prefix}logs-background-color: var(--#{$ua-prefix}muted-background-color); - display: flex; - flex-direction: column; - gap: 1rem; - min-height: var(--#{$ua-prefix}logs-height); - max-height: 100%; - padding: 1rem; - background-color: var(--#{$ua-prefix}logs-background-color); - border-radius: var(--#{$ua-prefix}border-radius); - &__inner { display: flex; flex-direction: column; @@ -36,78 +25,92 @@ $e-logs: ".logs"; } &__scroll { + --#{$ua-prefix}logs-height: calc(10lh + (10 * 0.5rem)); + --#{$ua-prefix}logs-background-color: var(--#{$ua-prefix}muted-background-color); position: relative; display: flex; flex-direction: column; flex-grow: 1; min-height: var(--#{$ua-prefix}logs-height); + background-color: var(--#{$ua-prefix}logs-background-color); + border-radius: var(--#{$ua-prefix}border-radius); + overflow: hidden; - &::before { - content: ""; - position: absolute; - top: 0; - display: block; - width: 100%; - height: 1rem; - background-image: linear-gradient( - to top, - transparent, - var(--#{$ua-prefix}muted-background-color) - ); + #{$e-logs}__line { + font-size: 0.75rem; + line-height: 1.375rem; + + &::before { + font-size: 1.2rem; + } } } &__scroll-inner { height: 100%; - padding-block-start: 1rem; overflow-y: auto; } &__list { display: flex; flex-direction: column; - gap: 0.5rem; max-height: 100%; } &__line { - padding-inline-start: 2rem; - background-color: rgb(255 255 255 / 0); + position: relative; + padding-block: 0.125rem; + padding-inline: 3rem 1rem; background-repeat: no-repeat; background-position: left center; background-size: 1.5rem 1.5rem; font-size: 0.875rem; - line-height: 1.4; + line-height: 1.25rem; word-break: break-word; transition: background-color 0.3s ease-in-out; - &--success { - background-image: url("../../img/check.svg"); + &::before { + content: ""; + display: block; + font-family: var(--#{$ua-prefix}font-family-material-icons); + font-size: 1.25rem; + line-height: 1; + width: 1.375rem; + height: 1.25rem; + position: absolute; + left: 1rem; + top: 50%; + transform: translateY(-50%); + } - &#{$e-logs}__line--pointed { + &--success { + &::before { + content: "check"; color: var(--#{$ua-prefix}green-500); } } &--warning { - background-image: url("../../img/warning.svg"); - - &#{$e-logs}__line--pointed { + &::before { + content: "warning"; color: var(--#{$ua-prefix}yellow-500); } } &--error { - background-image: url("../../img/close.svg"); - - &#{$e-logs}__line--pointed { + &::before { + content: "close"; color: var(--#{$ua-prefix}red-500); } } + + &--pointed { + --#{$ua-prefix}log-active-background-color: var(--#{$ua-prefix}primary-300); + background-color: var(--#{$ua-prefix}log-active-background-color); + } } &__summary-anchor { - margin-inline-start: 0.25rem; font-weight: 700; } @@ -125,6 +128,51 @@ $e-logs: ".logs"; display: flex; flex-direction: column; gap: 0.5rem; + padding: 1.5rem; + border: 1px solid var(--#{$ua-prefix}border-color); + border-radius: var(--#{$ua-prefix}border-radius); + + #{$e-logs}__line { + display: grid; + grid-template-columns: minmax(auto, min-content) auto; + gap: 0.25rem; + justify-content: start; + padding-inline-start: 2rem; + padding-block: 0; + line-height: 1.25rem; + + &::before { + left: 0; + } + } + + #{$e-logs}__line-content { + white-space: nowrap; + overflow: hidden; + text-overflow: ellipsis; + } + } + + &__summary-scroll { + --#{$ua-prefix}logs-height: calc(5lh + (6 * 0.5rem)); + position: relative; + display: flex; + flex-direction: column; + gap: 0.5rem; + flex-grow: 1; + max-height: var(--#{$ua-prefix}logs-height); + border-radius: var(--#{$ua-prefix}border-radius); + overflow-y: auto; + } + + &__summary-top { + display: flex; + gap: 0.5rem; + align-items: center; + } + + &__summary-total { + flex-shrink: 0; } } -} +} \ No newline at end of file diff --git a/_dev/src/scss/components/_progress.scss b/_dev/src/scss/components/_progress.scss index 5006a15ca..91a118c80 100644 --- a/_dev/src/scss/components/_progress.scss +++ b/_dev/src/scss/components/_progress.scss @@ -12,6 +12,7 @@ $e: ".log-progress"; &__status { display: flex; gap: 0.5rem; + font-size: 0.875rem; align-items: center; color: var(--#{$ua-prefix}primary-600); } diff --git a/_dev/src/scss/components/_scrollbar.scss b/_dev/src/scss/components/_scrollbar.scss new file mode 100644 index 000000000..a749e69a0 --- /dev/null +++ b/_dev/src/scss/components/_scrollbar.scss @@ -0,0 +1,21 @@ +@use "../variables" as *; + +::-webkit-scrollbar { + width: 0.5rem; + height: 0.5rem; +} + +::-webkit-scrollbar-thumb { + background: var(--#{$ua-prefix}scrollbar-thumb); + border-radius: var(--#{$ua-prefix}border-radius); +} + +::-webkit-scrollbar-thumb:hover { + background: var(--#{$ua-prefix}scrollbar-thumb-hover); + border-radius: var(--#{$ua-prefix}border-radius); +} + +::-webkit-scrollbar-track { + background: var(--#{$ua-prefix}scrollbar-track); + border-radius: var(--#{$ua-prefix}border-radius); +} diff --git a/_dev/src/scss/layouts/_layout.scss b/_dev/src/scss/layouts/_layout.scss index d58f1729a..cef19f387 100644 --- a/_dev/src/scss/layouts/_layout.scss +++ b/_dev/src/scss/layouts/_layout.scss @@ -27,6 +27,10 @@ $e: "#ua"; text-align: center; } + &_modal { + height: 0; + } + @container ua-main (max-width: 700px) { &_container { padding: 2rem; diff --git a/_dev/src/scss/layouts/_logs-pages.scss b/_dev/src/scss/layouts/_logs-pages.scss index 9f64befe8..82dff15e4 100644 --- a/_dev/src/scss/layouts/_logs-pages.scss +++ b/_dev/src/scss/layouts/_logs-pages.scss @@ -39,6 +39,7 @@ html { #{$ua-id} { display: grid; grid-template-columns: minmax(0, 1fr); + grid-template-rows: 1fr; min-height: calc(100cqh - var(--#{$ua-prefix}header-offset)); #ua_container { diff --git a/_dev/src/ts/components/LogsViewer.ts b/_dev/src/ts/components/LogsViewer.ts index b00a214ab..13a140d5f 100644 --- a/_dev/src/ts/components/LogsViewer.ts +++ b/_dev/src/ts/components/LogsViewer.ts @@ -1,9 +1,8 @@ import ComponentAbstract from './ComponentAbstract'; import { SeverityClasses, LogEntry } from '../types/logsTypes'; import { parseLogWithSeverity } from '../utils/logsUtils'; -import { Destroyable } from '../types/DomLifecycle'; -export default class LogsViewer extends ComponentAbstract implements Destroyable { +export default class LogsViewer extends ComponentAbstract { #warnings: string[] = []; #errors: string[] = []; #isSummaryDisplayed: boolean = false; @@ -28,14 +27,6 @@ export default class LogsViewer extends ComponentAbstract implements Destroyable '#log-summary', 'Template summary not found' ); - #templateSummaryButtons = this.queryElement( - '#summary-buttons', - 'Template summary buttons not found' - ); - - public beforeDestroy = () => { - this.#logsSummary.removeEventListener('click', this.#handleLinkEvent); - }; /** * @public @@ -111,31 +102,6 @@ export default class LogsViewer extends ComponentAbstract implements Destroyable this.#isSummaryDisplayed = true; } - /** - * @private - * @param {string} downloadLogsLink - The link to download update logs. - * @returns {HTMLDivElement} - DIV element containing summary buttons. - * @description Creates DIV element containing summary buttons. - * Applies appropriate href and download attributes to download button. - */ - #createSummaryButtons = (downloadLogsLink: string): HTMLDivElement => { - const summaryButtonsFragment = this.#templateSummaryButtons.content.cloneNode( - true - ) as DocumentFragment; - const summaryButtons = summaryButtonsFragment.querySelector( - '[data-slot-template="summary-buttons"]' - ) as HTMLDivElement; - - const downloadLogsButton = summaryButtons.querySelector( - '[data-slot-template="download-button"]' - ) as HTMLAnchorElement; - - downloadLogsButton.href = downloadLogsLink; - downloadLogsButton.download = downloadLogsLink.split('/').pop()!; - - return summaryButtons; - }; - /** * @private * @param {LogEntry} logEntry - Parsed log entry containing message and severity information. @@ -146,10 +112,11 @@ export default class LogsViewer extends ComponentAbstract implements Destroyable #createLogLine = (logEntry: LogEntry): HTMLDivElement => { const logLineFragment = this.#templateLogLine.content.cloneNode(true) as DocumentFragment; const logLine = logLineFragment.querySelector('.logs__line') as HTMLDivElement; + const logLineContent = logLineFragment.querySelector('.logs__line-content') as HTMLDivElement; logLine.classList.add(`logs__line--${logEntry.className}`); logLine.setAttribute('data-status', logEntry.className); - logLine.textContent = logEntry.message; + logLineContent.textContent = logEntry.message; return logLine; }; @@ -183,6 +150,7 @@ export default class LogsViewer extends ComponentAbstract implements Destroyable #createSummary(severity: SeverityClasses, logs: string[]): HTMLDivElement { const summaryFragment = this.#templateSummary.content.cloneNode(true) as DocumentFragment; const summary = summaryFragment.querySelector('.logs__summary') as HTMLDivElement; + const summaryScroll = summaryFragment.querySelector('.logs__summary-scroll') as HTMLDivElement; const title = this.#getSummaryTitle(severity); const titleContainer = summary.querySelector('[data-slot-template="title"]') as HTMLDivElement; @@ -200,7 +168,7 @@ export default class LogsViewer extends ComponentAbstract implements Destroyable cloneLogElement.appendChild(linkClone); - summary.appendChild(cloneLogElement); + summaryScroll.appendChild(cloneLogElement); }); return summary; diff --git a/_dev/tests/components/LogsViewer.test.ts b/_dev/tests/components/LogsViewer.test.ts index 3cdfe1b5c..d71a43a9b 100644 --- a/_dev/tests/components/LogsViewer.test.ts +++ b/_dev/tests/components/LogsViewer.test.ts @@ -20,6 +20,7 @@ describe('LogsViewer', () => { @@ -36,7 +37,7 @@ describe('LogsViewer', () => {