Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
22 commits
Select commit Hold shift + click to select a range
4f2348c
feat: replace buttons with trailhand buttons
johnlcos Feb 25, 2026
04ebfbe
feat: apply trailhand components to dashboard and override nav styles
johnlcos Feb 27, 2026
daae613
feat: move styles to single file and update colors
johnlcos Mar 2, 2026
0f77251
chore: use new single tone icons
johnlcos Mar 3, 2026
3f130c2
fix: version font weight, progress bar height, about link, side menu …
johnlcos Mar 3, 2026
1850411
fix: info card title color
johnlcos Mar 4, 2026
f2723f6
Merge pull request #533 from epinio/feat/EPINIO-315__trailhand_button
johnlcos Mar 4, 2026
a80170d
fix: hide info button in standalone and hide trailhand console warnings
johnlcos Mar 4, 2026
c459c3a
Merge pull request #536 from epinio/feat/EPINIO-315__trailhand_button
johnlcos Mar 5, 2026
6eadefc
Merge branch 'development' of github.com:epinio/ui into 1.14.0
dcharles525 Mar 5, 2026
a916ac0
feat: updating applications page to use trailhand table. Connecting n…
Hannahbird Mar 3, 2026
5b9de2e
refactor(tables): adopt data-table web component
Hannahbird Mar 5, 2026
b2f9d78
fix: show about in side nav on extension and fix darkmode bg
johnlcos Mar 6, 2026
1055330
fix: address data-table review feedback
Hannahbird Mar 9, 2026
916d755
fix: adding additional icons to deployed and not ready status
Hannahbird Mar 9, 2026
be80947
chore: updating component names from trailhand.
Hannahbird Mar 9, 2026
3b161e1
Merge pull request #540 from epinio/chore/EPINIO-492__about_in_nav
johnlcos Mar 9, 2026
0d4bc4f
change requests
Hannahbird Mar 9, 2026
0167be6
pre-fetch configurations and services in loadCluster for instant page…
Hannahbird Mar 11, 2026
35df0de
Merge branch '1.14.0' of github.com:epinio/ui into feat/EPINIO-479__t…
Hannahbird Mar 11, 2026
76373da
fix(polling): stop poller leaks and reduce cross-page contention
Hannahbird Mar 11, 2026
f769184
Merge pull request #538 from epinio/feat/EPINIO-479__trailhand_table
Hannahbird Mar 12, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
25,055 changes: 25,055 additions & 0 deletions dashboard/package-lock.json

Large diffs are not rendered by default.

