Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
53 commits
Select commit Hold shift + click to select a range
fa10af4
Update applications.vue
psanghvi17 Jan 29, 2026
a119b68
download buton added in system->about
psanghvi17 Jan 30, 2026
99edfd0
Update ExportAppDialog.vue
psanghvi17 Feb 5, 2026
b40bb07
Update en-us.yaml
psanghvi17 Feb 5, 2026
cf3d904
Merge branch 'development' of github.com:epinio/ui into Scale-instanc…
dcharles525 Feb 10, 2026
fdd2398
change debounce from 1 to 2
dcharles525 Feb 10, 2026
42c1202
Merge pull request #521 from epinio/Scale-instances-without-waiting
dcharles525 Feb 10, 2026
60e604b
Add RBAC permissions and enforce UI actions
psanghvi17 Feb 11, 2026
5bb0c49
linting error esolved
psanghvi17 Feb 11, 2026
b434714
Update ExportAppDialog.vue
psanghvi17 Feb 16, 2026
32e66cc
L:int error
psanghvi17 Feb 16, 2026
16b32a7
Merge pull request #528 from epinio/download-zip-server-side
dcharles525 Feb 16, 2026
50491a6
chore(deps): bump anchore/sbom-action from 0.21.1 to 0.23.0
dependabot[bot] Feb 26, 2026
fa5dd41
chore(deps): bump actions/upload-artifact from 6 to 7
dependabot[bot] Feb 27, 2026
ce3a3af
chore(deps): bump actions/download-artifact from 7 to 8
dependabot[bot] Feb 27, 2026
737f129
Edit config button visibility corrected
psanghvi17 Mar 5, 2026
301e0c4
chore(deps): bump docker/setup-buildx-action from 3 to 4
dependabot[bot] Mar 5, 2026
81acc83
Create instance button hidden from read only user
psanghvi17 Mar 5, 2026
bc1ecd8
Merge branch 'main' of github.com:epinio/ui into development
dcharles525 Mar 5, 2026
024516a
Merge branch 'development' of github.com:epinio/ui into development
dcharles525 Mar 5, 2026
6340446
chore(Cleanup UI naming):
dcharles525 Mar 5, 2026
8685dd6
Merge pull request #522 from epinio/usage-report
dcharles525 Mar 5, 2026
a7c5d84
gate Create/Shell/Config by permissions, fix Vue reactive warning
psanghvi17 Mar 6, 2026
862fade
fix(show cluster table based on all cluster count, not epinio cluster…
dcharles525 Mar 10, 2026
a8e21c3
chore(bump for rc1):
dcharles525 Mar 10, 2026
77ad6e5
chore(bump to rc2 due to failed uploads):
dcharles525 Mar 10, 2026
5a64367
enforce RBAC for Edit Config and Shell in applications
psanghvi17 Mar 11, 2026
e053847
show applications table for every namespace when empty
psanghvi17 Mar 12, 2026
af6654a
Enforce RBAC for Edit Config and Create in Epinio UI
psanghvi17 Mar 13, 2026
ccb3e7e
add Install button to trigger Epinio install on unregistered clusters
psanghvi17 Mar 18, 2026
d11210e
Update index.vue
psanghvi17 Mar 18, 2026
69800cd
Update InstallDialog.vue
psanghvi17 Mar 19, 2026
5d9059a
Merge pull request #542 from epinio/feat/EPINIO-494-application-table…
dcharles525 Mar 23, 2026
639be68
Merge pull request #545 from epinio/feat-epinio-243-Trigger-to-deploy…
dcharles525 Mar 31, 2026
a59ce43
Merge pull request #530 from epinio/dependabot/github_actions/anchore…
dcharles525 Mar 31, 2026
bf19a77
Merge pull request #531 from epinio/dependabot/github_actions/actions…
dcharles525 Mar 31, 2026
f8266c9
Merge pull request #532 from epinio/dependabot/github_actions/actions…
dcharles525 Mar 31, 2026
04eddd3
Merge pull request #537 from epinio/dependabot/github_actions/docker/…
dcharles525 Mar 31, 2026
818e630
Bump version to v1.13.10-rc3 in package.json
dcharles525 Mar 31, 2026
154b7fd
Bump version from 1.13.10-rc2 to 1.13.10-rc3
dcharles525 Mar 31, 2026
6efcc0f
chore(Cleanup and add automatically update the table upon install of …
dcharles525 Apr 6, 2026
4ac0010
Merge pull request #557 from epinio/chore/epinio-install-cleanup
psanghvi17 Apr 7, 2026
f5edcb8
chore(bump versions/crd refs for install operator support):
dcharles525 Apr 7, 2026
6ac0780
Update data structure in configurations.js
dcharles525 Apr 7, 2026
14bcb75
Merge pull request #559 from epinio/fix/configuration-update
dcharles525 Apr 7, 2026
579ecd0
chore(bump for rc4):
dcharles525 Apr 7, 2026
d348e99
fix(The MastHead component was showing twice due to the route not hav…
dcharles525 Apr 8, 2026
75bcaf3
Merge branch 'development' into new-rbac
dcharles525 Apr 8, 2026
784d159
Merge pull request #527 from epinio/new-rbac
dcharles525 Apr 8, 2026
0e34acd
chore(bump to rc5):
dcharles525 Apr 8, 2026
7382767
Merge branch 'development' of github.com:epinio/ui into development
dcharles525 Apr 8, 2026
181f10b
fix(cleanup missed merge conflict):
dcharles525 Apr 8, 2026
5b1acd2
chore(bump for full release):
dcharles525 Apr 10, 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
4 changes: 2 additions & 2 deletions .github/workflows/dashboard-build-extension.yml
Original file line number Diff line number Diff line change
Expand Up @@ -105,7 +105,7 @@ jobs:

- name: Upload charts artifact
if: github.ref_type == 'tag' || (github.ref == 'refs/heads/main' && github.event_name != 'pull_request') || inputs.is_test == 'true'
uses: actions/upload-artifact@v6
uses: actions/upload-artifact@v7
with:
name: charts
path: ./dashboard/tmp
Expand Down Expand Up @@ -134,7 +134,7 @@ jobs:
git config user.email 'github-actions[bot]@users.noreply.github.com'

- name: Download build artifact
uses: actions/download-artifact@v7
uses: actions/download-artifact@v8
with:
name: charts
path: ./dashboard
Expand Down
4 changes: 2 additions & 2 deletions .github/workflows/release-next.yml
Original file line number Diff line number Diff line change
Expand Up @@ -38,14 +38,14 @@ jobs:
name: Install yarn
run: npm install --global yarn
-
uses: anchore/sbom-action/download-syft@v0.21.1
uses: anchore/sbom-action/download-syft@v0.23.0
-
uses: sigstore/cosign-installer@v4.0.0
with:
cosign-release: 'v2.5.1'
-
name: Set up Docker Buildx
uses: docker/setup-buildx-action@v3
uses: docker/setup-buildx-action@v4
-
name: Login to GitHub Docker Registry
uses: docker/login-action@v3
Expand Down
4 changes: 2 additions & 2 deletions .github/workflows/release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -38,14 +38,14 @@ jobs:
name: Install yarn
run: npm install --global yarn
-
uses: anchore/sbom-action/download-syft@v0.21.1
uses: anchore/sbom-action/download-syft@v0.23.0
-
uses: sigstore/cosign-installer@v4.0.0
with:
cosign-release: 'v2.5.1'
-
name: Set up Docker Buildx
uses: docker/setup-buildx-action@v3
uses: docker/setup-buildx-action@v4
-
name: Login to GitHub Docker Registry
uses: docker/login-action@v3
Expand Down
File renamed without changes.
2 changes: 1 addition & 1 deletion dashboard/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "epinio",
"version": "v1.13.9",
"version": "v1.13.10",
"engines": {
"node": ">=20"
},
Expand Down
20 changes: 11 additions & 9 deletions dashboard/pkg/epinio/config/epinio.ts
Original file line number Diff line number Diff line change
Expand Up @@ -137,29 +137,31 @@ export function init($plugin: any, store: any) {
customRoute: createEpinioRoute('c-cluster-resource', { resource: EPINIO_TYPES.APP_CHARTS }),
});

// Configuration resource
// Configuration resource (isCreatable: false so shell doesn't show Create; list shows it only when canCreateConfiguration)
configureType(EPINIO_TYPES.CONFIGURATION, {
isCreatable: true,
isEditable: true,
isRemovable: true,
showState: false,
canYaml: false,
customRoute: createEpinioRoute('c-cluster-resource', { resource: EPINIO_TYPES.CONFIGURATION }),
isCreatable: true,
isEditable: true,
isRemovable: true,
showState: false,
canYaml: false,
customRoute: createEpinioRoute('c-cluster-resource', { resource: EPINIO_TYPES.CONFIGURATION }),
showListMasthead: false
});

// Groups
const ADVANCED_GROUP = 'Advanced';
const SERVICE_GROUP = 'Services';
const ABOUT = 'System';

// Service Instance
// Service Instance (isCreatable: false so shell doesn't show Create; our list/services.vue shows it only when canCreateService)
configureType(EPINIO_TYPES.SERVICE_INSTANCE, {
isCreatable: true,
isCreatable: false,
isEditable: true,
isRemovable: true,
showState: true,
canYaml: false,
customRoute: createEpinioRoute('c-cluster-resource', { resource: EPINIO_TYPES.SERVICE_INSTANCE }),
showListMasthead: false, // Custom masthead with RBAC-gated Create button
});

// Catalog Service
Expand Down
56 changes: 46 additions & 10 deletions dashboard/pkg/epinio/detail/applications.vue
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,8 @@ const store = useStore();

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

const saving = ref(false);
const scalingInFlight = ref(false);
const debouncePending = ref(false);
const gitSource = ref<any>(null);
const gitDeployment = ref({
deployedCommit: { short: '', long: '' },
Expand Down Expand Up @@ -124,6 +125,10 @@ const commitActions = [{
enabled: true
}];

// Debounce settings for scaling instances
const UPDATE_INSTANCES_DEBOUNCE_MS = 2000; // 2s; adjust as needed
let updateInstancesTimeout: number | null = null;

onMounted(async () => {
await store.dispatch('epinio/findAll', { type: EPINIO_TYPES.SERVICE_INSTANCE });
await store.dispatch('epinio/findAll', { type: EPINIO_TYPES.CONFIGURATION });
Expand All @@ -135,17 +140,35 @@ onMounted(async () => {
});

async function updateInstances(newInstances: number) {
saving.value = true;
try {
props.value.configuration.instances = newInstances;
await props.value.update();
await props.value.forceFetch();
} catch (err) {
console.error(`Failed to scale Application: `, epinioExceptionToErrorsArray(err));
// Update desired and configured instances immediately so the UI reflects the target
props.value.desiredInstances = newInstances;
props.value.configuration.instances = newInstances;

// Debounce the API call so rapid clicks collapse into one request
if (updateInstancesTimeout !== null) {
clearTimeout(updateInstancesTimeout);
}
saving.value = false;
debouncePending.value = true;

updateInstancesTimeout = window.setTimeout(async () => {
debouncePending.value = false;
scalingInFlight.value = true;

try {
await props.value.update();
await props.value.forceFetch();
} catch (err) {
console.error('[Epinio instances] Failed to scale Application', epinioExceptionToErrorsArray(err));
} finally {
scalingInFlight.value = false;
debouncePending.value = false;
updateInstancesTimeout = null;
}
}, UPDATE_INSTANCES_DEBOUNCE_MS);
}

const showScaleSpinner = computed(() => debouncePending.value || scalingInFlight.value);

function formatURL(str: string) {
const matchGit = str.match('^(https|git)(:\/\/|@)([^\/:]+)[\/:]([^\/:]+)\/(.+)(.git)*$'); // eslint-disable-line no-useless-escape
return `${matchGit?.[4]}/${matchGit?.[5]}`;
Expand Down Expand Up @@ -333,10 +356,16 @@ const commitPosition = computed(() => {
<PlusMinus
v-model:value="value.desiredInstances"
class="mt-15 mb-10"
:disabled="saving"
:disabled="scalingInFlight"
@minus="updateInstances(value.desiredInstances - 1)"
@plus="updateInstances(value.desiredInstances + 1)"
/>
<div
v-if="showScaleSpinner"
class="scale-instances__spinner mt-5"
>
<i class="icon-spinner animate-spin" />
</div>
</div>

<div class="deployment__origin__row">
Expand Down Expand Up @@ -746,6 +775,13 @@ const commitPosition = computed(() => {
}
}

.scale-instances__spinner {
display: inline-flex;
align-items: center;
font-size: 12px;
color: var(--muted-text);
}

.deployment__origin__list {
ul {
margin: 0;
Expand Down
79 changes: 38 additions & 41 deletions dashboard/pkg/epinio/dialog/ExportAppDialog.vue
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
<script setup lang="ts">
import { useStore } from 'vuex'
import {ref, computed, onMounted, onBeforeUnmount } from 'vue';
import { ref, onMounted, onBeforeUnmount } from 'vue';

import JSZip from 'jszip';

Expand All @@ -10,7 +10,6 @@ import Tab from '@shell/components/Tabbed/Tab.vue';
import { downloadFile } from '@shell/utils/download';
import GenericPrompt from '@shell/dialog/GenericPrompt';
import Tabbed from '@shell/components/Tabbed/index.vue';
import PercentageBar from '@shell/components/PercentageBar';

const store = useStore();
const t = store.getters['i18n/t'];
Expand All @@ -23,18 +22,10 @@ const props = defineProps<{
}>();

const showProgressBar = ref<boolean>(false);
const percentages = ref<object>({});
const step = ref<any>(null);
const cancelTokenSources:object = {};
const colorStops:object = { 0: '--primary', 100: '--primary' };
const genericPrompt = ref<HTMLElement>(null);

const partsWeight = {
[APPLICATION_PARTS.VALUES]: 0.1,
[APPLICATION_PARTS.CHART]: 0.1,
[APPLICATION_PARTS.IMAGE]: 0.7
};

const zipParts = props.resources[0]?.applicationParts.filter(
(part) => part !== APPLICATION_PARTS.MANIFEST
);
Expand All @@ -51,16 +42,6 @@ onBeforeUnmount(() => {
}, 2000);
});

const progressBar = computed({
get() {
return Object.keys(percentages.value).reduce(
(acc, part) => acc + (percentages.value[part] * (partsWeight[part] || 1)), 0);
},
set(value) {
percentages.value = { value };
}
}, { immediate: true });

const exportApplicationManifest = async () => {
enableDownload();
const resource = props.resources[0];
Expand Down Expand Up @@ -93,6 +74,19 @@ const exportApplicationManifest = async () => {
if (store.$router.currentRoute._value.hash === '#manifest') {
await resource.createManifest();
} else {
// Prefer server-side archive (one download, no client zip) when backend supports it
const archiveBlob = await fetchPartArchive(resource);
if (archiveBlob) {
await downloadFile(
`${ resource.meta.name }-helm-chart.zip`,
archiveBlob,
'application/zip',
);
await delayBeforeClose(1500);
return;
}

// Fallback: fetch three parts and zip in browser (slower, especially in Rancher extension)
const partsData = await zipParts.reduce(async(acc, part) => ({
...await acc,
[part]: await fetchPart(resource, part),
Expand All @@ -106,7 +100,6 @@ const exportApplicationManifest = async () => {

await chartZip(partsData);

progressBar.value = 100;
await delayBeforeClose(1500);
}
}
Expand All @@ -121,20 +114,32 @@ const getCancelToken = () => {
return store.$axios.CancelToken;
}

// Fetches server-side archive (one zip). Returns blob or null if backend does not support it.
const fetchPartArchive = async (resource) => {
toggleStep('archive', true);
cancelTokenSources.archive = getCancelToken().source();
try {
const blob = await resource.fetchPart('archive', {
onDownloadProgress: (progressEvent) => {
if (progressEvent.loaded > 0) {
toggleStep('archive');
}
},
cancelToken: cancelTokenSources.archive?.token,
});
return blob;
} catch {
return null;
}
};

const fetchPart = async (resource, part) => {
toggleStep(part, true);
cancelTokenSources[part] = getCancelToken().source();

return await resource.fetchPart(
part, {
onDownloadProgress: (progressEvent) => {
const total = progressEvent.event.srcElement.getResponseHeader('content-length') ||
progressEvent.event.srcElement.getResponseHeader('proxy-content-length');

if (total) {
percentages.value[part] = Math.round(progressEvent.loaded * 100 / total);
}

if (progressEvent.loaded > 0) {
toggleStep(part);
}
Expand All @@ -159,8 +164,7 @@ const fetchPart = async (resource, part) => {
const fetchCancel = () => {
// Cancel pending api requests, see https://axios-http.com/docs/cancellation
Object.keys(cancelTokenSources).forEach(
(part) => cancelTokenSources[part].
cancel(`${ part } part: download cancelled.`)
(part) => cancelTokenSources[part]?.cancel?.(`${ part } part: download cancelled.`)
);
}

Expand Down Expand Up @@ -192,7 +196,6 @@ const enableDownload = () => {
const disableDownload = () => {
fetchCancel();
showProgressBar.value = false;
progressBar.value = 0;
toggleStep(null);
}

Expand Down Expand Up @@ -251,15 +254,10 @@ const toggleStep = (part, isPreparing = false) => {
v-if="showProgressBar"
class="progress-info text info mb-10 mt-20"
>
<i class="icon-spinner animate-spin mr-5" />
<span v-if="step">
{{ t(`epinio.applications.export.chartValuesImages.steps.${ step }`) }}
</span>
<PercentageBar
class="progress-bar"
:modelValue="progressBar"
:color-stops="colorStops"
preferred-direction="MORE"
/>
</div>
</Tab>
</Tabbed>
Expand All @@ -277,9 +275,8 @@ const toggleStep = (part, isPreparing = false) => {
}

.progress-info {
span {
display: block;
margin-bottom: 10px;
}
display: flex;
align-items: center;
gap: 8px;
}
</style>
Loading
Loading