diff --git a/app/app.vue b/app/app.vue index e519d2da..42e8e3ba 100644 --- a/app/app.vue +++ b/app/app.vue @@ -5,12 +5,24 @@ import Footer from "~/components/Footer.vue"; - + diff --git a/app/assets/css/elements.css b/app/assets/css/elements.css index d55db757..8082c4dd 100644 --- a/app/assets/css/elements.css +++ b/app/assets/css/elements.css @@ -1,12 +1,10 @@ +/* Restore heading/paragraph defaults that Tailwind preflight removes */ h1 { display: block; font-size: 2em; margin-block-start: 0.67em; margin-block-end: 0.67em; - margin-inline-start: 0; - margin-inline-end: 0; font-weight: bold; - unicode-bidi: isolate; } h2 { @@ -14,10 +12,7 @@ h2 { font-size: 1.5em; margin-block-start: 0.83em; margin-block-end: 0.83em; - margin-inline-start: 0; - margin-inline-end: 0; font-weight: bold; - unicode-bidi: isolate; } p { @@ -27,42 +22,31 @@ p { margin-block-end: 1em; } +/* PrimeVue component overrides */ .p-card .p-card-title { - font-size: 1.5rem; + font-size: 1.25rem; font-weight: 700; - margin-bottom: .5rem; + margin-bottom: 0.5rem; + letter-spacing: -0.01em; } .p-menubar { - margin-bottom: 1rem; + margin-bottom: 0; } -a { - color: -webkit-link; +/* Non-PrimeVue links */ +a:not(.p-button):not([class*="p-"]) { + color: var(--p-primary-color); cursor: pointer; text-decoration: underline; } -button { - appearance: auto; - text-rendering: auto; - color: buttontext; - letter-spacing: normal; - word-spacing: normal; - line-height: normal; - text-transform: none; - text-indent: 0; - text-shadow: none; +/* Global tooltip constraints prevent overflow on short tooltips */ +.p-tooltip { + max-width: none !important; +} + +.p-tooltip-text { + width: auto !important; display: inline-block; - text-align: center; - cursor: default; - box-sizing: border-box; - background-color: buttonface; - margin: 0; - padding-block: 1px; - padding-inline: 6px; - border-width: 2px; - border-style: outset; - border-color: buttonborder; - border-image: initial; } diff --git a/app/assets/css/main.css b/app/assets/css/main.css index a461c505..4ded65d4 100644 --- a/app/assets/css/main.css +++ b/app/assets/css/main.css @@ -1 +1,17 @@ -@import "tailwindcss"; \ No newline at end of file +@import "tailwindcss"; + +html { + font-family: ui-sans-serif, system-ui, -apple-system, BlinkMacSystemFont, + "Segoe UI", Roboto, "Helvetica Neue", Arial, "Noto Sans", sans-serif; + -webkit-font-smoothing: antialiased; + -moz-osx-font-smoothing: grayscale; +} + +:root { + --page-padding-x: 0.75rem; + --page-padding-y: 1.5rem; + + /* PrimeVue runtime tokens — overridden by PrimeVue at hydration; declared here for IDE resolution */ + --p-primary-color: #ea580c; + --p-text-muted-color: #64748b; +} diff --git a/app/assets/css/preferences.css b/app/assets/css/preferences.css index db14e217..5e1eb249 100644 --- a/app/assets/css/preferences.css +++ b/app/assets/css/preferences.css @@ -1,16 +1,18 @@ .settings-field { display: flex; justify-content: space-between; + align-items: flex-start; + gap: 1rem; } .settings-description-title { - font-weight: bold; - padding-bottom: 1em; + font-weight: 600; + margin-bottom: 0.75rem; } .setting-description-text { - font-size: 0.85em; - color: gray; + font-size: 0.875rem; + color: var(--p-text-muted-color); } .settings-control { @@ -22,15 +24,15 @@ .preferences-update-btn { display: flex; justify-content: flex-end; - margin-top: 1em; + margin-top: 1rem; } .preferences-dialog-header .p-dialog-header { - padding-bottom: 0 + padding-bottom: 0; } .autostart-interval-input { min-width: unset; - height: 2.5em; - width: 8em; + height: 2.5rem; + width: 8rem; } diff --git a/app/assets/css/table.css b/app/assets/css/table.css index d736ee8d..f331b7dd 100644 --- a/app/assets/css/table.css +++ b/app/assets/css/table.css @@ -1,15 +1,16 @@ .table-header-row { display: flex; justify-content: space-between; + align-items: center; width: 100%; - margin-bottom: 1em; - margin-top: 2em; + margin-bottom: 1rem; + gap: 1rem; } .search-bar { display: flex; width: 50%; - justify-content: left; + gap: 0.5rem; } .refresh-switch { @@ -23,6 +24,6 @@ } .rounded-table { - border-radius: 12px; + border-radius: 0.75rem; overflow: hidden; -} \ No newline at end of file +} diff --git a/app/assets/img/hospital_network.jpg b/app/assets/img/hospital_network.jpg deleted file mode 100644 index f8bcf0c5..00000000 Binary files a/app/assets/img/hospital_network.jpg and /dev/null differ diff --git a/app/assets/img/hospital_network.webp b/app/assets/img/hospital_network.webp new file mode 100644 index 00000000..0a36f538 Binary files /dev/null and b/app/assets/img/hospital_network.webp differ diff --git a/app/assets/img/node_network.png b/app/assets/img/node_network.png deleted file mode 100644 index 68c0dafe..00000000 Binary files a/app/assets/img/node_network.png and /dev/null differ diff --git a/app/assets/primevue/flame-preset.ts b/app/assets/primevue/flame-preset.ts index 9e56281f..6e9d7bed 100644 --- a/app/assets/primevue/flame-preset.ts +++ b/app/assets/primevue/flame-preset.ts @@ -37,7 +37,7 @@ export const Flame = definePreset(Lara, { light: { surface: { 0: "#ffffff", - 50: "#fff3ea", // Warm ash background + 50: "#fff8f2", // Warm parchment background 100: "{slate.100}", 200: "{slate.200}", // Borders 300: "{slate.300}", @@ -59,19 +59,27 @@ export const Flame = definePreset(Lara, { }, }, dark: { + // Stone palette: warm charcoal undertones vs slate's cold blue-grey surface: { 0: "#ffffff", - 50: "{slate.50}", - 100: "{slate.100}", - 200: "{slate.200}", - 300: "{slate.300}", - 400: "{slate.400}", - 500: "{slate.500}", - 600: "{slate.600}", - 700: "{slate.700}", - 800: "{slate.800}", - 900: "{slate.900}", - 950: "{slate.950}", + 50: "{stone.50}", + 100: "{stone.100}", + 200: "{stone.200}", + 300: "{stone.300}", + 400: "{stone.400}", + 500: "{stone.500}", + 600: "{stone.600}", + 700: "{stone.700}", + 800: "{stone.800}", + 900: "{stone.900}", + 950: "{stone.950}", + }, + primary: { + color: "{orange.400}", + contrastColor: "{stone.950}", + hoverColor: "{orange.300}", + activeColor: "{orange.200}", + accentColor: "{orange.600}", }, }, }, diff --git a/app/components/Footer.vue b/app/components/Footer.vue index f68c4bfd..52746d0c 100644 --- a/app/components/Footer.vue +++ b/app/components/Footer.vue @@ -32,17 +32,16 @@ const pkgVersion = config.public.version; + diff --git a/app/components/analysis/AnalysesTable.vue b/app/components/analysis/AnalysesTable.vue index 6ddf2396..c7cc02f7 100644 --- a/app/components/analysis/AnalysesTable.vue +++ b/app/components/analysis/AnalysesTable.vue @@ -7,7 +7,7 @@ import { getAnalysisNodes } from "~/composables/useAPIFetch"; import { formatDataRow } from "~/utils/format-data-row"; import { showCacheWarningToast, - showConnectionErrorToast + showConnectionErrorToast, } from "~/composables/connectionErrorToast"; import { FilterMatchMode } from "@primevue/core/api"; import SearchBar from "~/components/table/SearchBar.vue"; @@ -15,7 +15,7 @@ import AnalysisControlButtons from "./AnalysisControlButtons.vue"; import { getApprovalStatusSeverity, getBuildStatusSeverity, - getExecutionStatusSeverity + getExecutionStatusSeverity, } from "~/utils/status-tag-severity"; import { type AnalysisNode, @@ -24,7 +24,7 @@ import { type PodProgressResponse, PodStatus, type Project, - type Route + type Route, } from "~/services/Api"; import { ApprovalStatus } from "~/types/node"; import ContainerCounter from "~/components/analysis/ContainerCounter.vue"; @@ -40,12 +40,12 @@ const { nodeType, requireDataStore: datastoreRequired } = useDatastoreRequirement(); const datastoreBadgeSeverity = computed(() => - datastoreRequired.value ? "danger" : "secondary" + datastoreRequired.value ? "danger" : "secondary", ); const datastoreBadgeTooltip = computed(() => datastoreRequired.value ? "Data store missing!" - : "Data store missing, but not required" + : "Data store missing, but not required", ); const analysesMap = ref>(new Map()); @@ -61,11 +61,11 @@ const filters = ref(); // Cache const analysisCache = useState( "analysisCache", - () => undefined + () => undefined, ); const projectCache = useState( "projectCache", - () => undefined + () => undefined, ); const podOrcUnreacheable = ref(false); @@ -93,8 +93,8 @@ async function getProjects() { method: "GET", query: { sort: "-updated_at", - fields: "id,name" - } + fields: "id,name", + }, }) .catch(() => undefined)) as Project[]; } @@ -102,7 +102,7 @@ async function getProjects() { async function getKongRoutes() { const kongRoutesResp = (await useNuxtApp() .$hubApi("/kong/project", { - method: "GET" + method: "GET", }) .catch(() => undefined)) as ListRoutes; if (kongRoutesResp && kongRoutesResp.data) { @@ -144,7 +144,7 @@ async function getExecutionStatusesFromPodOrc(): Promise< > { const podOrcResponse = (await useNuxtApp() .$hubApi("/po/status", { - method: "GET" + method: "GET", }) .catch(() => { if (!podOrcUnreacheable.value) { @@ -154,7 +154,7 @@ async function getExecutionStatusesFromPodOrc(): Promise< summary: "Missing PO Status Update", detail: "Unable to retrieve pod statuses from the PO, relying on information from the Hub", - life: 3000 + life: 3000, }); } return undefined; @@ -194,13 +194,13 @@ function determineProgressBarColor(progress: number) { } return { - "--p-progressbar-value-background": color + "--p-progressbar-value-background": color, }; } function parseAnalysis( analysisEntry: ModifiedAnalysisNode, - executionStatuses: PodProgressResponse | undefined + executionStatuses: PodProgressResponse | undefined, ): ModifiedAnalysisNode { const projId = analysisEntry.analysis?.project_id; const analysisId = analysisEntry.analysis_id; @@ -210,7 +210,7 @@ function parseAnalysis( } const acceptableHubStatuses: Array = [ PodStatus.Failed, - PodStatus.Executed + PodStatus.Executed, ]; if (executionStatuses && analysisId in executionStatuses) { const podStatus = executionStatuses[analysisId]!; @@ -229,7 +229,7 @@ async function compileAnalysisTable( respStatus: string, respData: AnalysisNode[] | undefined, silent = false, - merge = false + merge = false, ) { if (!silent) tableLoading.value = true; await parseProjects(); @@ -252,13 +252,13 @@ async function compileAnalysisTable( const formattedAnalyses = formatDataRow( analysisData, ["created_at", "updated_at"], - expandRowEntries + expandRowEntries, ) as ModifiedAnalysisNode[]; if (formattedAnalyses && projMap.size > 0) { formattedAnalyses.forEach((analysisEntry: ModifiedAnalysisNode) => { parsedAnalyses.set( analysisEntry.analysis_id, - parseAnalysis(analysisEntry, currentExecutionStatuses) + parseAnalysis(analysisEntry, currentExecutionStatuses), ); }); if (merge) { @@ -319,11 +319,11 @@ async function getNextPage() { query: { page: { offset: currentOffset, - limit: queryLimit + limit: queryLimit, }, include: "analysis,node", - sort: "-updated_at" - } + sort: "-updated_at", + }, }) .catch(() => undefined)) as AnalysisNode[]; if (nextSetResults.length > 0) { @@ -344,7 +344,7 @@ const defaultFilters = { global: { value: undefined, matchMode: FilterMatchMode.CONTAINS }, approval_status: { value: undefined, matchMode: FilterMatchMode.EQUALS }, "analysis.build_status": { value: undefined, matchMode: FilterMatchMode.IN }, - execution_status: { value: undefined, matchMode: FilterMatchMode.IN } + execution_status: { value: undefined, matchMode: FilterMatchMode.IN }, }; filters.value = defaultFilters; @@ -352,7 +352,7 @@ function resetFilters() { const clearedFilters = {}; for (const filterKey in defaultFilters) { clearedFilters[filterKey] = { - ...defaultFilters[filterKey] + ...defaultFilters[filterKey], }; clearedFilters[filterKey].value = undefined; } @@ -365,7 +365,7 @@ const updateFilters = (filterText: string) => { function updateAnalysisRun( analysisId: string, - newStatusData: AnalysisStatus | undefined + newStatusData: AnalysisStatus | undefined, ) { if (analysesMap.value.has(analysisId)) { const analysisToUpdate = analysesMap.value.get(analysisId)!; // Tell typescript we are sure there is a value @@ -387,7 +387,7 @@ function updateExecutionStatusFilter(filterText: string) { if (currentExecutionStatusFilters.includes(filterText)) { // If filter already there, then remove it const filteredStatuses = currentExecutionStatusFilters.filter( - (item) => item !== filterText + (item) => item !== filterText, ); if (filteredStatuses.length == 0) { // If empty array after filtering then set to null @@ -410,7 +410,7 @@ const showDataStoreNavToast = () => { "Unable to find an associated data store, click the button below " + "to create a data store for the project of this analysis", group: "datastoreToastLink", - life: 10000 + life: 10000, }); }; @@ -457,23 +457,35 @@ const onCloseNavToast = () => { @@ -734,17 +746,17 @@ const onCloseNavToast = () => { @@ -847,48 +859,65 @@ const onCloseNavToast = () => { diff --git a/app/components/analysis/ContainerCounter.vue b/app/components/analysis/ContainerCounter.vue index 428e58dc..20c00ad5 100644 --- a/app/components/analysis/ContainerCounter.vue +++ b/app/components/analysis/ContainerCounter.vue @@ -39,7 +39,7 @@ function onApplyExecutionStatusFilter(executionStatus: PodStatus) {
- diff --git a/app/components/data-stores/DetailedDataStoreTable.vue b/app/components/data-stores/DetailedDataStoreTable.vue index 31177e18..c8d5189a 100644 --- a/app/components/data-stores/DetailedDataStoreTable.vue +++ b/app/components/data-stores/DetailedDataStoreTable.vue @@ -195,6 +195,7 @@ const updateFilters = (filterText: string) => { filterDisplay="menu" paginator tableStyle="min-width: 50rem" + class="rounded-table" > { - diff --git a/app/pages/index.vue b/app/pages/index.vue index 883e9b86..95ed149d 100644 --- a/app/pages/index.vue +++ b/app/pages/index.vue @@ -7,14 +7,14 @@ definePageMeta({