1 change: 1 addition & 0 deletions dashboard/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
"node": ">=20"
},
"dependencies": {
"@krumio/trailhand-ui": "^1.9.2",
"@rancher/shell": "3.0.7",
"@types/lodash": "^4.17.16",
"eslint": "^9.28.0",
Expand Down
160 changes: 160 additions & 0 deletions dashboard/pkg/epinio/assets/overrides.scss
Original file line number Diff line number Diff line change
@@ -1,3 +1,163 @@
@import '@krumio/trailhand-ui/styles/colors.css';
@import url('https://fonts.googleapis.com/css2?family=Poppins:wght@400;500;600;700&display=swap');

// Font - scoped to epinio
body.epinio-active {
nav, main, .product, .rd-header-right {
font-family: 'Poppins', sans-serif;
}
}

// Light mode variables - only when epinio is active
body.epinio-active {
nav, main, .product, .rd-header-right, .spacer, .menu-spacer {
--active-nav-bg: var(--th-color-light-primary);
--active-nav-text: var(--th-color-dark-primary);
--th-card-icon-color: var(--th-color-primary);
--primary-border: var(--th-color-primary);
--link: var(--th-color-primary);
--th-card-bg: var(--th-color-background);
--th-progress-bar-height: 16px;
--th-progress-bar-border-radius: 8px;

.dashboard-card {
--th-card-bg: var(--th-color-grey-100);
}
}

main {
background-color: var(--body-bg);
}
}

// Dark mode variables - only when epinio is active
body.epinio-active[data-theme='dark'],
[data-theme='dark'] body.epinio-active {
nav, main, .product, .rd-header-right, .spacer, .menu-spacer {
--th-color-primary: #5DB2FF;
--body-bg: var(--th-color-background);
--active-nav-bg: color-mix(in srgb, var(--th-color-primary) 20%, transparent);
--active-nav-text: var(--th-color-primary);
--nav-hover: var(--th-color-grey-700);
--body-border: var(--th-color-border);
--nav-bg: var(--th-color-background);
--header-bg: var(--th-color-background);
--th-button-secondary-border: var(--th-color-primary);
--th-button-secondary-bg: transparent;
--th-button-secondary-bg-hover: var(--th-color-grey-800);

.dashboard-card {
--th-card-bg: var(--th-color-grey-700);
}
}

main {
background-color: var(--body-bg);
}
}

// Side nav styles - only when epinio is active
body.epinio-active {
.side-nav {
--category-active-hover: transparent;
padding: 10px 8px;

.nav {
.child.nav-type {
height: 48px;
border-radius: 4px;
i {
display: none;
}
a.type-link {
height: 100%;
display: flex;
align-items: center;
padding: 12px;
border-radius: 4px;
color: inherit;
font-size: 1rem;
font-weight: 500;
color: var(--th-color-text-secondary);
justify-content: start;
margin: 0;
}

// Reset rancher's router-link-active styles when it's not exact active
&.router-link-active:not(.router-link-exact-active) {
a.type-link {
background-color: transparent;
color: var(--th-color-text-secondary);
}
}

// Active - on the li
&.router-link-active {
a.type-link {
background-color: transparent;
color: var(--active-nav-text);
}
}

// Exact active - on the li
&.router-link-exact-active {
a.type-link {
background-color: var(--active-nav-bg);
color: var(--active-nav-text);
}
}
}

.accordion {
.accordion-item {
height: 48px;
display: flex;
align-items: center;
justify-content: space-between;
color: var(--th-color-text-secondary);

.header {
width: 100%;
h6 {
color: var(--th-color-text-secondary);
font-size: 1rem;
font-weight: 500;
display: flex;
justify-content: start;
gap: 5px;
}
}

.header:hover {
background-color: transparent;
}

.icon {
position: relative;
top: unset;
right: unset;
}
}
.accordion-item:hover {
background-color: var(--nav-hover);
}
}

.accordion.depth-0.child:hover {
background-color: transparent;
}
.accordion.depth-0.group-highlight:hover {
background-color: transparent;
}
.accordion.depth-0.group-highlight {
background: transparent;
--category-active-hover: var(--nav-hover);
}
}

}
}

.side-menu-logo{
align-items: center;
display: flex;
Expand Down
118 changes: 58 additions & 60 deletions dashboard/pkg/epinio/components/application/AppProgress.vue
Original file line number Diff line number Diff line change
@@ -1,22 +1,17 @@
<script lang="ts" setup>
import { ref, computed, watch, onMounted } from 'vue';
import { ref, computed, watch, onMounted, reactive } from 'vue';
import { useStore } from 'vuex';

import SortableTable from '@shell/components/SortableTable/index.vue';
import Checkbox from '@components/Form/Checkbox/Checkbox.vue';
import BadgeState from '@components/BadgeState/BadgeState.vue';

import ApplicationAction, { APPLICATION_ACTION_TYPE } from '../../models/application-action';
import { STATE, DESCRIPTION } from '@shell/config/table-headers';
import {
EPINIO_TYPES,
APPLICATION_ACTION_STATE,
EPINIO_TYPES,
APPLICATION_SOURCE_TYPE,
EpinioApplication,
EpinioAppSource,
EpinioAppBindings
} from '../../types';
import type EpinioNamespace from '../../models/namespaces';
import { makeProgressStateCell } from '../../utils/table-formatters';

const props = defineProps<{
application: EpinioApplication,
Expand All @@ -29,33 +24,63 @@ const props = defineProps<{
const emit = defineEmits(['finished']);

const store = useStore();
const t = store.getters['i18n/t'];

const running = ref(false);
const actions = ref<ApplicationAction[]>([]);

const actionHeaders = [
const columns = [
{
name: 'epinio-name',
labelKey: 'epinio.applications.steps.progress.table.stage.label',
value: 'name',
sort: ['index'],
width: 150,
field: 'name',
label: t('epinio.applications.steps.progress.table.stage.label'),
width: '150px',
sortable: false,
},
{
...DESCRIPTION,
sort: undefined,
value: 'description',
width: 450,
field: 'description',
label: t('tableHeaders.description'),
width: '450px',
sortable: false,
formatter: (_v: any, row: any) => {
const wrapper = document.createElement('span');

wrapper.style.cssText = 'display:flex; flex-direction:column;';

const main = document.createElement('span');

main.textContent = row.description || '';
wrapper.appendChild(main);

// stateMessage is set on failure — show it as secondary error text
if (row.stateMessage) {
const sub = document.createElement('span');

sub.style.cssText = 'font-size:0.85em; color:var(--error); margin-top:2px;';
sub.textContent = row.stateMessage;
wrapper.appendChild(sub);
}

return wrapper;
},
},
{
...STATE,
sort: undefined,
labelKey: 'epinio.applications.steps.progress.table.status',
width: 150,
field: 'stateDisplay',
label: t('epinio.applications.steps.progress.table.status'),
width: '150px',
sortable: false,
formatter: (_v: any, row: any) => makeProgressStateCell(row),
},
];

const actionsToRun = computed(() => actions.value.filter(action => action.run));

// tableRows is a copy of actions that tracks state and stateMessage so any change to those properties triggers a Lit re-render
const tableRows = computed(() => {
// Track state and stateMessage so any change triggers a Lit re-render
actions.value.forEach((a: ApplicationAction) => { a.state; (a as any).stateMessage; });

return [...actions.value];
});
const namespaces = computed(() => store.getters['epinio/all'](EPINIO_TYPES.NAMESPACE));
const fetchApp = async () => {
try {
Expand All @@ -66,6 +91,8 @@ const fetchApp = async () => {
};

const create = async () => {
// Make each action reactive so changes to their state trigger updates in the UI
actions.value = actions.value.map((a: ApplicationAction) => reactive(a) as ApplicationAction);
running.value = true;
const enabledActions = [...actionsToRun.value];

Expand Down Expand Up @@ -184,35 +211,12 @@ onMounted(createActions);
class="progress-container"
>
<div class="progress">
<SortableTable
:rows="actions"
:headers="actionHeaders"
:table-actions="false"
:row-actions="false"
default-sort-by="epinio-name"
:search="false"
<trailhand-table
:rows="tableRows"
:columns="columns"
:searchable="false"
key-field="key"
>
<template #cell:index="{ row }">
<Checkbox v-model="row.run" :disabled="true" />
</template>

<template #cell:state="{ row }">
<div class="status">
<i
v-if="row.state === APPLICATION_ACTION_STATE.RUNNING"
v-clean-tooltip="row.stateDisplay"
class="icon icon-lg icon-spinner icon-spin"
/>
<BadgeState
v-else
:color="row.stateBackground"
:label="row.stateDisplay"
class="badge"
/>
</div>
</template>
</SortableTable>
/>
</div>
</div>
</template>
Expand All @@ -225,16 +229,10 @@ onMounted(createActions);
.progress {
padding: 10px 0;

$statusHeight: 20px;

.status {
min-height: $statusHeight;
display: flex;
align-items: center;

.badge {
min-height: $statusHeight;
}
trailhand-table {
--sortable-table-row-hover-bg: var(--sortable-table-hover-bg);
--sortable-table-header-hover-bg: var(--sortable-table-hover-bg);
--sortable-table-header-sorted-bg: var(--sortable-table-hover-bg);
}
}
}
Expand Down
2 changes: 1 addition & 1 deletion dashboard/pkg/epinio/components/application/AppSource.vue
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ import Application from '../../models/applications';
import LabeledInput from '@components/Form/LabeledInput/LabeledInput.vue';
import LabeledSelect from '@shell/components/form/LabeledSelect.vue';
import FileSelector from '@shell/components/form/FileSelector.vue';
import GitPicker from '@shell/components/form/GitPicker.vue';
import GitPicker from './GitPicker.vue';
import RadioGroup from '@components/Form/Radio/RadioGroup.vue';
import { sortBy } from '@shell/utils/sort';
import { generateZip } from '@shell/utils/download';
Expand Down
Loading
Loading