-
-
-
-
-
-
-
-
-
{{ $t('_common.note') }} {{ $t('apps.cover_search_hint') }}
-
IGDB
-
-
-
-
-
-
-
- {{ $t('apps.loading') }}
-
-
-
-
-
-
![]()
-
-
-
-
-
-
-
-
-
-
{{ $t('apps.env_vars_about') }}
- {{ $t('apps.env_vars_desc') }}
+
+
-
-
- | {{ $t('apps.env_var_name') }} |
- |
-
-
- | SUNSHINE_APP_ID |
- {{ $t('apps.env_app_id') }} |
-
-
- | SUNSHINE_APP_NAME |
- {{ $t('apps.env_app_name') }} |
-
-
- | SUNSHINE_CLIENT_WIDTH |
- {{ $t('apps.env_client_width') }} |
-
-
- | SUNSHINE_CLIENT_HEIGHT |
- {{ $t('apps.env_client_height') }} |
-
-
- | SUNSHINE_CLIENT_FPS |
- {{ $t('apps.env_client_fps') }} |
-
-
- | SUNSHINE_CLIENT_HDR |
- {{ $t('apps.env_client_hdr') }} |
-
-
- | SUNSHINE_CLIENT_GCMAP |
- {{ $t('apps.env_client_gcmap') }} |
-
-
- | SUNSHINE_CLIENT_HOST_AUDIO |
- {{ $t('apps.env_client_host_audio') }} |
-
-
- | SUNSHINE_CLIENT_ENABLE_SOPS |
- {{ $t('apps.env_client_enable_sops') }} |
-
-
- | SUNSHINE_CLIENT_AUDIO_CONFIGURATION |
- {{ $t('apps.env_client_audio_config') }} |
-
-
-
{{ $t('apps.env_qres_example') }}
-
cmd /C <{{ $t('apps.env_qres_path') }}>\QRes.exe /X:%SUNSHINE_CLIENT_WIDTH% /Y:%SUNSHINE_CLIENT_HEIGHT% /R:%SUNSHINE_CLIENT_FPS%
-
-
{{ $t('apps.env_xrandr_example') }}
-
sh -c "xrandr --output HDMI-1 --mode \"${SUNSHINE_CLIENT_WIDTH}x${SUNSHINE_CLIENT_HEIGHT}\" --rate ${SUNSHINE_CLIENT_FPS}"
-
-
{{ $t('apps.env_displayplacer_example') }}
-
sh -c "displayplacer "id:<screenId> res:${SUNSHINE_CLIENT_WIDTH}x${SUNSHINE_CLIENT_HEIGHT} hz:${SUNSHINE_CLIENT_FPS} scaling:on origin:(0,0) degree:0""
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+ {{ deleteTarget.name }}
+
+
+
+
+
@@ -569,7 +613,6 @@
data() {
return {
apps: [],
- showEditForm: false,
editForm: null,
detachedCmd: "",
coverSearching: false,
@@ -589,6 +632,7 @@
fileBrowserTypedPath: "",
searchQuery: "",
sortMode: "default",
+ deleteTarget: null,
version: null,
githubVersion: null,
};
@@ -646,14 +690,21 @@
? `${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 +734,7 @@
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 +757,34 @@
if (this.editForm["exit-timeout"] === undefined) {
this.editForm["exit-timeout"] = 5;
}
- this.showEditForm = true;
+ this.openEditModal();
},
- 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();
+ 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 +809,8 @@
this.coverCandidates = [];
this.coverSearchQuery = "";
+ this.showStacked(this.$refs.coverFinderModal);
+
// Perform initial search with app name
this.performCoverSearch();
},
@@ -844,7 +908,7 @@
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 +1008,32 @@
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 a8efdffdf..b7cb50234 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 f4eee2cdc..a74d3d0a5 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.",