diff --git a/html/src/app.js b/html/src/app.js index 05f8f1aa..7f95337b 100644 --- a/html/src/app.js +++ b/html/src/app.js @@ -1805,7 +1805,7 @@ speechSynthesis.getVoices(); /* params: { - worldId: string + id: string } */ API.saveWorld = function (params) { @@ -1822,6 +1822,44 @@ speechSynthesis.getVoices(); }); }; + /* + params: { + worldId: string + } + */ + API.publishWorld = function (params) { + return this.call(`worlds/${params.worldId}/publish`, { + method: 'PUT', + params + }).then((json) => { + var args = { + json, + params + }; + this.$emit('WORLD:SAVE', args); + return args; + }); + }; + + /* + params: { + worldId: string + } + */ + API.unpublishWorld = function (params) { + return this.call(`worlds/${params.worldId}/publish`, { + method: 'DELETE', + params + }).then((json) => { + var args = { + json, + params + }; + this.$emit('WORLD:SAVE', args); + return args; + }); + }; + /* params: { worldId: string, @@ -10253,6 +10291,88 @@ speechSynthesis.getVoices(); }); }; + $app.methods.promptChangeWorldCapacity = function (world) { + this.$prompt('Enter world capacity, Max: 40', 'Change Capacity', { + distinguishCancelAndClose: true, + confirmButtonText: 'OK', + cancelButtonText: 'Cancel', + inputValue: world.ref.capacity, + inputPattern: /\d+$/, + inputErrorMessage: 'Valid number is required', + callback: (action, instance) => { + if ( + action === 'confirm' && + instance.inputValue !== world.ref.capacity + ) { + API.saveWorld({ + id: world.id, + capacity: instance.inputValue + }).then((args) => { + this.$message({ + message: 'World capacity changed', + type: 'success' + }); + return args; + }); + } + } + }); + }; + + $app.methods.promptChangeWorldYouTubePreview = function (world) { + this.$prompt( + 'Enter world YouTube preview, WARNING: once a preview is added it cannot be removed', + 'Change YouTube Preview', + { + distinguishCancelAndClose: true, + confirmButtonText: 'OK', + cancelButtonText: 'Cancel', + inputValue: world.ref.previewYoutubeId, + inputErrorMessage: 'Valid YouTube URL is required', + callback: (action, instance) => { + if ( + action === 'confirm' && + instance.inputValue !== world.ref.previewYoutubeId + ) { + if (instance.inputValue.length > 11) { + try { + var url = new URL(instance.inputValue); + var id1 = url.pathname; + var id2 = url.searchParams.get('v'); + if (id1 && id1.length === 12) { + instance.inputValue = id1.substring(1, 12); + } + if (id2 && id2.length === 11) { + instance.inputValue = id2; + } + } catch { + this.$message({ + message: 'Invalid YouTube URL', + type: 'error' + }); + return; + } + } + if ( + instance.inputValue !== world.ref.previewYoutubeId + ) { + API.saveWorld({ + id: world.id, + previewYoutubeId: instance.inputValue + }).then((args) => { + this.$message({ + message: 'World YouTube preview changed', + type: 'success' + }); + return args; + }); + } + } + } + } + ); + }; + $app.methods.promptMaxTableSizeDialog = function () { this.$prompt('Enter a number', 'Max Table Size', { distinguishCancelAndClose: true, @@ -11462,6 +11582,15 @@ speechSynthesis.getVoices(); case 'Change Description': this.promptChangeWorldDescription(D); break; + case 'Change Capacity': + this.promptChangeWorldCapacity(D); + break; + case 'Change YouTube Preview': + this.promptChangeWorldYouTubePreview(D); + break; + case 'Change Tags': + this.showSetWorldTagsDialog(); + break; case 'Download Unity Package': this.openExternalLink(this.worldDialog.ref.unityPackageUrl); break; @@ -11502,6 +11631,28 @@ speechSynthesis.getVoices(); return args; }); break; + case 'Publish': + API.publishWorld({ + worldId: D.id + }).then((args) => { + this.$message({ + message: 'World has been published', + type: 'success' + }); + return args; + }); + break; + case 'Unpublish': + API.unpublishWorld({ + worldId: D.id + }).then((args) => { + this.$message({ + message: 'World has been unpublished', + type: 'success' + }); + return args; + }); + break; case 'Delete': API.deleteWorld({ worldId: D.id @@ -12343,6 +12494,56 @@ speechSynthesis.getVoices(); D.visible = true; }; + // App: Set World Tags Dialog + + $app.data.setWorldTagsDialog = { + visible: false, + tags: [], + debugAllowed: false + }; + + $app.methods.showSetWorldTagsDialog = function () { + this.$nextTick(() => adjustDialogZ(this.$refs.setWorldTagsDialog.$el)); + var D = this.setWorldTagsDialog; + D.visible = true; + var oldTags = this.worldDialog.ref.tags; + var tags = []; + oldTags.forEach((tag) => { + if (tag.includes('author_tag_')) { + tags.unshift(tag.substring(11)); + } + if (tag === 'debug_allowed') { + D.debugAllowed = true; + } + }); + D.tags = tags.toString(); + }; + + $app.methods.saveSetWorldTagsDialog = function () { + var D = this.setWorldTagsDialog; + var oldTags = D.tags.split(',');; + var tags = []; + oldTags.forEach((tag) => { + if (tag) { + tags.unshift(`author_tag_${tag}`); + } + }); + if (D.debugAllowed) { + tags.unshift('debug_allowed'); + } + API.saveWorld({ + id: $app.worldDialog.id, + tags + }).then((args) => { + this.$message({ + message: 'Tags updated', + type: 'success' + }); + D.visible = false; + return args; + }); + }; + // App: Notification position $app.data.notificationPositionDialog = { diff --git a/html/src/index.pug b/html/src/index.pug index e0a4eec4..e0b85e59 100644 --- a/html/src/index.pug +++ b/html/src/index.pug @@ -1398,9 +1398,14 @@ html template(v-else) el-dropdown-item(icon="el-icon-edit" command="Rename") Rename el-dropdown-item(icon="el-icon-edit" command="Change Description") Change Description + el-dropdown-item(icon="el-icon-edit" command="Change Capacity") Change Capacity + el-dropdown-item(icon="el-icon-edit" command="Change YouTube Preview") Change YouTube Preview + el-dropdown-item(icon="el-icon-edit" command="Change Tags") Change Tags el-dropdown-item(icon="el-icon-picture-outline" command="Change Image") Change Image el-dropdown-item(v-if="worldDialog.ref.unityPackageUrl" icon="el-icon-download" command="Download Unity Package") Download Unity Package - el-dropdown-item(icon="el-icon-delete" command="Delete" style="color:#F56C6C" divided) Delete + el-dropdown-item(v-if="worldDialog.ref.tags.includes('system_approved') || worldDialog.ref.tags.includes('system_labs')" icon="el-icon-view" command="Unpublish" divided) Unpublish From Labs + el-dropdown-item(v-else icon="el-icon-view" command="Publish" divided) Publish To Labs + el-dropdown-item(icon="el-icon-delete" command="Delete" style="color:#F56C6C") Delete el-tabs el-tab-pane(label="Instances") div. @@ -1439,12 +1444,17 @@ html timer(:epoch="user.$location_at") el-tab-pane(label="Info") .x-friend-list(style="max-height:none") - .x-friend-item(style="width:100%;cursor:default") - .detail - span.name World ID - span.extra {{ worldDialog.id }} - el-tooltip(placement="top" content="Copy to clipboard" :disabled="hideTooltips") - el-button(@click="copyWorld(worldDialog.id)" size="mini" icon="el-icon-s-order" style="margin-left:5px" circle) + div(style="width:100%;display:flex") + .x-friend-item(style="width:350px;cursor:default") + .detail + span.name World ID + span.extra {{ worldDialog.id }} + el-tooltip(placement="top" content="Copy to clipboard" :disabled="hideTooltips") + el-button(@click="copyWorld(worldDialog.id)" size="mini" icon="el-icon-s-order" style="margin-left:5px" circle) + .x-friend-item(v-if="worldDialog.ref.previewYoutubeId" style="width:350px" @click="openExternalLink(`https://www.youtube.com/watch?v=${worldDialog.ref.previewYoutubeId}`)") + .detail + span.name YouTube Preview + span.extra https://www.youtube.com/watch?v={{ worldDialog.ref.previewYoutubeId }} .x-friend-item(style="cursor:default") .detail span.name Players @@ -1817,6 +1827,17 @@ html div(style="display:flex") el-button(size="small" @click="openExternalLink('https://rapidapi.com/blog/how-to-get-youtube-api-key/')") Guide el-button(type="primary" size="small" @click="testYouTubeApiKey" style="margin-left:auto") Save + + //- dialog: Set World Tags + el-dialog.x-dialog(ref="setWorldTagsDialog" :visible.sync="setWorldTagsDialog.visible" title="Set World Tags" width="400px") + el-checkbox(v-model="setWorldTagsDialog.debugAllowed") Enable world debugging for others + div(style='font-size:12px;margin-top:10px') + | Enter tags comma separated #[br] + el-input(type="textarea" v-model="setWorldTagsDialog.tags" size="mini" show-word-limit :autosize="{ minRows:2, maxRows:5 }" placeholder="" style="margin-top:10px") + template(#footer) + div(style="display:flex") + el-button(size="small" @click="setWorldTagsDialog.visible = false") Cancel + el-button(type="primary" size="small" @click="saveSetWorldTagsDialog") Save //- dialog: Cache Download el-dialog.x-dialog(ref="downloadDialog" :visible.sync="downloadDialog.visible" title="Download History" width="770px")