diff --git a/src_assets/common/assets/web/apps.html b/src_assets/common/assets/web/apps.html
index 8525749092e..c398014622b 100644
--- a/src_assets/common/assets/web/apps.html
+++ b/src_assets/common/assets/web/apps.html
@@ -14,27 +14,37 @@
{{ $t('apps.applications_title') }} ({{ appCountLab
-
-
-
-
-
@@ -416,7 +426,7 @@
{{ $t('apps.env_vars_about') }}
sh -c "displayplacer "id:<screenId> res:${SUNSHINE_CLIENT_WIDTH}x${SUNSHINE_CLIENT_HEIGHT} hz:${SUNSHINE_CLIENT_FPS} scaling:on origin:(0,0) degree:0""
@@ -569,7 +579,6 @@ {{ fileBrowserTitle || $t('file_browser.title') }}
data() {
return {
apps: [],
- showEditForm: false,
editForm: null,
detachedCmd: "",
coverSearching: false,
@@ -589,6 +598,7 @@ {{ fileBrowserTitle || $t('file_browser.title') }}
fileBrowserTypedPath: "",
searchQuery: "",
sortMode: "default",
+ deleteTarget: null,
version: null,
githubVersion: null,
};
@@ -646,14 +656,21 @@ {{ fileBrowserTitle || $t('file_browser.title') }}
? `${total}`
: `${shown} / ${total}`;
},
+ editModalTitle() {
+ if (!this.editForm) {
+ return "";
+ }
+ const action = this.editForm.index === -1
+ ? this.$t("apps.add_new")
+ : this.$t("apps.edit");
+
+ return this.editForm.name
+ ? `${action}: ${this.editForm.name}`
+ : action;
+ },
},
created() {
- fetch("./api/apps")
- .then((r) => r.json())
- .then((r) => {
- console.log(r);
- this.apps = r.apps;
- });
+ this.loadApps();
fetch("./api/config")
.then(r => r.json())
@@ -683,8 +700,7 @@ {{ fileBrowserTitle || $t('file_browser.title') }}
detached: [],
"image-path": ""
};
- this.editForm.index = -1;
- this.showEditForm = true;
+ this.openEditModal();
},
editApp(id) {
this.editForm = JSON.parse(JSON.stringify(this.apps[id]));
@@ -707,22 +723,34 @@ {{ fileBrowserTitle || $t('file_browser.title') }}
if (this.editForm["exit-timeout"] === undefined) {
this.editForm["exit-timeout"] = 5;
}
- this.showEditForm = true;
- },
- showDeleteForm(id) {
- let resp = confirm(
- "Are you sure to delete " + this.apps[id].name + "?"
- );
- if (resp) {
- apiFetch("./api/apps/" + id, {
- method: "DELETE",
- headers: {
- "Content-Type": "application/json"
- },
- }).then((r) => {
- if (r.status === 200) document.location.reload();
+ this.openEditModal();
+ },
+ showDeleteModal(id) {
+ this.deleteTarget = { index: id, name: this.apps[id].name };
+ this.$nextTick(() => {
+ Modal.getOrCreateInstance(this.$refs.deleteModal).show();
+ });
+ },
+ closeDeleteModal() {
+ const modal = Modal.getInstance(this.$refs.deleteModal);
+ if (modal) modal.hide();
+ },
+ loadApps() {
+ return fetch("./api/apps")
+ .then((r) => r.json())
+ .then((r) => {
+ this.apps = r.apps;
});
- }
+ },
+ confirmDelete() {
+ apiFetch("./api/apps/" + this.deleteTarget.index, {
+ method: "DELETE",
+ headers: {
+ "Content-Type": "application/json"
+ },
+ }).then((r) => {
+ if (r.status === 200) document.location.reload();
+ });
},
addPrepCmd() {
let template = {
@@ -747,6 +775,8 @@ {{ fileBrowserTitle || $t('file_browser.title') }}
this.coverCandidates = [];
this.coverSearchQuery = "";
+ this.showStacked(this.$refs.coverFinderModal);
+
// Perform initial search with app name
this.performCoverSearch();
},
@@ -844,7 +874,7 @@ {{ fileBrowserTitle || $t('file_browser.title') }}
this.fileBrowserTypedPath = startPath || '';
this.fileBrowserError = '';
this.fileBrowserNavigate(startPath || '');
- Modal.getOrCreateInstance(this.$refs.fileBrowserModal).show();
+ this.showStacked(this.$refs.fileBrowserModal);
},
fileBrowserClose() {
const modal = Modal.getInstance(this.$refs.fileBrowserModal);
@@ -944,6 +974,32 @@ {{ fileBrowserTitle || $t('file_browser.title') }}
else
this.sortMode = "default";
},
+ openEditModal() {
+ // Use $nextTick because if the edit version of the modal is created too early, it breaks...
+ this.$nextTick(() => {
+ Modal.getOrCreateInstance(this.$refs.editModal).show();
+ });
+ },
+ closeEditModal() {
+ const modal = Modal.getInstance(this.$refs.editModal);
+ if (modal) modal.hide();
+ },
+ // We need to update the z-index since bootstrap gives all modals the same z-index
+ // Fixes the stacking issue of modals (cover finder / file browser)
+ showStacked(modalEl) {
+ modalEl.addEventListener('show.bs.modal', () => {
+ const openCount = document.querySelectorAll('.modal.show').length;
+ const z = 1055 + (openCount + 1) * 20;
+ modalEl.style.zIndex = z;
+
+ requestAnimationFrame(() => {
+ const backdrops = document.querySelectorAll('.modal-backdrop');
+ const backdrop = backdrops[backdrops.length - 1];
+ if (backdrop) backdrop.style.zIndex = z - 10;
+ });
+ }, { once: true });
+ Modal.getOrCreateInstance(modalEl).show();
+ },
},
});
diff --git a/src_assets/common/assets/web/public/assets/css/sunshine.css b/src_assets/common/assets/web/public/assets/css/sunshine.css
index a8efdffdfbf..b7cb502345e 100644
--- a/src_assets/common/assets/web/public/assets/css/sunshine.css
+++ b/src_assets/common/assets/web/public/assets/css/sunshine.css
@@ -682,6 +682,7 @@ body {
.modal-header,
.modal-footer {
border-color: var(--color-border) !important;
+ background-color: var(--color-surface-raised) !important;
}
.list-group-item {
@@ -1713,7 +1714,7 @@ p {
}
.apps-toolbar .input-group {
- max-width: 18rem;
+ width: 14rem;
}
.apps-toolbar .btn-outline-secondary {
diff --git a/src_assets/common/assets/web/public/assets/locale/en.json b/src_assets/common/assets/web/public/assets/locale/en.json
index f4eee2cdccf..a74d3d0a555 100644
--- a/src_assets/common/assets/web/public/assets/locale/en.json
+++ b/src_assets/common/assets/web/public/assets/locale/en.json
@@ -50,6 +50,8 @@
"covers_found": "Covers Found",
"cover_search_hint": "Search names should match IGDB naming conventions.",
"delete": "Delete",
+ "delete_confirm": "Are you sure you want to delete {name}?",
+ "delete_title": "Delete Application",
"detached_cmds": "Detached Commands",
"detached_cmds_add": "Add Detached Command",
"detached_cmds_desc": "A list of commands to be run in the background.",