mirror of
https://github.com/MrUnknownDE/VRCX.git
synced 2026-04-19 06:43:51 +02:00
replace ElMessageBox(alert, confirm) with alert dialog
This commit is contained in:
78
package-lock.json
generated
78
package-lock.json
generated
@@ -21,12 +21,12 @@
|
|||||||
"@fontsource-variable/noto-sans-tc": "^5.2.9",
|
"@fontsource-variable/noto-sans-tc": "^5.2.9",
|
||||||
"@kamiya4047/eslint-plugin-pretty-import": "^0.1.6",
|
"@kamiya4047/eslint-plugin-pretty-import": "^0.1.6",
|
||||||
"@sentry/vite-plugin": "^4.6.1",
|
"@sentry/vite-plugin": "^4.6.1",
|
||||||
"@sentry/vue": "^10.32.1",
|
"@sentry/vue": "^10.33.0",
|
||||||
"@tailwindcss/vite": "^4.1.18",
|
"@tailwindcss/vite": "^4.1.18",
|
||||||
"@tanstack/vue-table": "^8.21.3",
|
"@tanstack/vue-table": "^8.21.3",
|
||||||
"@tanstack/vue-virtual": "^3.13.18",
|
"@tanstack/vue-virtual": "^3.13.18",
|
||||||
"@types/jest": "^30.0.0",
|
"@types/jest": "^30.0.0",
|
||||||
"@types/node": "^25.0.6",
|
"@types/node": "^25.0.7",
|
||||||
"@vee-validate/zod": "^4.15.1",
|
"@vee-validate/zod": "^4.15.1",
|
||||||
"@vitejs/plugin-vue": "^6.0.3",
|
"@vitejs/plugin-vue": "^6.0.3",
|
||||||
"@vitejs/plugin-vue-jsx": "^5.1.3",
|
"@vitejs/plugin-vue-jsx": "^5.1.3",
|
||||||
@@ -4372,54 +4372,54 @@
|
|||||||
]
|
]
|
||||||
},
|
},
|
||||||
"node_modules/@sentry-internal/browser-utils": {
|
"node_modules/@sentry-internal/browser-utils": {
|
||||||
"version": "10.32.1",
|
"version": "10.33.0",
|
||||||
"resolved": "https://registry.npmjs.org/@sentry-internal/browser-utils/-/browser-utils-10.32.1.tgz",
|
"resolved": "https://registry.npmjs.org/@sentry-internal/browser-utils/-/browser-utils-10.33.0.tgz",
|
||||||
"integrity": "sha512-sjLLep1es3rTkbtAdTtdpc/a6g7v7bK5YJiZJsUigoJ4NTiFeMI5uIDCxbH/tjJ1q23YE1LzVn7T96I+qBRjHA==",
|
"integrity": "sha512-nDJFHAfiFifBfJB0OF6DV6BIsIV5uah4lDsV4UBAgPBf+YAHclO10y1gi2U/JMh58c+s4lXi9p+PI1TFXZ0c6w==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@sentry/core": "10.32.1"
|
"@sentry/core": "10.33.0"
|
||||||
},
|
},
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=18"
|
"node": ">=18"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@sentry-internal/feedback": {
|
"node_modules/@sentry-internal/feedback": {
|
||||||
"version": "10.32.1",
|
"version": "10.33.0",
|
||||||
"resolved": "https://registry.npmjs.org/@sentry-internal/feedback/-/feedback-10.32.1.tgz",
|
"resolved": "https://registry.npmjs.org/@sentry-internal/feedback/-/feedback-10.33.0.tgz",
|
||||||
"integrity": "sha512-O24G8jxbfBY1RE/v2qFikPJISVMOrd/zk8FKyl+oUVYdOxU2Ucjk2cR3EQruBFlc7irnL6rT3GPfRZ/kBgLkmQ==",
|
"integrity": "sha512-sN/VLWtEf0BeV6w6wldIpTxUQxNVc9o9tjLRQa8je1ZV2FCgXA124Iff/zsowsz82dLqtg7qp6GA5zYXVq+JMA==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@sentry/core": "10.32.1"
|
"@sentry/core": "10.33.0"
|
||||||
},
|
},
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=18"
|
"node": ">=18"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@sentry-internal/replay": {
|
"node_modules/@sentry-internal/replay": {
|
||||||
"version": "10.32.1",
|
"version": "10.33.0",
|
||||||
"resolved": "https://registry.npmjs.org/@sentry-internal/replay/-/replay-10.32.1.tgz",
|
"resolved": "https://registry.npmjs.org/@sentry-internal/replay/-/replay-10.33.0.tgz",
|
||||||
"integrity": "sha512-KKmLUgIaLRM0VjrMA1ByQTawZyRDYSkG2evvEOVpEtR9F0sumidAQdi7UY71QEKE1RYe/Jcp/3WoaqsMh8tbnQ==",
|
"integrity": "sha512-UOU9PYxuXnPop3HoQ3l4Q7SZUXJC3Vmfm0Adgad8U03UcrThWIHYc5CxECSrVzfDFNOT7w9o7HQgRAgWxBPMXg==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@sentry-internal/browser-utils": "10.32.1",
|
"@sentry-internal/browser-utils": "10.33.0",
|
||||||
"@sentry/core": "10.32.1"
|
"@sentry/core": "10.33.0"
|
||||||
},
|
},
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=18"
|
"node": ">=18"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@sentry-internal/replay-canvas": {
|
"node_modules/@sentry-internal/replay-canvas": {
|
||||||
"version": "10.32.1",
|
"version": "10.33.0",
|
||||||
"resolved": "https://registry.npmjs.org/@sentry-internal/replay-canvas/-/replay-canvas-10.32.1.tgz",
|
"resolved": "https://registry.npmjs.org/@sentry-internal/replay-canvas/-/replay-canvas-10.33.0.tgz",
|
||||||
"integrity": "sha512-/XGTzWNWVc+B691fIVekV2KeoHFEDA5KftrLFAhEAW7uWOwk/xy3aQX4TYM0LcPm2PBKvoumlAD+Sd/aXk63oA==",
|
"integrity": "sha512-MTmP6uoAVzw4CCPeqCgCLsRSiOfGLxgyMFjGTCW3E7t62MJ9S0H5sLsQ34sHxXUa1gFU9UNAjEvRRpZ0JvWrPw==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@sentry-internal/replay": "10.32.1",
|
"@sentry-internal/replay": "10.33.0",
|
||||||
"@sentry/core": "10.32.1"
|
"@sentry/core": "10.33.0"
|
||||||
},
|
},
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=18"
|
"node": ">=18"
|
||||||
@@ -4436,17 +4436,17 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@sentry/browser": {
|
"node_modules/@sentry/browser": {
|
||||||
"version": "10.32.1",
|
"version": "10.33.0",
|
||||||
"resolved": "https://registry.npmjs.org/@sentry/browser/-/browser-10.32.1.tgz",
|
"resolved": "https://registry.npmjs.org/@sentry/browser/-/browser-10.33.0.tgz",
|
||||||
"integrity": "sha512-NPNCXTZ05ZGTFyJdKNqjykpFm+urem0ebosILQiw3C4BxNVNGH4vfYZexyl6prRhmg91oB6GjVNiVDuJiap1gg==",
|
"integrity": "sha512-iWiPjik9zetM84jKfk01UveW1J0+X7w8XmJ8+IrhTyNDBVUWCRJWD8FrksiN1dRSg5mFWgfMRzKMz27hAScRwg==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@sentry-internal/browser-utils": "10.32.1",
|
"@sentry-internal/browser-utils": "10.33.0",
|
||||||
"@sentry-internal/feedback": "10.32.1",
|
"@sentry-internal/feedback": "10.33.0",
|
||||||
"@sentry-internal/replay": "10.32.1",
|
"@sentry-internal/replay": "10.33.0",
|
||||||
"@sentry-internal/replay-canvas": "10.32.1",
|
"@sentry-internal/replay-canvas": "10.33.0",
|
||||||
"@sentry/core": "10.32.1"
|
"@sentry/core": "10.33.0"
|
||||||
},
|
},
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=18"
|
"node": ">=18"
|
||||||
@@ -4647,9 +4647,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@sentry/core": {
|
"node_modules/@sentry/core": {
|
||||||
"version": "10.32.1",
|
"version": "10.33.0",
|
||||||
"resolved": "https://registry.npmjs.org/@sentry/core/-/core-10.32.1.tgz",
|
"resolved": "https://registry.npmjs.org/@sentry/core/-/core-10.33.0.tgz",
|
||||||
"integrity": "sha512-PH2ldpSJlhqsMj2vCTyU0BI2Fx1oIDhm7Izo5xFALvjVCS0gmlqHt1udu6YlKn8BtpGH6bGzssvv5APrk+OdPQ==",
|
"integrity": "sha512-ehH1VSUclIHZKEZVdv+klofsFIh8FFzqA6AAV23RtLepptzA8wqQzUGraEuSN25sYcNmYJ0jti5U0Ys+WZv5Dw==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"engines": {
|
"engines": {
|
||||||
@@ -4671,14 +4671,14 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@sentry/vue": {
|
"node_modules/@sentry/vue": {
|
||||||
"version": "10.32.1",
|
"version": "10.33.0",
|
||||||
"resolved": "https://registry.npmjs.org/@sentry/vue/-/vue-10.32.1.tgz",
|
"resolved": "https://registry.npmjs.org/@sentry/vue/-/vue-10.33.0.tgz",
|
||||||
"integrity": "sha512-3KVvjkBw18FgbYar87CevQNPRATtBrzi+xIRZf6uJG2Wnd9w+WH3+CQsjKwDvQiYyChiW4CYuFL2DuQ/VqOxfQ==",
|
"integrity": "sha512-CUtoBl62DG8mkoYfgpkw2WdB187XA2CfPj7OJdIzt3lavhpSAPmsY4jUarK2RUJvcowr5zYbEfv50Y0tsQxuGA==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@sentry/browser": "10.32.1",
|
"@sentry/browser": "10.33.0",
|
||||||
"@sentry/core": "10.32.1"
|
"@sentry/core": "10.33.0"
|
||||||
},
|
},
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=18"
|
"node": ">=18"
|
||||||
@@ -5313,9 +5313,9 @@
|
|||||||
"license": "MIT"
|
"license": "MIT"
|
||||||
},
|
},
|
||||||
"node_modules/@types/node": {
|
"node_modules/@types/node": {
|
||||||
"version": "25.0.6",
|
"version": "25.0.7",
|
||||||
"resolved": "https://registry.npmjs.org/@types/node/-/node-25.0.6.tgz",
|
"resolved": "https://registry.npmjs.org/@types/node/-/node-25.0.7.tgz",
|
||||||
"integrity": "sha512-NNu0sjyNxpoiW3YuVFfNz7mxSQ+S4X2G28uqg2s+CzoqoQjLPsWSbsFFyztIAqt2vb8kfEAsJNepMGPTxFDx3Q==",
|
"integrity": "sha512-C/er7DlIZgRJO7WtTdYovjIFzGsz0I95UlMyR9anTb4aCpBSRWe5Jc1/RvLKUfzmOxHPGjSE5+63HgLtndxU4w==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
|
|||||||
@@ -42,12 +42,12 @@
|
|||||||
"@fontsource-variable/noto-sans-tc": "^5.2.9",
|
"@fontsource-variable/noto-sans-tc": "^5.2.9",
|
||||||
"@kamiya4047/eslint-plugin-pretty-import": "^0.1.6",
|
"@kamiya4047/eslint-plugin-pretty-import": "^0.1.6",
|
||||||
"@sentry/vite-plugin": "^4.6.1",
|
"@sentry/vite-plugin": "^4.6.1",
|
||||||
"@sentry/vue": "^10.32.1",
|
"@sentry/vue": "^10.33.0",
|
||||||
"@tailwindcss/vite": "^4.1.18",
|
"@tailwindcss/vite": "^4.1.18",
|
||||||
"@tanstack/vue-table": "^8.21.3",
|
"@tanstack/vue-table": "^8.21.3",
|
||||||
"@tanstack/vue-virtual": "^3.13.18",
|
"@tanstack/vue-virtual": "^3.13.18",
|
||||||
"@types/jest": "^30.0.0",
|
"@types/jest": "^30.0.0",
|
||||||
"@types/node": "^25.0.6",
|
"@types/node": "^25.0.7",
|
||||||
"@vee-validate/zod": "^4.15.1",
|
"@vee-validate/zod": "^4.15.1",
|
||||||
"@vitejs/plugin-vue": "^6.0.3",
|
"@vitejs/plugin-vue": "^6.0.3",
|
||||||
"@vitejs/plugin-vue-jsx": "^5.1.3",
|
"@vitejs/plugin-vue-jsx": "^5.1.3",
|
||||||
|
|||||||
@@ -14,6 +14,8 @@
|
|||||||
<RouterView></RouterView>
|
<RouterView></RouterView>
|
||||||
<Toaster position="top-center"></Toaster>
|
<Toaster position="top-center"></Toaster>
|
||||||
|
|
||||||
|
<AlertDialogModal></AlertDialogModal>
|
||||||
|
|
||||||
<VRCXUpdateDialog></VRCXUpdateDialog>
|
<VRCXUpdateDialog></VRCXUpdateDialog>
|
||||||
</div>
|
</div>
|
||||||
</el-config-provider>
|
</el-config-provider>
|
||||||
@@ -29,6 +31,7 @@
|
|||||||
import { createGlobalStores } from './stores';
|
import { createGlobalStores } from './stores';
|
||||||
import { initNoty } from './plugin/noty';
|
import { initNoty } from './plugin/noty';
|
||||||
|
|
||||||
|
import AlertDialogModal from './components/ui/alert-dialog/AlertDialogModal.vue';
|
||||||
import MacOSTitleBar from './components/MacOSTitleBar.vue';
|
import MacOSTitleBar from './components/MacOSTitleBar.vue';
|
||||||
import VRCXUpdateDialog from './components/dialogs/VRCXUpdateDialog.vue';
|
import VRCXUpdateDialog from './components/dialogs/VRCXUpdateDialog.vue';
|
||||||
|
|
||||||
|
|||||||
@@ -67,11 +67,10 @@
|
|||||||
import { reactive, watch } from 'vue';
|
import { reactive, watch } from 'vue';
|
||||||
import { Button } from '@/components/ui/button';
|
import { Button } from '@/components/ui/button';
|
||||||
import { CaretBottom } from '@element-plus/icons-vue';
|
import { CaretBottom } from '@element-plus/icons-vue';
|
||||||
import { ElMessageBox } from 'element-plus';
|
|
||||||
import { toast } from 'vue-sonner';
|
import { toast } from 'vue-sonner';
|
||||||
import { useI18n } from 'vue-i18n';
|
import { useI18n } from 'vue-i18n';
|
||||||
|
|
||||||
import { useGroupStore, useInstanceStore, useLocationStore, useUserStore } from '../stores';
|
import { useGroupStore, useInstanceStore, useLocationStore, useModalStore, useUserStore } from '../stores';
|
||||||
import { formatDateFilter, hasGroupPermission } from '../shared/utils';
|
import { formatDateFilter, hasGroupPermission } from '../shared/utils';
|
||||||
import { miscRequest } from '../api';
|
import { miscRequest } from '../api';
|
||||||
|
|
||||||
@@ -81,6 +80,7 @@
|
|||||||
const userStore = useUserStore();
|
const userStore = useUserStore();
|
||||||
const groupStore = useGroupStore();
|
const groupStore = useGroupStore();
|
||||||
const instanceStore = useInstanceStore();
|
const instanceStore = useInstanceStore();
|
||||||
|
const modalStore = useModalStore();
|
||||||
|
|
||||||
const props = defineProps({
|
const props = defineProps({
|
||||||
location: String,
|
location: String,
|
||||||
@@ -126,13 +126,13 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
function closeInstance(location) {
|
function closeInstance(location) {
|
||||||
ElMessageBox.confirm('Continue? Close Instance, nobody will be able to join', 'Confirm', {
|
modalStore
|
||||||
confirmButtonText: 'Confirm',
|
.confirm({
|
||||||
cancelButtonText: 'Cancel',
|
description: 'Continue? Close Instance, nobody will be able to join',
|
||||||
type: 'warning'
|
title: 'Confirm'
|
||||||
})
|
})
|
||||||
.then(async (action) => {
|
.then(async ({ ok }) => {
|
||||||
if (action !== 'confirm') return;
|
if (!ok) return;
|
||||||
const args = await miscRequest.closeInstance({ location, hardClose: false });
|
const args = await miscRequest.closeInstance({ location, hardClose: false });
|
||||||
if (args.json) {
|
if (args.json) {
|
||||||
toast.success(t('message.instance.closed'));
|
toast.success(t('message.instance.closed'));
|
||||||
|
|||||||
@@ -246,8 +246,8 @@
|
|||||||
|
|
||||||
<script setup>
|
<script setup>
|
||||||
import { computed, defineAsyncComponent, onMounted, ref, watch } from 'vue';
|
import { computed, defineAsyncComponent, onMounted, ref, watch } from 'vue';
|
||||||
import { ElMessageBox, dayjs } from 'element-plus';
|
|
||||||
import { Button } from '@/components/ui/button';
|
import { Button } from '@/components/ui/button';
|
||||||
|
import { dayjs } from 'element-plus';
|
||||||
import { storeToRefs } from 'pinia';
|
import { storeToRefs } from 'pinia';
|
||||||
import { useI18n } from 'vue-i18n';
|
import { useI18n } from 'vue-i18n';
|
||||||
import { useRouter } from 'vue-router';
|
import { useRouter } from 'vue-router';
|
||||||
@@ -255,6 +255,7 @@
|
|||||||
import {
|
import {
|
||||||
useAppearanceSettingsStore,
|
useAppearanceSettingsStore,
|
||||||
useAuthStore,
|
useAuthStore,
|
||||||
|
useModalStore,
|
||||||
useSearchStore,
|
useSearchStore,
|
||||||
useUiStore,
|
useUiStore,
|
||||||
useVRCXUpdaterStore
|
useVRCXUpdaterStore
|
||||||
@@ -269,6 +270,7 @@
|
|||||||
|
|
||||||
const { t, locale } = useI18n();
|
const { t, locale } = useI18n();
|
||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
|
const modalStore = useModalStore();
|
||||||
|
|
||||||
const createDefaultNavLayout = () => [
|
const createDefaultNavLayout = () => [
|
||||||
{ type: 'item', key: 'feed' },
|
{ type: 'item', key: 'feed' },
|
||||||
@@ -559,12 +561,15 @@
|
|||||||
};
|
};
|
||||||
|
|
||||||
const handleCustomNavReset = () => {
|
const handleCustomNavReset = () => {
|
||||||
ElMessageBox.confirm(t('nav_menu.custom_nav.restore_default_confirm'), {
|
modalStore
|
||||||
type: 'warning',
|
.confirm({
|
||||||
confirmButtonText: t('nav_menu.custom_nav.restore_default'),
|
description: t('nav_menu.custom_nav.restore_default_confirm'),
|
||||||
cancelButtonText: t('nav_menu.custom_nav.cancel')
|
title: t('confirm.title'),
|
||||||
})
|
confirmText: t('nav_menu.custom_nav.restore_default'),
|
||||||
.then(async () => {
|
cancelText: t('nav_menu.custom_nav.cancel')
|
||||||
|
})
|
||||||
|
.then(async ({ ok }) => {
|
||||||
|
if (!ok) return;
|
||||||
const defaults = sanitizeLayout(createDefaultNavLayout());
|
const defaults = sanitizeLayout(createDefaultNavLayout());
|
||||||
navLayout.value = defaults;
|
navLayout.value = defaults;
|
||||||
await saveNavLayout(defaults);
|
await saveNavLayout(defaults);
|
||||||
|
|||||||
@@ -559,6 +559,7 @@
|
|||||||
useFavoriteStore,
|
useFavoriteStore,
|
||||||
useGalleryStore,
|
useGalleryStore,
|
||||||
useGameStore,
|
useGameStore,
|
||||||
|
useModalStore,
|
||||||
useUserStore
|
useUserStore
|
||||||
} from '../../../stores';
|
} from '../../../stores';
|
||||||
import {
|
import {
|
||||||
@@ -591,6 +592,7 @@
|
|||||||
const { deleteVRChatCache } = useGameStore();
|
const { deleteVRChatCache } = useGameStore();
|
||||||
const { showFullscreenImageDialog } = useGalleryStore();
|
const { showFullscreenImageDialog } = useGalleryStore();
|
||||||
const { isDarkMode } = storeToRefs(useAppearanceSettingsStore());
|
const { isDarkMode } = storeToRefs(useAppearanceSettingsStore());
|
||||||
|
const modalStore = useModalStore();
|
||||||
|
|
||||||
const { t } = useI18n();
|
const { t } = useI18n();
|
||||||
|
|
||||||
@@ -752,15 +754,13 @@
|
|||||||
showFavoriteDialog('avatar', D.id);
|
showFavoriteDialog('avatar', D.id);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
ElMessageBox.confirm(`Continue? ${command}`, 'Confirm', {
|
modalStore
|
||||||
confirmButtonText: 'Confirm',
|
.confirm({
|
||||||
cancelButtonText: 'Cancel',
|
title: 'Confirm',
|
||||||
type: 'info'
|
description: `Continue? ${command}`
|
||||||
})
|
})
|
||||||
.then((action) => {
|
.then(({ ok }) => {
|
||||||
if (action !== 'confirm') {
|
if (!ok) return;
|
||||||
return;
|
|
||||||
}
|
|
||||||
switch (command) {
|
switch (command) {
|
||||||
case 'Delete Favorite':
|
case 'Delete Favorite':
|
||||||
favoriteRequest.deleteFavorite({
|
favoriteRequest.deleteFavorite({
|
||||||
@@ -897,8 +897,7 @@
|
|||||||
});
|
});
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
})
|
});
|
||||||
.catch(() => {});
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1146,11 +1146,10 @@
|
|||||||
View,
|
View,
|
||||||
Warning
|
Warning
|
||||||
} from '@element-plus/icons-vue';
|
} from '@element-plus/icons-vue';
|
||||||
import { Card } from '@/components/ui/card';
|
|
||||||
import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from '@/components/ui/select';
|
import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from '@/components/ui/select';
|
||||||
import { computed, nextTick, reactive, ref, watch } from 'vue';
|
import { computed, nextTick, reactive, ref, watch } from 'vue';
|
||||||
import { Button } from '@/components/ui/button';
|
import { Button } from '@/components/ui/button';
|
||||||
import { ElMessageBox } from 'element-plus';
|
import { Card } from '@/components/ui/card';
|
||||||
import { InputGroupField } from '@/components/ui/input-group';
|
import { InputGroupField } from '@/components/ui/input-group';
|
||||||
import { RefreshCcw } from 'lucide-vue-next';
|
import { RefreshCcw } from 'lucide-vue-next';
|
||||||
import { Spinner } from '@/components/ui/spinner';
|
import { Spinner } from '@/components/ui/spinner';
|
||||||
@@ -1176,6 +1175,14 @@
|
|||||||
userImage,
|
userImage,
|
||||||
userStatusClass
|
userStatusClass
|
||||||
} from '../../../shared/utils';
|
} from '../../../shared/utils';
|
||||||
|
import {
|
||||||
|
useAppearanceSettingsStore,
|
||||||
|
useGalleryStore,
|
||||||
|
useGroupStore,
|
||||||
|
useLocationStore,
|
||||||
|
useModalStore,
|
||||||
|
useUserStore
|
||||||
|
} from '../../../stores';
|
||||||
import {
|
import {
|
||||||
DropdownMenu,
|
DropdownMenu,
|
||||||
DropdownMenuContent,
|
DropdownMenuContent,
|
||||||
@@ -1183,13 +1190,6 @@
|
|||||||
DropdownMenuSeparator,
|
DropdownMenuSeparator,
|
||||||
DropdownMenuTrigger
|
DropdownMenuTrigger
|
||||||
} from '../../ui/dropdown-menu';
|
} from '../../ui/dropdown-menu';
|
||||||
import {
|
|
||||||
useAppearanceSettingsStore,
|
|
||||||
useGalleryStore,
|
|
||||||
useGroupStore,
|
|
||||||
useLocationStore,
|
|
||||||
useUserStore
|
|
||||||
} from '../../../stores';
|
|
||||||
import { formatJsonVars, getNextDialogIndex } from '../../../shared/utils/base/ui';
|
import { formatJsonVars, getNextDialogIndex } from '../../../shared/utils/base/ui';
|
||||||
import { groupDialogFilterOptions, groupDialogSortingOptions } from '../../../shared/constants';
|
import { groupDialogFilterOptions, groupDialogSortingOptions } from '../../../shared/constants';
|
||||||
import { Badge } from '../../ui/badge';
|
import { Badge } from '../../ui/badge';
|
||||||
@@ -1203,6 +1203,8 @@
|
|||||||
|
|
||||||
const { t } = useI18n();
|
const { t } = useI18n();
|
||||||
|
|
||||||
|
const modalStore = useModalStore();
|
||||||
|
|
||||||
const { showUserDialog } = useUserStore();
|
const { showUserDialog } = useUserStore();
|
||||||
const { currentUser } = storeToRefs(useUserStore());
|
const { currentUser } = storeToRefs(useUserStore());
|
||||||
const { groupDialog, inviteGroupDialog } = storeToRefs(useGroupStore());
|
const { groupDialog, inviteGroupDialog } = storeToRefs(useGroupStore());
|
||||||
@@ -1469,43 +1471,42 @@
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
function confirmDeleteGroupPost(post) {
|
function confirmDeleteGroupPost(post) {
|
||||||
ElMessageBox.confirm('Are you sure you want to delete this post?', 'Confirm', {
|
modalStore
|
||||||
confirmButtonText: 'Confirm',
|
.confirm({
|
||||||
cancelButtonText: 'Cancel',
|
description: 'Are you sure you want to delete this post?',
|
||||||
type: 'info'
|
title: 'Confirm'
|
||||||
})
|
})
|
||||||
.then((action) => {
|
.then(({ ok }) => {
|
||||||
if (action === 'confirm') {
|
if (!ok) return;
|
||||||
groupRequest
|
groupRequest
|
||||||
.deleteGroupPost({
|
.deleteGroupPost({
|
||||||
groupId: post.groupId,
|
groupId: post.groupId,
|
||||||
postId: post.id
|
postId: post.id
|
||||||
})
|
})
|
||||||
.then((args) => {
|
.then((args) => {
|
||||||
const D = groupDialog.value;
|
const D = groupDialog.value;
|
||||||
if (D.id !== args.params.groupId) {
|
if (D.id !== args.params.groupId) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const postId = args.params.postId;
|
const postId = args.params.postId;
|
||||||
// remove existing post
|
// remove existing post
|
||||||
for (const item of D.posts) {
|
for (const item of D.posts) {
|
||||||
if (item.id === postId) {
|
if (item.id === postId) {
|
||||||
removeFromArray(D.posts, item);
|
removeFromArray(D.posts, item);
|
||||||
break;
|
break;
|
||||||
}
|
|
||||||
}
|
}
|
||||||
// remove/update announcement
|
}
|
||||||
if (postId === D.announcement.id) {
|
// remove/update announcement
|
||||||
if (D.posts.length > 0) {
|
if (postId === D.announcement.id) {
|
||||||
D.announcement = D.posts[0];
|
if (D.posts.length > 0) {
|
||||||
} else {
|
D.announcement = D.posts[0];
|
||||||
D.announcement = {};
|
} else {
|
||||||
}
|
D.announcement = {};
|
||||||
}
|
}
|
||||||
updateGroupPostSearch();
|
}
|
||||||
});
|
updateGroupPostSearch();
|
||||||
}
|
});
|
||||||
})
|
})
|
||||||
.catch(() => {});
|
.catch(() => {});
|
||||||
}
|
}
|
||||||
@@ -1571,46 +1572,44 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
function blockGroup(groupId) {
|
function blockGroup(groupId) {
|
||||||
ElMessageBox.confirm('Are you sure you want to block this group?', 'Confirm', {
|
modalStore
|
||||||
confirmButtonText: 'Confirm',
|
.confirm({
|
||||||
cancelButtonText: 'Cancel',
|
description: 'Are you sure you want to block this group?',
|
||||||
type: 'info'
|
title: 'Confirm'
|
||||||
})
|
})
|
||||||
.then((action) => {
|
.then(({ ok }) => {
|
||||||
if (action === 'confirm') {
|
if (!ok) return;
|
||||||
groupRequest
|
groupRequest
|
||||||
.blockGroup({
|
.blockGroup({
|
||||||
groupId
|
groupId
|
||||||
})
|
})
|
||||||
.then((args) => {
|
.then((args) => {
|
||||||
if (groupDialog.value.visible && groupDialog.value.id === args.params.groupId) {
|
if (groupDialog.value.visible && groupDialog.value.id === args.params.groupId) {
|
||||||
showGroupDialog(args.params.groupId);
|
showGroupDialog(args.params.groupId);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
|
||||||
})
|
})
|
||||||
.catch(() => {});
|
.catch(() => {});
|
||||||
}
|
}
|
||||||
|
|
||||||
function unblockGroup(groupId) {
|
function unblockGroup(groupId) {
|
||||||
ElMessageBox.confirm('Are you sure you want to unblock this group?', 'Confirm', {
|
modalStore
|
||||||
confirmButtonText: 'Confirm',
|
.confirm({
|
||||||
cancelButtonText: 'Cancel',
|
description: 'Are you sure you want to unblock this group?',
|
||||||
type: 'info'
|
title: 'Confirm'
|
||||||
})
|
})
|
||||||
.then((action) => {
|
.then(({ ok }) => {
|
||||||
if (action === 'confirm') {
|
if (!ok) return;
|
||||||
groupRequest
|
groupRequest
|
||||||
.unblockGroup({
|
.unblockGroup({
|
||||||
groupId,
|
groupId,
|
||||||
userId: currentUser.value.id
|
userId: currentUser.value.id
|
||||||
})
|
})
|
||||||
.then((args) => {
|
.then((args) => {
|
||||||
if (groupDialog.value.visible && groupDialog.value.id === args.params.groupId) {
|
if (groupDialog.value.visible && groupDialog.value.id === args.params.groupId) {
|
||||||
showGroupDialog(args.params.groupId);
|
showGroupDialog(args.params.groupId);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
|
||||||
})
|
})
|
||||||
.catch(() => {});
|
.catch(() => {});
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -87,12 +87,11 @@
|
|||||||
import { computed, ref } from 'vue';
|
import { computed, ref } from 'vue';
|
||||||
import { Button } from '@/components/ui/button';
|
import { Button } from '@/components/ui/button';
|
||||||
import { Check as CheckIcon } from 'lucide-vue-next';
|
import { Check as CheckIcon } from 'lucide-vue-next';
|
||||||
import { ElMessageBox } from 'element-plus';
|
|
||||||
import { storeToRefs } from 'pinia';
|
import { storeToRefs } from 'pinia';
|
||||||
import { toast } from 'vue-sonner';
|
import { toast } from 'vue-sonner';
|
||||||
import { useI18n } from 'vue-i18n';
|
import { useI18n } from 'vue-i18n';
|
||||||
|
|
||||||
import { useFriendStore, useGalleryStore, useInviteStore, useUserStore } from '../../../stores';
|
import { useFriendStore, useGalleryStore, useInviteStore, useModalStore, useUserStore } from '../../../stores';
|
||||||
import { parseLocation, userImage, userStatusClass } from '../../../shared/utils';
|
import { parseLocation, userImage, userStatusClass } from '../../../shared/utils';
|
||||||
import { instanceRequest, notificationRequest } from '../../../api';
|
import { instanceRequest, notificationRequest } from '../../../api';
|
||||||
import { VirtualCombobox } from '../../ui/virtual-combobox';
|
import { VirtualCombobox } from '../../ui/virtual-combobox';
|
||||||
@@ -104,6 +103,8 @@
|
|||||||
const { currentUser } = storeToRefs(useUserStore());
|
const { currentUser } = storeToRefs(useUserStore());
|
||||||
const { clearInviteImageUpload } = useGalleryStore();
|
const { clearInviteImageUpload } = useGalleryStore();
|
||||||
|
|
||||||
|
const modalStore = useModalStore();
|
||||||
|
|
||||||
const { t } = useI18n();
|
const { t } = useI18n();
|
||||||
const props = defineProps({
|
const props = defineProps({
|
||||||
inviteDialog: {
|
inviteDialog: {
|
||||||
@@ -233,14 +234,15 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
function sendInvite() {
|
function sendInvite() {
|
||||||
ElMessageBox.confirm('Continue? Invite', 'Confirm', {
|
modalStore
|
||||||
confirmButtonText: 'Confirm',
|
.confirm({
|
||||||
cancelButtonText: 'Cancel',
|
description: 'Continue? Invite',
|
||||||
type: 'info'
|
title: 'Confirm'
|
||||||
})
|
})
|
||||||
.then((action) => {
|
.then(({ ok }) => {
|
||||||
|
if (!ok) return;
|
||||||
const D = props.inviteDialog;
|
const D = props.inviteDialog;
|
||||||
if (action !== 'confirm' || D.loading === true) {
|
if (D.loading === true) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
D.loading = true;
|
D.loading = true;
|
||||||
@@ -275,7 +277,8 @@
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
inviteLoop();
|
inviteLoop();
|
||||||
})
|
});
|
||||||
.catch(() => {});
|
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
}) .catch(() => {});
|
||||||
|
|||||||
@@ -79,14 +79,13 @@
|
|||||||
import { computed, nextTick, ref, watch } from 'vue';
|
import { computed, nextTick, ref, watch } from 'vue';
|
||||||
import { Button } from '@/components/ui/button';
|
import { Button } from '@/components/ui/button';
|
||||||
import { Check as CheckIcon } from 'lucide-vue-next';
|
import { Check as CheckIcon } from 'lucide-vue-next';
|
||||||
import { ElMessageBox } from 'element-plus';
|
|
||||||
import { storeToRefs } from 'pinia';
|
import { storeToRefs } from 'pinia';
|
||||||
import { toast } from 'vue-sonner';
|
import { toast } from 'vue-sonner';
|
||||||
import { useI18n } from 'vue-i18n';
|
import { useI18n } from 'vue-i18n';
|
||||||
|
|
||||||
import { hasGroupPermission, userImage, userStatusClass } from '../../shared/utils';
|
import { hasGroupPermission, userImage, userStatusClass } from '../../shared/utils';
|
||||||
|
import { useFriendStore, useGroupStore, useModalStore } from '../../stores';
|
||||||
import { groupRequest, userRequest } from '../../api';
|
import { groupRequest, userRequest } from '../../api';
|
||||||
import { useFriendStore, useGroupStore } from '../../stores';
|
|
||||||
import { VirtualCombobox } from '../ui/virtual-combobox';
|
import { VirtualCombobox } from '../ui/virtual-combobox';
|
||||||
import { getNextDialogIndex } from '../../shared/utils/base/ui';
|
import { getNextDialogIndex } from '../../shared/utils/base/ui';
|
||||||
|
|
||||||
@@ -96,6 +95,7 @@
|
|||||||
const { currentUserGroups, inviteGroupDialog } = storeToRefs(useGroupStore());
|
const { currentUserGroups, inviteGroupDialog } = storeToRefs(useGroupStore());
|
||||||
const { applyGroup } = useGroupStore();
|
const { applyGroup } = useGroupStore();
|
||||||
const { t } = useI18n();
|
const { t } = useI18n();
|
||||||
|
const modalStore = useModalStore();
|
||||||
|
|
||||||
watch(
|
watch(
|
||||||
() => inviteGroupDialog.value.visible,
|
() => inviteGroupDialog.value.visible,
|
||||||
@@ -272,14 +272,15 @@
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
function sendGroupInvite() {
|
function sendGroupInvite() {
|
||||||
ElMessageBox.confirm('Continue? Invite User(s) To Group', 'Confirm', {
|
modalStore
|
||||||
confirmButtonText: 'Confirm',
|
.confirm({
|
||||||
cancelButtonText: 'Cancel',
|
description: 'Continue? Invite User(s) To Group',
|
||||||
type: 'info'
|
title: 'Confirm'
|
||||||
})
|
})
|
||||||
.then((action) => {
|
.then(({ ok }) => {
|
||||||
|
if (!ok) return;
|
||||||
const D = inviteGroupDialog.value;
|
const D = inviteGroupDialog.value;
|
||||||
if (action !== 'confirm' || D.loading === true) {
|
if (D.loading === true) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
D.loading = true;
|
D.loading = true;
|
||||||
|
|||||||
@@ -135,7 +135,6 @@
|
|||||||
import { Button } from '@/components/ui/button';
|
import { Button } from '@/components/ui/button';
|
||||||
import { ButtonGroup } from '@/components/ui/button-group';
|
import { ButtonGroup } from '@/components/ui/button-group';
|
||||||
import { Copy } from 'lucide-vue-next';
|
import { Copy } from 'lucide-vue-next';
|
||||||
import { ElMessageBox } from 'element-plus';
|
|
||||||
import { InputGroupField } from '@/components/ui/input-group';
|
import { InputGroupField } from '@/components/ui/input-group';
|
||||||
import { MoreHorizontal } from 'lucide-vue-next';
|
import { MoreHorizontal } from 'lucide-vue-next';
|
||||||
import { Warning } from '@element-plus/icons-vue';
|
import { Warning } from '@element-plus/icons-vue';
|
||||||
@@ -143,7 +142,14 @@
|
|||||||
import { toast } from 'vue-sonner';
|
import { toast } from 'vue-sonner';
|
||||||
import { useI18n } from 'vue-i18n';
|
import { useI18n } from 'vue-i18n';
|
||||||
|
|
||||||
import { useFriendStore, useGameStore, useInviteStore, useLaunchStore, useLocationStore } from '../../stores';
|
import {
|
||||||
|
useFriendStore,
|
||||||
|
useGameStore,
|
||||||
|
useInviteStore,
|
||||||
|
useLaunchStore,
|
||||||
|
useLocationStore,
|
||||||
|
useModalStore
|
||||||
|
} from '../../stores';
|
||||||
import { checkCanInvite, getLaunchURL, isRealInstance, parseLocation } from '../../shared/utils';
|
import { checkCanInvite, getLaunchURL, isRealInstance, parseLocation } from '../../shared/utils';
|
||||||
import { instanceRequest, worldRequest } from '../../api';
|
import { instanceRequest, worldRequest } from '../../api';
|
||||||
import { getNextDialogIndex } from '../../shared/utils/base/ui';
|
import { getNextDialogIndex } from '../../shared/utils/base/ui';
|
||||||
@@ -153,6 +159,8 @@
|
|||||||
|
|
||||||
const { t } = useI18n();
|
const { t } = useI18n();
|
||||||
|
|
||||||
|
const modalStore = useModalStore();
|
||||||
|
|
||||||
const { friends } = storeToRefs(useFriendStore());
|
const { friends } = storeToRefs(useFriendStore());
|
||||||
const { lastLocation } = storeToRefs(useLocationStore());
|
const { lastLocation } = storeToRefs(useLocationStore());
|
||||||
const { launchGame, tryOpenInstanceInVrc } = useLaunchStore();
|
const { launchGame, tryOpenInstanceInVrc } = useLaunchStore();
|
||||||
@@ -245,16 +253,17 @@
|
|||||||
}
|
}
|
||||||
function handleLaunchGame(location, shortName, desktop) {
|
function handleLaunchGame(location, shortName, desktop) {
|
||||||
if (isGameRunning.value) {
|
if (isGameRunning.value) {
|
||||||
ElMessageBox.confirm(t('dialog.launch.game_running_warning'), t('dialog.launch.header'), {
|
modalStore
|
||||||
confirmButtonText: t('dialog.launch.confirm_yes'),
|
.confirm({
|
||||||
cancelButtonText: t('dialog.launch.confirm_no'),
|
description: t('dialog.launch.game_running_warning'),
|
||||||
type: 'warning'
|
title: t('dialog.launch.header'),
|
||||||
})
|
confirmText: t('dialog.launch.confirm_yes'),
|
||||||
.then((action) => {
|
cancelText: t('dialog.launch.confirm_no')
|
||||||
if (action === 'confirm') {
|
})
|
||||||
launchGame(location, shortName, desktop);
|
.then(({ ok }) => {
|
||||||
isVisible.value = false;
|
if (!ok) return;
|
||||||
}
|
launchGame(location, shortName, desktop);
|
||||||
|
isVisible.value = false;
|
||||||
})
|
})
|
||||||
.catch(() => {});
|
.catch(() => {});
|
||||||
return;
|
return;
|
||||||
|
|||||||
@@ -29,7 +29,6 @@
|
|||||||
|
|
||||||
<script setup>
|
<script setup>
|
||||||
import { computed, nextTick, ref, watch } from 'vue';
|
import { computed, nextTick, ref, watch } from 'vue';
|
||||||
import { ElMessageBox } from 'element-plus';
|
|
||||||
import { InputGroupField } from '@/components/ui/input-group';
|
import { InputGroupField } from '@/components/ui/input-group';
|
||||||
import { storeToRefs } from 'pinia';
|
import { storeToRefs } from 'pinia';
|
||||||
import { useI18n } from 'vue-i18n';
|
import { useI18n } from 'vue-i18n';
|
||||||
@@ -41,7 +40,7 @@
|
|||||||
removeFromArray,
|
removeFromArray,
|
||||||
timeToText
|
timeToText
|
||||||
} from '../../../shared/utils';
|
} from '../../../shared/utils';
|
||||||
import { useInstanceStore, useSearchStore, useUiStore, useVrcxStore } from '../../../stores';
|
import { useInstanceStore, useModalStore, useSearchStore, useUiStore, useVrcxStore } from '../../../stores';
|
||||||
import { DataTableLayout } from '../../ui/data-table';
|
import { DataTableLayout } from '../../ui/data-table';
|
||||||
import { createColumns } from './previousInstancesGroupColumns.jsx';
|
import { createColumns } from './previousInstancesGroupColumns.jsx';
|
||||||
import { database } from '../../../service/database';
|
import { database } from '../../../service/database';
|
||||||
@@ -56,6 +55,8 @@
|
|||||||
const previousInstancesGroupDialogIndex = ref(2000);
|
const previousInstancesGroupDialogIndex = ref(2000);
|
||||||
const loading = ref(false);
|
const loading = ref(false);
|
||||||
|
|
||||||
|
const modalStore = useModalStore();
|
||||||
|
|
||||||
const vrcxStore = useVrcxStore();
|
const vrcxStore = useVrcxStore();
|
||||||
const rawRows = ref([]);
|
const rawRows = ref([]);
|
||||||
const search = ref('');
|
const search = ref('');
|
||||||
@@ -169,15 +170,14 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
function deleteGameLogGroupInstancePrompt(row) {
|
function deleteGameLogGroupInstancePrompt(row) {
|
||||||
ElMessageBox.confirm('Continue? Delete GameLog Instance', 'Confirm', {
|
modalStore
|
||||||
confirmButtonText: 'Confirm',
|
.confirm({
|
||||||
cancelButtonText: 'Cancel',
|
description: 'Continue? Delete GameLog Instance',
|
||||||
type: 'info'
|
title: 'Confirm'
|
||||||
})
|
})
|
||||||
.then((action) => {
|
.then(({ ok }) => {
|
||||||
if (action === 'confirm') {
|
if (!ok) return;
|
||||||
deleteGameLogGroupInstance(row);
|
deleteGameLogGroupInstance(row);
|
||||||
}
|
|
||||||
})
|
})
|
||||||
.catch(() => {});
|
.catch(() => {});
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -30,11 +30,18 @@
|
|||||||
|
|
||||||
<script setup>
|
<script setup>
|
||||||
import { computed, nextTick, ref, watch } from 'vue';
|
import { computed, nextTick, ref, watch } from 'vue';
|
||||||
import { ElMessageBox } from 'element-plus';
|
|
||||||
import { InputGroupField } from '@/components/ui/input-group';
|
import { InputGroupField } from '@/components/ui/input-group';
|
||||||
import { storeToRefs } from 'pinia';
|
import { storeToRefs } from 'pinia';
|
||||||
import { useI18n } from 'vue-i18n';
|
import { useI18n } from 'vue-i18n';
|
||||||
|
|
||||||
|
import {
|
||||||
|
useInstanceStore,
|
||||||
|
useModalStore,
|
||||||
|
useSearchStore,
|
||||||
|
useUiStore,
|
||||||
|
useUserStore,
|
||||||
|
useVrcxStore
|
||||||
|
} from '../../../stores';
|
||||||
import {
|
import {
|
||||||
compareByCreatedAt,
|
compareByCreatedAt,
|
||||||
localeIncludes,
|
localeIncludes,
|
||||||
@@ -42,7 +49,6 @@
|
|||||||
removeFromArray,
|
removeFromArray,
|
||||||
timeToText
|
timeToText
|
||||||
} from '../../../shared/utils';
|
} from '../../../shared/utils';
|
||||||
import { useInstanceStore, useSearchStore, useUiStore, useUserStore, useVrcxStore } from '../../../stores';
|
|
||||||
import { DataTableLayout } from '../../ui/data-table';
|
import { DataTableLayout } from '../../ui/data-table';
|
||||||
import { createColumns } from './previousInstancesWorldColumns.jsx';
|
import { createColumns } from './previousInstancesWorldColumns.jsx';
|
||||||
import { database } from '../../../service/database';
|
import { database } from '../../../service/database';
|
||||||
@@ -51,6 +57,8 @@
|
|||||||
|
|
||||||
const { t } = useI18n();
|
const { t } = useI18n();
|
||||||
|
|
||||||
|
const modalStore = useModalStore();
|
||||||
|
|
||||||
const props = defineProps({
|
const props = defineProps({
|
||||||
previousInstancesWorldDialog: {
|
previousInstancesWorldDialog: {
|
||||||
type: Object,
|
type: Object,
|
||||||
@@ -164,15 +172,14 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
function deleteGameLogWorldInstancePrompt(row) {
|
function deleteGameLogWorldInstancePrompt(row) {
|
||||||
ElMessageBox.confirm('Continue? Delete GameLog Instance', 'Confirm', {
|
modalStore
|
||||||
confirmButtonText: 'Confirm',
|
.confirm({
|
||||||
cancelButtonText: 'Cancel',
|
description: 'Continue? Delete GameLog Instance',
|
||||||
type: 'info'
|
title: 'Confirm'
|
||||||
})
|
})
|
||||||
.then((action) => {
|
.then(({ ok }) => {
|
||||||
if (action === 'confirm') {
|
if (!ok) return;
|
||||||
deleteGameLogWorldInstance(row);
|
deleteGameLogWorldInstance(row);
|
||||||
}
|
|
||||||
})
|
})
|
||||||
.catch(() => {});
|
.catch(() => {});
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -30,11 +30,18 @@
|
|||||||
|
|
||||||
<script setup>
|
<script setup>
|
||||||
import { computed, nextTick, ref, watch } from 'vue';
|
import { computed, nextTick, ref, watch } from 'vue';
|
||||||
import { ElMessageBox } from 'element-plus';
|
|
||||||
import { InputGroupField } from '@/components/ui/input-group';
|
import { InputGroupField } from '@/components/ui/input-group';
|
||||||
import { storeToRefs } from 'pinia';
|
import { storeToRefs } from 'pinia';
|
||||||
import { useI18n } from 'vue-i18n';
|
import { useI18n } from 'vue-i18n';
|
||||||
|
|
||||||
|
import {
|
||||||
|
useInstanceStore,
|
||||||
|
useLaunchStore,
|
||||||
|
useModalStore,
|
||||||
|
useSearchStore,
|
||||||
|
useUiStore,
|
||||||
|
useVrcxStore
|
||||||
|
} from '../../../stores';
|
||||||
import {
|
import {
|
||||||
compareByCreatedAt,
|
compareByCreatedAt,
|
||||||
localeIncludes,
|
localeIncludes,
|
||||||
@@ -42,7 +49,6 @@
|
|||||||
removeFromArray,
|
removeFromArray,
|
||||||
timeToText
|
timeToText
|
||||||
} from '../../../shared/utils';
|
} from '../../../shared/utils';
|
||||||
import { useInstanceStore, useLaunchStore, useSearchStore, useUiStore, useVrcxStore } from '../../../stores';
|
|
||||||
import { DataTableLayout } from '../../ui/data-table';
|
import { DataTableLayout } from '../../ui/data-table';
|
||||||
import { createColumns } from './previousInstancesUserColumns.jsx';
|
import { createColumns } from './previousInstancesUserColumns.jsx';
|
||||||
import { database } from '../../../service/database';
|
import { database } from '../../../service/database';
|
||||||
@@ -68,6 +74,8 @@
|
|||||||
});
|
});
|
||||||
|
|
||||||
const emit = defineEmits(['update:previous-instances-user-dialog']);
|
const emit = defineEmits(['update:previous-instances-user-dialog']);
|
||||||
|
|
||||||
|
const modalStore = useModalStore();
|
||||||
const loading = ref(false);
|
const loading = ref(false);
|
||||||
const rawRows = ref([]);
|
const rawRows = ref([]);
|
||||||
const search = ref('');
|
const search = ref('');
|
||||||
@@ -189,13 +197,14 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
function deleteGameLogUserInstancePrompt(row) {
|
function deleteGameLogUserInstancePrompt(row) {
|
||||||
ElMessageBox.confirm('Continue? Delete User From GameLog Instance', 'Confirm', {
|
modalStore
|
||||||
confirmButtonText: 'Confirm',
|
.confirm({
|
||||||
cancelButtonText: 'Cancel',
|
description: 'Continue? Delete User From GameLog Instance',
|
||||||
type: 'info'
|
title: 'Confirm'
|
||||||
})
|
})
|
||||||
.then((action) => {
|
.then(({ ok }) => {
|
||||||
if (action === 'confirm') deleteGameLogUserInstance(row);
|
if (!ok) return;
|
||||||
|
deleteGameLogUserInstance(row);
|
||||||
})
|
})
|
||||||
.catch(() => {});
|
.catch(() => {});
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1318,7 +1318,6 @@
|
|||||||
import { Download, LogOut, RefreshCcw } from 'lucide-vue-next';
|
import { Download, LogOut, RefreshCcw } from 'lucide-vue-next';
|
||||||
import { Button } from '@/components/ui/button';
|
import { Button } from '@/components/ui/button';
|
||||||
import { Checkbox } from '@/components/ui/checkbox';
|
import { Checkbox } from '@/components/ui/checkbox';
|
||||||
import { ElMessageBox } from 'element-plus';
|
|
||||||
import { Spinner } from '@/components/ui/spinner';
|
import { Spinner } from '@/components/ui/spinner';
|
||||||
import { storeToRefs } from 'pinia';
|
import { storeToRefs } from 'pinia';
|
||||||
import { toast } from 'vue-sonner';
|
import { toast } from 'vue-sonner';
|
||||||
@@ -1358,6 +1357,7 @@
|
|||||||
useGroupStore,
|
useGroupStore,
|
||||||
useInviteStore,
|
useInviteStore,
|
||||||
useLocationStore,
|
useLocationStore,
|
||||||
|
useModalStore,
|
||||||
useModerationStore,
|
useModerationStore,
|
||||||
useUiStore,
|
useUiStore,
|
||||||
useUserStore,
|
useUserStore,
|
||||||
@@ -1393,6 +1393,8 @@
|
|||||||
|
|
||||||
const { t } = useI18n();
|
const { t } = useI18n();
|
||||||
|
|
||||||
|
const modalStore = useModalStore();
|
||||||
|
|
||||||
const { hideUserNotes, hideUserMemos, isDarkMode } = storeToRefs(useAppearanceSettingsStore());
|
const { hideUserNotes, hideUserMemos, isDarkMode } = storeToRefs(useAppearanceSettingsStore());
|
||||||
const { bioLanguage, avatarRemoteDatabase, translationApi, translationApiType } =
|
const { bioLanguage, avatarRemoteDatabase, translationApi, translationApiType } =
|
||||||
storeToRefs(useAdvancedSettingsStore());
|
storeToRefs(useAdvancedSettingsStore());
|
||||||
@@ -1894,19 +1896,17 @@
|
|||||||
? command
|
? command
|
||||||
: t(`${i18nPreFix}${formattedCommand}`);
|
: t(`${i18nPreFix}${formattedCommand}`);
|
||||||
|
|
||||||
ElMessageBox.confirm(
|
modalStore
|
||||||
t('confirm.message', {
|
.confirm({
|
||||||
command: displayCommandText
|
description: t('confirm.message', {
|
||||||
}),
|
command: displayCommandText
|
||||||
t('confirm.title'),
|
}),
|
||||||
{
|
title: t('confirm.title'),
|
||||||
confirmButtonText: t('confirm.confirm_button'),
|
confirmText: t('confirm.confirm_button'),
|
||||||
cancelButtonText: t('confirm.cancel_button'),
|
cancelText: t('confirm.cancel_button')
|
||||||
type: 'info'
|
})
|
||||||
}
|
.then(({ ok }) => {
|
||||||
)
|
if (ok) {
|
||||||
.then((action) => {
|
|
||||||
if (action === 'confirm') {
|
|
||||||
performUserDialogCommand(command, D.id);
|
performUserDialogCommand(command, D.id);
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
@@ -2422,22 +2422,21 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
function resetHome() {
|
function resetHome() {
|
||||||
ElMessageBox.confirm('Continue? Reset Home', 'Confirm', {
|
modalStore
|
||||||
confirmButtonText: 'Confirm',
|
.confirm({
|
||||||
cancelButtonText: 'Cancel',
|
description: 'Continue? Reset Home',
|
||||||
type: 'info'
|
title: 'Confirm'
|
||||||
})
|
})
|
||||||
.then((action) => {
|
.then(({ ok }) => {
|
||||||
if (action === 'confirm') {
|
if (!ok) return;
|
||||||
userRequest
|
userRequest
|
||||||
.saveCurrentUser({
|
.saveCurrentUser({
|
||||||
homeLocation: ''
|
homeLocation: ''
|
||||||
})
|
})
|
||||||
.then((args) => {
|
.then((args) => {
|
||||||
toast.success('Home world has been reset');
|
toast.success('Home world has been reset');
|
||||||
return args;
|
return args;
|
||||||
});
|
});
|
||||||
}
|
|
||||||
})
|
})
|
||||||
.catch(() => {});
|
.catch(() => {});
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -795,6 +795,7 @@
|
|||||||
useInstanceStore,
|
useInstanceStore,
|
||||||
useInviteStore,
|
useInviteStore,
|
||||||
useLocationStore,
|
useLocationStore,
|
||||||
|
useModalStore,
|
||||||
useUserStore,
|
useUserStore,
|
||||||
useWorldStore
|
useWorldStore
|
||||||
} from '../../../stores';
|
} from '../../../stores';
|
||||||
@@ -810,6 +811,8 @@
|
|||||||
import { Badge } from '../../ui/badge';
|
import { Badge } from '../../ui/badge';
|
||||||
import { database } from '../../../service/database.js';
|
import { database } from '../../../service/database.js';
|
||||||
|
|
||||||
|
const modalStore = useModalStore();
|
||||||
|
|
||||||
const NewInstanceDialog = defineAsyncComponent(() => import('../NewInstanceDialog.vue'));
|
const NewInstanceDialog = defineAsyncComponent(() => import('../NewInstanceDialog.vue'));
|
||||||
const PreviousInstancesWorldDialog = defineAsyncComponent(
|
const PreviousInstancesWorldDialog = defineAsyncComponent(
|
||||||
() => import('../PreviousInstancesDialog/PreviousInstancesWorldDialog.vue')
|
() => import('../PreviousInstancesDialog/PreviousInstancesWorldDialog.vue')
|
||||||
@@ -988,15 +991,13 @@
|
|||||||
case 'Unpublish':
|
case 'Unpublish':
|
||||||
case 'Delete Persistent Data':
|
case 'Delete Persistent Data':
|
||||||
case 'Delete':
|
case 'Delete':
|
||||||
ElMessageBox.confirm(`Continue? ${command}`, 'Confirm', {
|
modalStore
|
||||||
confirmButtonText: 'Confirm',
|
.confirm({
|
||||||
cancelButtonText: 'Cancel',
|
description: `Continue? ${command}`,
|
||||||
type: 'info'
|
title: 'Confirm'
|
||||||
})
|
})
|
||||||
.then((action) => {
|
.then(({ ok }) => {
|
||||||
if (action !== 'confirm') {
|
if (!ok) return;
|
||||||
return;
|
|
||||||
}
|
|
||||||
switch (command) {
|
switch (command) {
|
||||||
case 'Delete Favorite':
|
case 'Delete Favorite':
|
||||||
favoriteRequest.deleteFavorite({
|
favoriteRequest.deleteFavorite({
|
||||||
|
|||||||
17
src/components/ui/alert-dialog/AlertDialog.vue
Normal file
17
src/components/ui/alert-dialog/AlertDialog.vue
Normal file
@@ -0,0 +1,17 @@
|
|||||||
|
<script setup>
|
||||||
|
import { AlertDialogRoot, useForwardPropsEmits } from 'reka-ui';
|
||||||
|
|
||||||
|
const props = defineProps({
|
||||||
|
open: { type: Boolean, required: false },
|
||||||
|
defaultOpen: { type: Boolean, required: false }
|
||||||
|
});
|
||||||
|
const emits = defineEmits(['update:open']);
|
||||||
|
|
||||||
|
const forwarded = useForwardPropsEmits(props, emits);
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<AlertDialogRoot v-slot="slotProps" data-slot="alert-dialog" v-bind="forwarded">
|
||||||
|
<slot v-bind="slotProps" />
|
||||||
|
</AlertDialogRoot>
|
||||||
|
</template>
|
||||||
20
src/components/ui/alert-dialog/AlertDialogAction.vue
Normal file
20
src/components/ui/alert-dialog/AlertDialogAction.vue
Normal file
@@ -0,0 +1,20 @@
|
|||||||
|
<script setup>
|
||||||
|
import { AlertDialogAction } from 'reka-ui';
|
||||||
|
import { buttonVariants } from '@/components/ui/button';
|
||||||
|
import { cn } from '@/lib/utils';
|
||||||
|
import { reactiveOmit } from '@vueuse/core';
|
||||||
|
|
||||||
|
const props = defineProps({
|
||||||
|
asChild: { type: Boolean, required: false },
|
||||||
|
as: { type: null, required: false },
|
||||||
|
class: { type: null, required: false }
|
||||||
|
});
|
||||||
|
|
||||||
|
const delegatedProps = reactiveOmit(props, 'class');
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<AlertDialogAction v-bind="delegatedProps" :class="cn(buttonVariants(), props.class)">
|
||||||
|
<slot />
|
||||||
|
</AlertDialogAction>
|
||||||
|
</template>
|
||||||
22
src/components/ui/alert-dialog/AlertDialogCancel.vue
Normal file
22
src/components/ui/alert-dialog/AlertDialogCancel.vue
Normal file
@@ -0,0 +1,22 @@
|
|||||||
|
<script setup>
|
||||||
|
import { AlertDialogCancel } from 'reka-ui';
|
||||||
|
import { buttonVariants } from '@/components/ui/button';
|
||||||
|
import { cn } from '@/lib/utils';
|
||||||
|
import { reactiveOmit } from '@vueuse/core';
|
||||||
|
|
||||||
|
const props = defineProps({
|
||||||
|
asChild: { type: Boolean, required: false },
|
||||||
|
as: { type: null, required: false },
|
||||||
|
class: { type: null, required: false }
|
||||||
|
});
|
||||||
|
|
||||||
|
const delegatedProps = reactiveOmit(props, 'class');
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<AlertDialogCancel
|
||||||
|
v-bind="delegatedProps"
|
||||||
|
:class="cn(buttonVariants({ variant: 'outline' }), 'mt-2 sm:mt-0', props.class)">
|
||||||
|
<slot />
|
||||||
|
</AlertDialogCancel>
|
||||||
|
</template>
|
||||||
48
src/components/ui/alert-dialog/AlertDialogContent.vue
Normal file
48
src/components/ui/alert-dialog/AlertDialogContent.vue
Normal file
@@ -0,0 +1,48 @@
|
|||||||
|
<script setup>
|
||||||
|
import { AlertDialogContent, AlertDialogOverlay, AlertDialogPortal, useForwardPropsEmits } from 'reka-ui';
|
||||||
|
import { cn } from '@/lib/utils';
|
||||||
|
import { reactiveOmit } from '@vueuse/core';
|
||||||
|
|
||||||
|
defineOptions({
|
||||||
|
inheritAttrs: false
|
||||||
|
});
|
||||||
|
|
||||||
|
const props = defineProps({
|
||||||
|
forceMount: { type: Boolean, required: false },
|
||||||
|
disableOutsidePointerEvents: { type: Boolean, required: false },
|
||||||
|
asChild: { type: Boolean, required: false },
|
||||||
|
as: { type: null, required: false },
|
||||||
|
class: { type: null, required: false }
|
||||||
|
});
|
||||||
|
const emits = defineEmits([
|
||||||
|
'escapeKeyDown',
|
||||||
|
'pointerDownOutside',
|
||||||
|
'focusOutside',
|
||||||
|
'interactOutside',
|
||||||
|
'openAutoFocus',
|
||||||
|
'closeAutoFocus'
|
||||||
|
]);
|
||||||
|
|
||||||
|
const delegatedProps = reactiveOmit(props, 'class');
|
||||||
|
|
||||||
|
const forwarded = useForwardPropsEmits(delegatedProps, emits);
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<AlertDialogPortal>
|
||||||
|
<AlertDialogOverlay
|
||||||
|
data-slot="alert-dialog-overlay"
|
||||||
|
class="data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 fixed inset-0 z-10000 bg-black/80" />
|
||||||
|
<AlertDialogContent
|
||||||
|
data-slot="alert-dialog-content"
|
||||||
|
v-bind="{ ...$attrs, ...forwarded }"
|
||||||
|
:class="
|
||||||
|
cn(
|
||||||
|
'bg-background data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 fixed top-[50%] left-[50%] z-10000 grid w-full max-w-[calc(100%-2rem)] translate-x-[-50%] translate-y-[-50%] gap-4 rounded-lg border p-6 shadow-lg duration-200 sm:max-w-lg',
|
||||||
|
props.class
|
||||||
|
)
|
||||||
|
">
|
||||||
|
<slot />
|
||||||
|
</AlertDialogContent>
|
||||||
|
</AlertDialogPortal>
|
||||||
|
</template>
|
||||||
22
src/components/ui/alert-dialog/AlertDialogDescription.vue
Normal file
22
src/components/ui/alert-dialog/AlertDialogDescription.vue
Normal file
@@ -0,0 +1,22 @@
|
|||||||
|
<script setup>
|
||||||
|
import { AlertDialogDescription } from 'reka-ui';
|
||||||
|
import { cn } from '@/lib/utils';
|
||||||
|
import { reactiveOmit } from '@vueuse/core';
|
||||||
|
|
||||||
|
const props = defineProps({
|
||||||
|
asChild: { type: Boolean, required: false },
|
||||||
|
as: { type: null, required: false },
|
||||||
|
class: { type: null, required: false }
|
||||||
|
});
|
||||||
|
|
||||||
|
const delegatedProps = reactiveOmit(props, 'class');
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<AlertDialogDescription
|
||||||
|
data-slot="alert-dialog-description"
|
||||||
|
v-bind="delegatedProps"
|
||||||
|
:class="cn('text-muted-foreground text-sm', props.class)">
|
||||||
|
<slot />
|
||||||
|
</AlertDialogDescription>
|
||||||
|
</template>
|
||||||
15
src/components/ui/alert-dialog/AlertDialogFooter.vue
Normal file
15
src/components/ui/alert-dialog/AlertDialogFooter.vue
Normal file
@@ -0,0 +1,15 @@
|
|||||||
|
<script setup>
|
||||||
|
import { cn } from '@/lib/utils';
|
||||||
|
|
||||||
|
const props = defineProps({
|
||||||
|
class: { type: null, required: false }
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<div
|
||||||
|
data-slot="alert-dialog-footer"
|
||||||
|
:class="cn('flex flex-col-reverse gap-2 sm:flex-row sm:justify-end', props.class)">
|
||||||
|
<slot />
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
13
src/components/ui/alert-dialog/AlertDialogHeader.vue
Normal file
13
src/components/ui/alert-dialog/AlertDialogHeader.vue
Normal file
@@ -0,0 +1,13 @@
|
|||||||
|
<script setup>
|
||||||
|
import { cn } from '@/lib/utils';
|
||||||
|
|
||||||
|
const props = defineProps({
|
||||||
|
class: { type: null, required: false }
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<div data-slot="alert-dialog-header" :class="cn('flex flex-col gap-2 text-center sm:text-left', props.class)">
|
||||||
|
<slot />
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
67
src/components/ui/alert-dialog/AlertDialogModal.vue
Normal file
67
src/components/ui/alert-dialog/AlertDialogModal.vue
Normal file
@@ -0,0 +1,67 @@
|
|||||||
|
<script setup>
|
||||||
|
import {
|
||||||
|
AlertDialog,
|
||||||
|
AlertDialogAction,
|
||||||
|
AlertDialogCancel,
|
||||||
|
AlertDialogContent,
|
||||||
|
AlertDialogDescription,
|
||||||
|
AlertDialogFooter,
|
||||||
|
AlertDialogHeader,
|
||||||
|
AlertDialogTitle
|
||||||
|
} from '@/components/ui/alert-dialog';
|
||||||
|
import { storeToRefs } from 'pinia';
|
||||||
|
import { useModalStore } from '@/stores';
|
||||||
|
|
||||||
|
const modalStore = useModalStore();
|
||||||
|
|
||||||
|
const { alertOpen, alertMode, alertTitle, alertDescription, alertOkText, alertCancelText, alertDismissible } =
|
||||||
|
storeToRefs(modalStore);
|
||||||
|
|
||||||
|
function onEscapeKeyDown(event) {
|
||||||
|
if (!alertDismissible.value) {
|
||||||
|
event.preventDefault();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
modalStore.handleDismiss();
|
||||||
|
}
|
||||||
|
|
||||||
|
function onPointerDownOutside(event) {
|
||||||
|
if (!alertDismissible.value) {
|
||||||
|
event.preventDefault();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
modalStore.handleDismiss();
|
||||||
|
}
|
||||||
|
|
||||||
|
function onInteractOutside(event) {
|
||||||
|
if (!alertDismissible.value) {
|
||||||
|
event.preventDefault();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
modalStore.handleDismiss();
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<AlertDialog :open="alertOpen" @update:open="modalStore.setAlertOpen">
|
||||||
|
<AlertDialogContent
|
||||||
|
@escapeKeyDown="onEscapeKeyDown"
|
||||||
|
@pointerDownOutside="onPointerDownOutside"
|
||||||
|
@interactOutside="onInteractOutside">
|
||||||
|
<AlertDialogHeader>
|
||||||
|
<AlertDialogTitle>{{ alertTitle }}</AlertDialogTitle>
|
||||||
|
<AlertDialogDescription>{{ alertDescription }}</AlertDialogDescription>
|
||||||
|
</AlertDialogHeader>
|
||||||
|
|
||||||
|
<AlertDialogFooter>
|
||||||
|
<AlertDialogCancel v-if="alertMode === 'confirm'" @click="modalStore.handleCancel">
|
||||||
|
{{ alertCancelText }}
|
||||||
|
</AlertDialogCancel>
|
||||||
|
|
||||||
|
<AlertDialogAction @click="modalStore.handleOk">
|
||||||
|
{{ alertOkText }}
|
||||||
|
</AlertDialogAction>
|
||||||
|
</AlertDialogFooter>
|
||||||
|
</AlertDialogContent>
|
||||||
|
</AlertDialog>
|
||||||
|
</template>
|
||||||
22
src/components/ui/alert-dialog/AlertDialogTitle.vue
Normal file
22
src/components/ui/alert-dialog/AlertDialogTitle.vue
Normal file
@@ -0,0 +1,22 @@
|
|||||||
|
<script setup>
|
||||||
|
import { AlertDialogTitle } from 'reka-ui';
|
||||||
|
import { cn } from '@/lib/utils';
|
||||||
|
import { reactiveOmit } from '@vueuse/core';
|
||||||
|
|
||||||
|
const props = defineProps({
|
||||||
|
asChild: { type: Boolean, required: false },
|
||||||
|
as: { type: null, required: false },
|
||||||
|
class: { type: null, required: false }
|
||||||
|
});
|
||||||
|
|
||||||
|
const delegatedProps = reactiveOmit(props, 'class');
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<AlertDialogTitle
|
||||||
|
data-slot="alert-dialog-title"
|
||||||
|
v-bind="delegatedProps"
|
||||||
|
:class="cn('text-lg font-semibold', props.class)">
|
||||||
|
<slot />
|
||||||
|
</AlertDialogTitle>
|
||||||
|
</template>
|
||||||
14
src/components/ui/alert-dialog/AlertDialogTrigger.vue
Normal file
14
src/components/ui/alert-dialog/AlertDialogTrigger.vue
Normal file
@@ -0,0 +1,14 @@
|
|||||||
|
<script setup>
|
||||||
|
import { AlertDialogTrigger } from 'reka-ui';
|
||||||
|
|
||||||
|
const props = defineProps({
|
||||||
|
asChild: { type: Boolean, required: false },
|
||||||
|
as: { type: null, required: false }
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<AlertDialogTrigger data-slot="alert-dialog-trigger" v-bind="props">
|
||||||
|
<slot />
|
||||||
|
</AlertDialogTrigger>
|
||||||
|
</template>
|
||||||
9
src/components/ui/alert-dialog/index.js
Normal file
9
src/components/ui/alert-dialog/index.js
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
export { default as AlertDialog } from './AlertDialog.vue';
|
||||||
|
export { default as AlertDialogAction } from './AlertDialogAction.vue';
|
||||||
|
export { default as AlertDialogCancel } from './AlertDialogCancel.vue';
|
||||||
|
export { default as AlertDialogContent } from './AlertDialogContent.vue';
|
||||||
|
export { default as AlertDialogDescription } from './AlertDialogDescription.vue';
|
||||||
|
export { default as AlertDialogFooter } from './AlertDialogFooter.vue';
|
||||||
|
export { default as AlertDialogHeader } from './AlertDialogHeader.vue';
|
||||||
|
export { default as AlertDialogTitle } from './AlertDialogTitle.vue';
|
||||||
|
export { default as AlertDialogTrigger } from './AlertDialogTrigger.vue';
|
||||||
@@ -911,6 +911,11 @@
|
|||||||
"pending_offline": "Pending Offline"
|
"pending_offline": "Pending Offline"
|
||||||
},
|
},
|
||||||
"dialog": {
|
"dialog": {
|
||||||
|
"alertdialog": {
|
||||||
|
"ok": "OK",
|
||||||
|
"cancel": "Cancel",
|
||||||
|
"confirm": "Confirm"
|
||||||
|
},
|
||||||
"user": {
|
"user": {
|
||||||
"status": {
|
"status": {
|
||||||
"active": "Active",
|
"active": "Active",
|
||||||
|
|||||||
@@ -1,4 +1,3 @@
|
|||||||
import { ElMessageBox } from 'element-plus';
|
|
||||||
import { toast } from 'vue-sonner';
|
import { toast } from 'vue-sonner';
|
||||||
|
|
||||||
import Noty from 'noty';
|
import Noty from 'noty';
|
||||||
@@ -6,6 +5,7 @@ import Noty from 'noty';
|
|||||||
import {
|
import {
|
||||||
useAuthStore,
|
useAuthStore,
|
||||||
useAvatarStore,
|
useAvatarStore,
|
||||||
|
useModalStore,
|
||||||
useNotificationStore,
|
useNotificationStore,
|
||||||
useUpdateLoopStore,
|
useUpdateLoopStore,
|
||||||
useUserStore
|
useUserStore
|
||||||
@@ -33,6 +33,7 @@ export function request(endpoint, options) {
|
|||||||
const userStore = useUserStore();
|
const userStore = useUserStore();
|
||||||
const avatarStore = useAvatarStore();
|
const avatarStore = useAvatarStore();
|
||||||
const authStore = useAuthStore();
|
const authStore = useAuthStore();
|
||||||
|
const modalStore = useModalStore();
|
||||||
const notificationStore = useNotificationStore();
|
const notificationStore = useNotificationStore();
|
||||||
const updateLoopStore = useUpdateLoopStore();
|
const updateLoopStore = useUpdateLoopStore();
|
||||||
if (
|
if (
|
||||||
@@ -187,10 +188,10 @@ export function request(endpoint, options) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (status === 403 && endpoint === 'config') {
|
if (status === 403 && endpoint === 'config') {
|
||||||
ElMessageBox.alert(
|
modalStore.alert({
|
||||||
t('api.error.message.vpn_in_use'),
|
description: t('api.error.message.vpn_in_use'),
|
||||||
`403 ${t('api.error.message.login_error')}`
|
title: `403 ${t('api.error.message.login_error')}`
|
||||||
).catch(() => {});
|
});
|
||||||
authStore.handleLogoutEvent();
|
authStore.handleLogoutEvent();
|
||||||
$throw(403, endpoint);
|
$throw(403, endpoint);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,22 +1,20 @@
|
|||||||
import { ElMessageBox } from 'element-plus';
|
|
||||||
|
|
||||||
import { openExternalLink } from '../shared/utils';
|
import { openExternalLink } from '../shared/utils';
|
||||||
|
import { useModalStore } from '../stores';
|
||||||
|
|
||||||
// requires binding of SQLite
|
// requires binding of SQLite
|
||||||
class SQLiteService {
|
class SQLiteService {
|
||||||
handleSQLiteError(e) {
|
handleSQLiteError(e) {
|
||||||
if (typeof e.message === 'string') {
|
if (typeof e.message === 'string') {
|
||||||
|
const modalStore = useModalStore();
|
||||||
if (e.message.includes('database disk image is malformed')) {
|
if (e.message.includes('database disk image is malformed')) {
|
||||||
ElMessageBox.confirm(
|
modalStore
|
||||||
'Please repair or delete your database file by following these instructions.',
|
.confirm({
|
||||||
'Your database is corrupted',
|
description:
|
||||||
{
|
'Please repair or delete your database file by following these instructions.',
|
||||||
confirmButtonText: 'Confirm',
|
title: 'Your database is corrupted'
|
||||||
type: 'warning'
|
})
|
||||||
}
|
.then(({ ok }) => {
|
||||||
)
|
if (!ok) return;
|
||||||
.then(async (action) => {
|
|
||||||
if (action !== 'confirm') return;
|
|
||||||
openExternalLink(
|
openExternalLink(
|
||||||
'https://github.com/vrcx-team/VRCX/wiki#how-to-repair-vrcx-database'
|
'https://github.com/vrcx-team/VRCX/wiki#how-to-repair-vrcx-database'
|
||||||
);
|
);
|
||||||
@@ -24,37 +22,26 @@ class SQLiteService {
|
|||||||
.catch(() => {});
|
.catch(() => {});
|
||||||
}
|
}
|
||||||
if (e.message.includes('database or disk is full')) {
|
if (e.message.includes('database or disk is full')) {
|
||||||
ElMessageBox.alert(
|
modalStore.alert({
|
||||||
'Please free up some disk space.',
|
description: 'Please free up some disk space.',
|
||||||
'Disk containing database is full',
|
title: 'Disk containing database is full'
|
||||||
{
|
});
|
||||||
confirmButtonText: 'OK',
|
|
||||||
type: 'warning'
|
|
||||||
}
|
|
||||||
).catch(() => {});
|
|
||||||
}
|
}
|
||||||
if (
|
if (
|
||||||
e.message.includes('database is locked') ||
|
e.message.includes('database is locked') ||
|
||||||
e.message.includes('attempt to write a readonly database')
|
e.message.includes('attempt to write a readonly database')
|
||||||
) {
|
) {
|
||||||
ElMessageBox.alert(
|
modalStore.alert({
|
||||||
'Please close other applications that might be using the database file.',
|
description:
|
||||||
'Database is locked',
|
'Please close other applications that might be using the database file.',
|
||||||
{
|
title: 'Database is locked'
|
||||||
confirmButtonText: 'OK',
|
});
|
||||||
type: 'warning'
|
|
||||||
}
|
|
||||||
).catch(() => {});
|
|
||||||
}
|
}
|
||||||
if (e.message.includes('disk I/O error')) {
|
if (e.message.includes('disk I/O error')) {
|
||||||
ElMessageBox.alert(
|
modalStore.alert({
|
||||||
'Please check your disk for errors.',
|
description: 'Please check your disk for errors.',
|
||||||
'Disk I/O error',
|
title: 'Disk I/O error'
|
||||||
{
|
});
|
||||||
confirmButtonText: 'OK',
|
|
||||||
type: 'warning'
|
|
||||||
}
|
|
||||||
).catch(() => {});
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
throw e;
|
throw e;
|
||||||
|
|||||||
@@ -1,4 +1,3 @@
|
|||||||
import { ElMessageBox } from 'element-plus';
|
|
||||||
import { storeToRefs } from 'pinia';
|
import { storeToRefs } from 'pinia';
|
||||||
import { toast } from 'vue-sonner';
|
import { toast } from 'vue-sonner';
|
||||||
|
|
||||||
@@ -7,6 +6,7 @@ import Noty from 'noty';
|
|||||||
import {
|
import {
|
||||||
useAvatarStore,
|
useAvatarStore,
|
||||||
useInstanceStore,
|
useInstanceStore,
|
||||||
|
useModalStore,
|
||||||
useSearchStore,
|
useSearchStore,
|
||||||
useWorldStore
|
useWorldStore
|
||||||
} from '../../stores';
|
} from '../../stores';
|
||||||
@@ -395,24 +395,22 @@ function openExternalLink(link) {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
ElMessageBox.confirm(`${link}`, 'Open External Link', {
|
const modalStore = useModalStore();
|
||||||
distinguishCancelAndClose: true,
|
modalStore
|
||||||
confirmButtonText: 'Open',
|
.confirm({
|
||||||
cancelButtonText: 'Copy',
|
description: `${link}`,
|
||||||
type: 'info',
|
title: 'Open External Link',
|
||||||
beforeClose: (action, instance, done) => {
|
confirmText: 'Open',
|
||||||
if (action === 'cancel') {
|
cancelText: 'Copy'
|
||||||
copyToClipboard(link);
|
|
||||||
}
|
|
||||||
done();
|
|
||||||
}
|
|
||||||
})
|
|
||||||
.then((action) => {
|
|
||||||
if (action === 'confirm') {
|
|
||||||
AppApi.OpenLink(link);
|
|
||||||
}
|
|
||||||
})
|
})
|
||||||
.catch(() => {});
|
// TODO: beforeClose alert dialog
|
||||||
|
.then(({ ok }) => {
|
||||||
|
if (!ok) {
|
||||||
|
copyToClipboard(link, 'Link copied to clipboard!');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
AppApi.OpenLink(link);
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -13,6 +13,7 @@ import { database } from '../service/database';
|
|||||||
import { escapeTag } from '../shared/utils';
|
import { escapeTag } from '../shared/utils';
|
||||||
import { request } from '../service/request';
|
import { request } from '../service/request';
|
||||||
import { useAdvancedSettingsStore } from './settings/advanced';
|
import { useAdvancedSettingsStore } from './settings/advanced';
|
||||||
|
import { useModalStore } from './modal';
|
||||||
import { useNotificationStore } from './notification';
|
import { useNotificationStore } from './notification';
|
||||||
import { useUpdateLoopStore } from './updateLoop';
|
import { useUpdateLoopStore } from './updateLoop';
|
||||||
import { useUserStore } from './user';
|
import { useUserStore } from './user';
|
||||||
@@ -27,6 +28,7 @@ export const useAuthStore = defineStore('Auth', () => {
|
|||||||
const notificationStore = useNotificationStore();
|
const notificationStore = useNotificationStore();
|
||||||
const userStore = useUserStore();
|
const userStore = useUserStore();
|
||||||
const updateLoopStore = useUpdateLoopStore();
|
const updateLoopStore = useUpdateLoopStore();
|
||||||
|
const modalStore = useModalStore();
|
||||||
|
|
||||||
const { t } = useI18n();
|
const { t } = useI18n();
|
||||||
const state = reactive({
|
const state = reactive({
|
||||||
@@ -405,21 +407,20 @@ export const useAuthStore = defineStore('Auth', () => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function logout() {
|
function logout() {
|
||||||
ElMessageBox.confirm('Continue? Logout', 'Confirm', {
|
modalStore
|
||||||
confirmButtonText: 'Confirm',
|
.confirm({
|
||||||
cancelButtonText: 'Cancel',
|
description: 'Continue? Logout',
|
||||||
type: 'info'
|
title: 'Confirm'
|
||||||
})
|
})
|
||||||
.then((action) => {
|
.then(({ ok }) => {
|
||||||
if (action === 'confirm') {
|
if (!ok) return;
|
||||||
const existingStyle = document.getElementById(
|
const existingStyle = document.getElementById(
|
||||||
'login-container-style'
|
'login-container-style'
|
||||||
);
|
);
|
||||||
if (existingStyle) {
|
if (existingStyle) {
|
||||||
existingStyle.parentNode.removeChild(existingStyle);
|
existingStyle.parentNode.removeChild(existingStyle);
|
||||||
}
|
|
||||||
handleLogoutEvent();
|
|
||||||
}
|
}
|
||||||
|
handleLogoutEvent();
|
||||||
})
|
})
|
||||||
.catch(() => {});
|
.catch(() => {});
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,5 +1,4 @@
|
|||||||
import { nextTick, ref, watch } from 'vue';
|
import { nextTick, ref, watch } from 'vue';
|
||||||
import { ElMessageBox } from 'element-plus';
|
|
||||||
import { defineStore } from 'pinia';
|
import { defineStore } from 'pinia';
|
||||||
import { toast } from 'vue-sonner';
|
import { toast } from 'vue-sonner';
|
||||||
|
|
||||||
@@ -18,6 +17,7 @@ import { database } from '../service/database';
|
|||||||
import { useAdvancedSettingsStore } from './settings/advanced';
|
import { useAdvancedSettingsStore } from './settings/advanced';
|
||||||
import { useAvatarProviderStore } from './avatarProvider';
|
import { useAvatarProviderStore } from './avatarProvider';
|
||||||
import { useFavoriteStore } from './favorite';
|
import { useFavoriteStore } from './favorite';
|
||||||
|
import { useModalStore } from './modal';
|
||||||
import { useUserStore } from './user';
|
import { useUserStore } from './user';
|
||||||
import { useVRCXUpdaterStore } from './vrcxUpdater';
|
import { useVRCXUpdaterStore } from './vrcxUpdater';
|
||||||
import { watchState } from '../service/watchState';
|
import { watchState } from '../service/watchState';
|
||||||
@@ -30,6 +30,7 @@ export const useAvatarStore = defineStore('Avatar', () => {
|
|||||||
const vrcxUpdaterStore = useVRCXUpdaterStore();
|
const vrcxUpdaterStore = useVRCXUpdaterStore();
|
||||||
const advancedSettingsStore = useAdvancedSettingsStore();
|
const advancedSettingsStore = useAdvancedSettingsStore();
|
||||||
const userStore = useUserStore();
|
const userStore = useUserStore();
|
||||||
|
const modalStore = useModalStore();
|
||||||
|
|
||||||
let cachedAvatarModerations = new Map();
|
let cachedAvatarModerations = new Map();
|
||||||
let cachedAvatars = new Map();
|
let cachedAvatars = new Map();
|
||||||
@@ -389,12 +390,13 @@ export const useAvatarStore = defineStore('Avatar', () => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function promptClearAvatarHistory() {
|
function promptClearAvatarHistory() {
|
||||||
ElMessageBox.confirm('Continue? Clear Avatar History', 'Confirm', {
|
modalStore
|
||||||
confirmButtonText: 'Confirm',
|
.confirm({
|
||||||
cancelButtonText: 'Cancel',
|
description: 'Continue? Clear Avatar History',
|
||||||
type: 'info'
|
title: 'Confirm'
|
||||||
})
|
})
|
||||||
.then(() => {
|
.then(({ ok }) => {
|
||||||
|
if (!ok) return;
|
||||||
clearAvatarHistory();
|
clearAvatarHistory();
|
||||||
})
|
})
|
||||||
.catch(() => {});
|
.catch(() => {});
|
||||||
@@ -552,12 +554,13 @@ export const useAvatarStore = defineStore('Avatar', () => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function selectAvatarWithConfirmation(id) {
|
function selectAvatarWithConfirmation(id) {
|
||||||
ElMessageBox.confirm(`Continue? Select Avatar`, 'Confirm', {
|
modalStore
|
||||||
confirmButtonText: 'Confirm',
|
.confirm({
|
||||||
cancelButtonText: 'Cancel',
|
description: 'Continue? Select Avatar',
|
||||||
type: 'info'
|
title: 'Confirm'
|
||||||
})
|
})
|
||||||
.then(() => {
|
.then(({ ok }) => {
|
||||||
|
if (!ok) return;
|
||||||
selectAvatarWithoutConfirmation(id);
|
selectAvatarWithoutConfirmation(id);
|
||||||
})
|
})
|
||||||
.catch(() => {});
|
.catch(() => {});
|
||||||
|
|||||||
@@ -1,5 +1,4 @@
|
|||||||
import { computed, reactive, ref, watch } from 'vue';
|
import { computed, reactive, ref, watch } from 'vue';
|
||||||
import { ElMessageBox } from 'element-plus';
|
|
||||||
import { defineStore } from 'pinia';
|
import { defineStore } from 'pinia';
|
||||||
import { toast } from 'vue-sonner';
|
import { toast } from 'vue-sonner';
|
||||||
import { useI18n } from 'vue-i18n';
|
import { useI18n } from 'vue-i18n';
|
||||||
@@ -27,6 +26,7 @@ import { useFeedStore } from './feed';
|
|||||||
import { useGeneralSettingsStore } from './settings/general';
|
import { useGeneralSettingsStore } from './settings/general';
|
||||||
import { useGroupStore } from './group';
|
import { useGroupStore } from './group';
|
||||||
import { useLocationStore } from './location';
|
import { useLocationStore } from './location';
|
||||||
|
import { useModalStore } from './modal';
|
||||||
import { useNotificationStore } from './notification';
|
import { useNotificationStore } from './notification';
|
||||||
import { useSharedFeedStore } from './sharedFeed';
|
import { useSharedFeedStore } from './sharedFeed';
|
||||||
import { useUiStore } from './ui';
|
import { useUiStore } from './ui';
|
||||||
@@ -51,6 +51,7 @@ export const useFriendStore = defineStore('Friend', () => {
|
|||||||
const authStore = useAuthStore();
|
const authStore = useAuthStore();
|
||||||
const locationStore = useLocationStore();
|
const locationStore = useLocationStore();
|
||||||
const favoriteStore = useFavoriteStore();
|
const favoriteStore = useFavoriteStore();
|
||||||
|
const modalStore = useModalStore();
|
||||||
const { t } = useI18n();
|
const { t } = useI18n();
|
||||||
|
|
||||||
const state = reactive({
|
const state = reactive({
|
||||||
@@ -1578,12 +1579,13 @@ export const useFriendStore = defineStore('Friend', () => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function confirmDeleteFriend(id) {
|
function confirmDeleteFriend(id) {
|
||||||
ElMessageBox.confirm('Continue? Unfriend', 'Confirm', {
|
modalStore
|
||||||
confirmButtonText: 'Confirm',
|
.confirm({
|
||||||
cancelButtonText: 'Cancel',
|
description: 'Continue? Unfriend',
|
||||||
type: 'info'
|
title: 'Confirm'
|
||||||
})
|
})
|
||||||
.then(async () => {
|
.then(async ({ ok }) => {
|
||||||
|
if (!ok) return;
|
||||||
const args = await friendRequest.deleteFriend({
|
const args = await friendRequest.deleteFriend({
|
||||||
userId: id
|
userId: id
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -1,5 +1,4 @@
|
|||||||
import { reactive, ref, shallowReactive, watch } from 'vue';
|
import { reactive, ref, shallowReactive, watch } from 'vue';
|
||||||
import { ElMessageBox } from 'element-plus';
|
|
||||||
import { defineStore } from 'pinia';
|
import { defineStore } from 'pinia';
|
||||||
import { useI18n } from 'vue-i18n';
|
import { useI18n } from 'vue-i18n';
|
||||||
|
|
||||||
@@ -19,9 +18,10 @@ import {
|
|||||||
} from '../api';
|
} from '../api';
|
||||||
import { AppDebug } from '../service/appConfig';
|
import { AppDebug } from '../service/appConfig';
|
||||||
import { handleImageUploadInput } from '../shared/utils/imageUpload';
|
import { handleImageUploadInput } from '../shared/utils/imageUpload';
|
||||||
import { useAdvancedSettingsStore } from './settings/advanced';
|
|
||||||
import { watchState } from '../service/watchState';
|
|
||||||
import { router } from '../plugin/router';
|
import { router } from '../plugin/router';
|
||||||
|
import { useAdvancedSettingsStore } from './settings/advanced';
|
||||||
|
import { useModalStore } from './modal';
|
||||||
|
import { watchState } from '../service/watchState';
|
||||||
|
|
||||||
import miscReq from '../api/misc';
|
import miscReq from '../api/misc';
|
||||||
|
|
||||||
@@ -30,6 +30,7 @@ import * as workerTimers from 'worker-timers';
|
|||||||
export const useGalleryStore = defineStore('Gallery', () => {
|
export const useGalleryStore = defineStore('Gallery', () => {
|
||||||
const advancedSettingsStore = useAdvancedSettingsStore();
|
const advancedSettingsStore = useAdvancedSettingsStore();
|
||||||
const { t } = useI18n();
|
const { t } = useI18n();
|
||||||
|
const modalStore = useModalStore();
|
||||||
|
|
||||||
const state = reactive({
|
const state = reactive({
|
||||||
printCache: [],
|
printCache: [],
|
||||||
@@ -515,17 +516,15 @@ export const useGalleryStore = defineStore('Gallery', () => {
|
|||||||
}
|
}
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
if (e.message.includes('Could not find file')) {
|
if (e.message.includes('Could not find file')) {
|
||||||
ElMessageBox.confirm(
|
modalStore
|
||||||
'Windows has blocked VRCX from creating files on your system. Please allow VRCX to create files to save emojis, would you like to see instructions on how to fix this?',
|
.confirm({
|
||||||
'Failed to create emoji folder',
|
description:
|
||||||
{
|
'Windows has blocked VRCX from creating files on your system. Please allow VRCX to create files to save emojis, would you like to see instructions on how to fix this?',
|
||||||
confirmButtonText: 'Confirm',
|
title: 'Failed to create emoji folder',
|
||||||
cancelButtonText: 'Ignore',
|
cancelText: 'Ignore'
|
||||||
type: 'warning'
|
})
|
||||||
}
|
.then(({ ok }) => {
|
||||||
)
|
if (!ok) return;
|
||||||
.then(async (action) => {
|
|
||||||
if (action !== 'confirm') return;
|
|
||||||
openExternalLink(
|
openExternalLink(
|
||||||
'https://www.youtube.com/watch?v=1mwmmCdA4D8&t=213s'
|
'https://www.youtube.com/watch?v=1mwmmCdA4D8&t=213s'
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -1,5 +1,4 @@
|
|||||||
import { reactive, ref } from 'vue';
|
import { reactive, ref } from 'vue';
|
||||||
import { ElMessageBox } from 'element-plus';
|
|
||||||
import { defineStore } from 'pinia';
|
import { defineStore } from 'pinia';
|
||||||
import { toast } from 'vue-sonner';
|
import { toast } from 'vue-sonner';
|
||||||
|
|
||||||
@@ -14,6 +13,7 @@ import { useGameLogStore } from './gameLog';
|
|||||||
import { useInstanceStore } from './instance';
|
import { useInstanceStore } from './instance';
|
||||||
import { useLaunchStore } from './launch';
|
import { useLaunchStore } from './launch';
|
||||||
import { useLocationStore } from './location';
|
import { useLocationStore } from './location';
|
||||||
|
import { useModalStore } from './modal';
|
||||||
import { useNotificationStore } from './notification';
|
import { useNotificationStore } from './notification';
|
||||||
import { useUpdateLoopStore } from './updateLoop';
|
import { useUpdateLoopStore } from './updateLoop';
|
||||||
import { useUserStore } from './user';
|
import { useUserStore } from './user';
|
||||||
@@ -36,6 +36,7 @@ export const useGameStore = defineStore('Game', () => {
|
|||||||
const vrStore = useVrStore();
|
const vrStore = useVrStore();
|
||||||
const userStore = useUserStore();
|
const userStore = useUserStore();
|
||||||
const updateLoopStore = useUpdateLoopStore();
|
const updateLoopStore = useUpdateLoopStore();
|
||||||
|
const modalStore = useModalStore();
|
||||||
|
|
||||||
const state = reactive({
|
const state = reactive({
|
||||||
lastCrashedTime: null
|
lastCrashedTime: null
|
||||||
@@ -218,17 +219,19 @@ export const useGameStore = defineStore('Game', () => {
|
|||||||
);
|
);
|
||||||
if (!result) {
|
if (!result) {
|
||||||
// failed to set key
|
// failed to set key
|
||||||
ElMessageBox.alert(
|
modalStore.alert({
|
||||||
'VRCX has noticed VRChat debug logging is disabled. VRCX requires debug logging in order to function correctly. Please enable debug logging in VRChat quick menu settings > debug > enable debug logging, then rejoin the instance or restart VRChat.',
|
description:
|
||||||
'Enable debug logging'
|
'VRCX has noticed VRChat debug logging is disabled. VRCX requires debug logging in order to function correctly. Please enable debug logging in VRChat quick menu settings > debug > enable debug logging, then rejoin the instance or restart VRChat.',
|
||||||
).catch(() => {});
|
title: 'Enable debug logging'
|
||||||
|
});
|
||||||
console.error('Failed to enable debug logging', result);
|
console.error('Failed to enable debug logging', result);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
ElMessageBox.alert(
|
modalStore.alert({
|
||||||
'VRCX has noticed VRChat debug logging is disabled and automatically re-enabled it. VRCX requires debug logging in order to function correctly.',
|
description:
|
||||||
'Enabled debug logging'
|
'VRCX has noticed VRChat debug logging is disabled and automatically re-enabled it. VRCX requires debug logging in order to function correctly.',
|
||||||
).catch(() => {});
|
title: 'Enabled debug logging'
|
||||||
|
});
|
||||||
console.log('Enabled debug logging');
|
console.log('Enabled debug logging');
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
console.error(e);
|
console.error(e);
|
||||||
|
|||||||
@@ -1,5 +1,4 @@
|
|||||||
import { reactive, ref, shallowReactive, watch } from 'vue';
|
import { reactive, ref, shallowReactive, watch } from 'vue';
|
||||||
import { ElMessageBox } from 'element-plus';
|
|
||||||
import { defineStore } from 'pinia';
|
import { defineStore } from 'pinia';
|
||||||
import { toast } from 'vue-sonner';
|
import { toast } from 'vue-sonner';
|
||||||
|
|
||||||
@@ -23,6 +22,7 @@ import { useGameStore } from './game';
|
|||||||
import { useGeneralSettingsStore } from './settings/general';
|
import { useGeneralSettingsStore } from './settings/general';
|
||||||
import { useInstanceStore } from './instance';
|
import { useInstanceStore } from './instance';
|
||||||
import { useLocationStore } from './location';
|
import { useLocationStore } from './location';
|
||||||
|
import { useModalStore } from './modal';
|
||||||
import { useNotificationStore } from './notification';
|
import { useNotificationStore } from './notification';
|
||||||
import { usePhotonStore } from './photon';
|
import { usePhotonStore } from './photon';
|
||||||
import { useSharedFeedStore } from './sharedFeed';
|
import { useSharedFeedStore } from './sharedFeed';
|
||||||
@@ -54,6 +54,7 @@ export const useGameLogStore = defineStore('GameLog', () => {
|
|||||||
const galleryStore = useGalleryStore();
|
const galleryStore = useGalleryStore();
|
||||||
const photonStore = usePhotonStore();
|
const photonStore = usePhotonStore();
|
||||||
const sharedFeedStore = useSharedFeedStore();
|
const sharedFeedStore = useSharedFeedStore();
|
||||||
|
const modalStore = useModalStore();
|
||||||
|
|
||||||
const state = reactive({
|
const state = reactive({
|
||||||
lastLocationAvatarList: new Map()
|
lastLocationAvatarList: new Map()
|
||||||
@@ -1414,15 +1415,14 @@ export const useGameLogStore = defineStore('GameLog', () => {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (!advancedSettingsStore.gameLogDisabled) {
|
if (!advancedSettingsStore.gameLogDisabled) {
|
||||||
ElMessageBox.confirm('Continue? Disable GameLog', 'Confirm', {
|
modalStore
|
||||||
confirmButtonText: 'Confirm',
|
.confirm({
|
||||||
cancelButtonText: 'Cancel',
|
description: 'Continue? Disable GameLog',
|
||||||
type: 'info'
|
title: 'Confirm'
|
||||||
})
|
})
|
||||||
.then(({ action }) => {
|
.then(({ ok }) => {
|
||||||
if (action === 'confirm') {
|
if (!ok) return;
|
||||||
advancedSettingsStore.setGameLogDisabled();
|
advancedSettingsStore.setGameLogDisabled();
|
||||||
}
|
|
||||||
})
|
})
|
||||||
.catch(() => {});
|
.catch(() => {});
|
||||||
} else {
|
} else {
|
||||||
|
|||||||
@@ -1,5 +1,4 @@
|
|||||||
import { nextTick, reactive, ref, watch } from 'vue';
|
import { nextTick, reactive, ref, watch } from 'vue';
|
||||||
import { ElMessageBox } from 'element-plus';
|
|
||||||
import { defineStore } from 'pinia';
|
import { defineStore } from 'pinia';
|
||||||
import { toast } from 'vue-sonner';
|
import { toast } from 'vue-sonner';
|
||||||
|
|
||||||
@@ -18,6 +17,7 @@ import { database } from '../service/database.js';
|
|||||||
import { groupDialogFilterOptions } from '../shared/constants/';
|
import { groupDialogFilterOptions } from '../shared/constants/';
|
||||||
import { useGameStore } from './game';
|
import { useGameStore } from './game';
|
||||||
import { useInstanceStore } from './instance';
|
import { useInstanceStore } from './instance';
|
||||||
|
import { useModalStore } from './modal';
|
||||||
import { useNotificationStore } from './notification';
|
import { useNotificationStore } from './notification';
|
||||||
import { useUserStore } from './user';
|
import { useUserStore } from './user';
|
||||||
import { watchState } from '../service/watchState';
|
import { watchState } from '../service/watchState';
|
||||||
@@ -31,6 +31,7 @@ export const useGroupStore = defineStore('Group', () => {
|
|||||||
const gameStore = useGameStore();
|
const gameStore = useGameStore();
|
||||||
const userStore = useUserStore();
|
const userStore = useUserStore();
|
||||||
const notificationStore = useNotificationStore();
|
const notificationStore = useNotificationStore();
|
||||||
|
const modalStore = useModalStore();
|
||||||
|
|
||||||
let cachedGroups = new Map();
|
let cachedGroups = new Map();
|
||||||
|
|
||||||
@@ -555,16 +556,13 @@ export const useGroupStore = defineStore('Group', () => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function leaveGroupPrompt(groupId) {
|
function leaveGroupPrompt(groupId) {
|
||||||
ElMessageBox.confirm(
|
modalStore
|
||||||
'Are you sure you want to leave this group?',
|
.confirm({
|
||||||
'Confirm',
|
description: 'Are you sure you want to leave this group?',
|
||||||
{
|
title: 'Confirm'
|
||||||
confirmButtonText: 'Confirm',
|
})
|
||||||
cancelButtonText: 'Cancel',
|
.then(({ ok }) => {
|
||||||
type: 'info'
|
if (!ok) return;
|
||||||
}
|
|
||||||
)
|
|
||||||
.then(() => {
|
|
||||||
leaveGroup(groupId);
|
leaveGroup(groupId);
|
||||||
})
|
})
|
||||||
.catch(() => {});
|
.catch(() => {});
|
||||||
|
|||||||
@@ -21,6 +21,7 @@ import { useInstanceStore } from './instance';
|
|||||||
import { useInviteStore } from './invite';
|
import { useInviteStore } from './invite';
|
||||||
import { useLaunchStore } from './launch';
|
import { useLaunchStore } from './launch';
|
||||||
import { useLocationStore } from './location';
|
import { useLocationStore } from './location';
|
||||||
|
import { useModalStore } from './modal';
|
||||||
import { useModerationStore } from './moderation';
|
import { useModerationStore } from './moderation';
|
||||||
import { useNotificationStore } from './notification';
|
import { useNotificationStore } from './notification';
|
||||||
import { useNotificationsSettingsStore } from './settings/notifications';
|
import { useNotificationsSettingsStore } from './settings/notifications';
|
||||||
@@ -162,7 +163,8 @@ export function createGlobalStores() {
|
|||||||
updateLoop: useUpdateLoopStore(),
|
updateLoop: useUpdateLoopStore(),
|
||||||
auth: useAuthStore(),
|
auth: useAuthStore(),
|
||||||
vrcStatus: useVrcStatusStore(),
|
vrcStatus: useVrcStatusStore(),
|
||||||
charts: useChartsStore()
|
charts: useChartsStore(),
|
||||||
|
modal: useModalStore()
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -200,5 +202,6 @@ export {
|
|||||||
useWorldStore,
|
useWorldStore,
|
||||||
useSharedFeedStore,
|
useSharedFeedStore,
|
||||||
useUpdateLoopStore,
|
useUpdateLoopStore,
|
||||||
useVrcStatusStore
|
useVrcStatusStore,
|
||||||
|
useModalStore
|
||||||
};
|
};
|
||||||
|
|||||||
178
src/stores/modal.js
Normal file
178
src/stores/modal.js
Normal file
@@ -0,0 +1,178 @@
|
|||||||
|
import { defineStore } from 'pinia';
|
||||||
|
import { i18n } from '@/plugin';
|
||||||
|
import { ref } from 'vue';
|
||||||
|
|
||||||
|
function translate(key, fallback) {
|
||||||
|
try {
|
||||||
|
return i18n.global.t(key);
|
||||||
|
} catch {
|
||||||
|
return fallback;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @typedef {Object} ConfirmResult
|
||||||
|
* @property {boolean} ok
|
||||||
|
* @property {'ok' | 'cancel' | 'dismiss' | 'replaced'} reason
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @typedef {Object} ConfirmOptions
|
||||||
|
* @property {string} title
|
||||||
|
* @property {string} description
|
||||||
|
* @property {string=} confirmText
|
||||||
|
* @property {string=} cancelText
|
||||||
|
* @property {boolean=} dismissible // true: allow esc/outside, false: block
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @typedef {Object} AlertOptions
|
||||||
|
* @property {string} title
|
||||||
|
* @property {string} description
|
||||||
|
* @property {string=} confirmText
|
||||||
|
* @property {boolean=} dismissible
|
||||||
|
*/
|
||||||
|
|
||||||
|
// TODO: Method chains for confirm
|
||||||
|
|
||||||
|
export const useModalStore = defineStore('Modal', () => {
|
||||||
|
const alertOpen = ref(false);
|
||||||
|
const alertMode = ref('confirm'); // 'confirm' | 'alert'
|
||||||
|
const alertTitle = ref('');
|
||||||
|
const alertDescription = ref('');
|
||||||
|
const alertOkText = ref('');
|
||||||
|
const alertCancelText = ref('');
|
||||||
|
const alertDismissible = ref(true);
|
||||||
|
|
||||||
|
/** @type {{ resolve: ((result: ConfirmResult) => void) | null } | null} */
|
||||||
|
let pending = null;
|
||||||
|
|
||||||
|
function closeDialog() {
|
||||||
|
alertOpen.value = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {'ok' | 'cancel' | 'dismiss' | 'replaced'} reason
|
||||||
|
*/
|
||||||
|
function finish(reason) {
|
||||||
|
const resolve = pending?.resolve;
|
||||||
|
pending = null;
|
||||||
|
closeDialog();
|
||||||
|
if (resolve) resolve({ ok: reason === 'ok', reason });
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {'ok' | 'cancel' | 'dismiss' | 'replaced'} reason
|
||||||
|
*/
|
||||||
|
function finishWithoutClosing(reason) {
|
||||||
|
const resolve = pending?.resolve;
|
||||||
|
pending = null;
|
||||||
|
if (resolve) resolve({ ok: reason === 'ok', reason });
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {'confirm' | 'alert'} mode
|
||||||
|
* @param {any} options
|
||||||
|
*/
|
||||||
|
function openBase(mode, options) {
|
||||||
|
if (pending) {
|
||||||
|
// old dialog is force-finished
|
||||||
|
// do not call closeDialog here because we are about to open a new one
|
||||||
|
finishWithoutClosing('replaced');
|
||||||
|
}
|
||||||
|
|
||||||
|
alertMode.value = mode;
|
||||||
|
alertTitle.value = options.title;
|
||||||
|
alertDescription.value = options.description;
|
||||||
|
alertDismissible.value = options.dismissible !== false;
|
||||||
|
|
||||||
|
if (mode === 'alert') {
|
||||||
|
alertOkText.value =
|
||||||
|
options.confirmText || translate('dialog.alertdialog.ok', 'OK');
|
||||||
|
alertCancelText.value = '';
|
||||||
|
} else {
|
||||||
|
alertOkText.value =
|
||||||
|
options.confirmText ||
|
||||||
|
translate('dialog.alertdialog.confirm', 'Confirm');
|
||||||
|
alertCancelText.value =
|
||||||
|
options.cancelText ||
|
||||||
|
translate('dialog.alertdialog.cancel', 'Cancel');
|
||||||
|
}
|
||||||
|
|
||||||
|
alertOpen.value = true;
|
||||||
|
|
||||||
|
return new Promise((resolve) => {
|
||||||
|
pending = { resolve };
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* confirm: always resolve({ok, reason})
|
||||||
|
* @param {ConfirmOptions} options
|
||||||
|
* @returns {Promise<ConfirmResult>}
|
||||||
|
*/
|
||||||
|
function confirm(options) {
|
||||||
|
return openBase('confirm', options);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* alert: always resolve({ok:true, reason:'ok'}) when closed
|
||||||
|
* @param {AlertOptions} options
|
||||||
|
* @returns {Promise<ConfirmResult>}
|
||||||
|
*/
|
||||||
|
function alert(options) {
|
||||||
|
return openBase('alert', options);
|
||||||
|
}
|
||||||
|
|
||||||
|
function handleOk() {
|
||||||
|
if (!pending) return;
|
||||||
|
finish('ok');
|
||||||
|
}
|
||||||
|
|
||||||
|
function handleCancel() {
|
||||||
|
if (!pending) return;
|
||||||
|
|
||||||
|
// alert has no cancel semantics
|
||||||
|
if (alertMode.value === 'alert') {
|
||||||
|
finish('ok');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
finish('cancel');
|
||||||
|
}
|
||||||
|
|
||||||
|
function handleDismiss() {
|
||||||
|
if (!pending) return;
|
||||||
|
if (!alertDismissible.value) return;
|
||||||
|
|
||||||
|
// alert: dismiss also means done
|
||||||
|
if (alertMode.value === 'alert') {
|
||||||
|
finish('ok');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
finish('dismiss');
|
||||||
|
}
|
||||||
|
|
||||||
|
function setAlertOpen(open) {
|
||||||
|
alertOpen.value = !!open;
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
alertOpen,
|
||||||
|
alertMode,
|
||||||
|
alertTitle,
|
||||||
|
alertDescription,
|
||||||
|
alertOkText,
|
||||||
|
alertCancelText,
|
||||||
|
alertDismissible,
|
||||||
|
|
||||||
|
confirm,
|
||||||
|
alert,
|
||||||
|
|
||||||
|
handleOk,
|
||||||
|
handleCancel,
|
||||||
|
handleDismiss,
|
||||||
|
setAlertOpen
|
||||||
|
};
|
||||||
|
});
|
||||||
@@ -8,6 +8,7 @@ import { AppDebug } from '../../service/appConfig';
|
|||||||
import { database } from '../../service/database';
|
import { database } from '../../service/database';
|
||||||
import { languageCodes } from '../../localization';
|
import { languageCodes } from '../../localization';
|
||||||
import { useGameStore } from '../game';
|
import { useGameStore } from '../game';
|
||||||
|
import { useModalStore } from '../modal';
|
||||||
import { useVRCXUpdaterStore } from '../vrcxUpdater';
|
import { useVRCXUpdaterStore } from '../vrcxUpdater';
|
||||||
import { useVrcxStore } from '../vrcx';
|
import { useVrcxStore } from '../vrcx';
|
||||||
import { watchState } from '../../service/watchState';
|
import { watchState } from '../../service/watchState';
|
||||||
@@ -19,6 +20,7 @@ export const useAdvancedSettingsStore = defineStore('AdvancedSettings', () => {
|
|||||||
const gameStore = useGameStore();
|
const gameStore = useGameStore();
|
||||||
const vrcxStore = useVrcxStore();
|
const vrcxStore = useVrcxStore();
|
||||||
const VRCXUpdaterStore = useVRCXUpdaterStore();
|
const VRCXUpdaterStore = useVRCXUpdaterStore();
|
||||||
|
const modalStore = useModalStore();
|
||||||
|
|
||||||
const { t } = useI18n();
|
const { t } = useI18n();
|
||||||
|
|
||||||
@@ -466,68 +468,58 @@ export const useAdvancedSettingsStore = defineStore('AdvancedSettings', () => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
async function checkSentryConsent() {
|
async function checkSentryConsent() {
|
||||||
const { action: consentAction } = await ElMessageBox.confirm(
|
modalStore
|
||||||
'Help improve VRCX by allowing anonymous error reporting?</br></br>' +
|
.confirm({
|
||||||
'• Only collects crash and error information.</br>' +
|
description:
|
||||||
'• No personal data or VRChat information is collected.</br>' +
|
'Help improve VRCX by allowing anonymous error reporting?</br></br>' +
|
||||||
'• Only enabled in nightly builds.</br>' +
|
'• Only collects crash and error information.</br>' +
|
||||||
'• Can be disabled at anytime in Advanced Settings.',
|
'• No personal data or VRChat information is collected.</br>' +
|
||||||
'Anonymous Error Reporting',
|
'• Only enabled in nightly builds.</br>' +
|
||||||
{
|
'• Can be disabled at anytime in Advanced Settings.',
|
||||||
type: 'warning',
|
title: 'Anonymous Error Reporting'
|
||||||
center: true,
|
})
|
||||||
dangerouslyUseHTMLString: true,
|
.then(async ({ ok }) => {
|
||||||
closeOnClickModal: false,
|
if (!ok) return;
|
||||||
closeOnPressEscape: false,
|
modalStore
|
||||||
distinguishCancelAndClose: true
|
.confirm({
|
||||||
}
|
description:
|
||||||
).catch(() => ({ action: 'cancel' }));
|
'Error reporting setting has been enabled. Would you like to restart VRCX now for the change to take effect?',
|
||||||
|
title: 'Restart Required',
|
||||||
|
confirmText: 'Restart Now',
|
||||||
|
cancelText: 'Later'
|
||||||
|
})
|
||||||
|
.then(async ({ ok }) => {
|
||||||
|
if (!ok) return;
|
||||||
|
|
||||||
if (consentAction === 'cancel') return;
|
sentryErrorReporting.value = true;
|
||||||
|
configRepository.setBool('VRCX_SentryEnabled', true);
|
||||||
|
|
||||||
const { action: restartAction } = await ElMessageBox.confirm(
|
VRCXUpdaterStore.restartVRCX(false);
|
||||||
'Error reporting setting has been enabled. Would you like to restart VRCX now for the change to take effect?',
|
});
|
||||||
'Restart Required',
|
});
|
||||||
{
|
|
||||||
confirmButtonText: 'Restart Now',
|
|
||||||
cancelButtonText: 'Later',
|
|
||||||
type: 'warning',
|
|
||||||
center: true,
|
|
||||||
closeOnClickModal: false,
|
|
||||||
closeOnPressEscape: false
|
|
||||||
}
|
|
||||||
).catch(() => ({ action: 'cancel' }));
|
|
||||||
|
|
||||||
if (restartAction === 'cancel') return;
|
|
||||||
|
|
||||||
sentryErrorReporting.value = true;
|
|
||||||
configRepository.setBool('VRCX_SentryEnabled', true);
|
|
||||||
|
|
||||||
VRCXUpdaterStore.restartVRCX(false);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
async function setSentryErrorReporting() {
|
async function setSentryErrorReporting() {
|
||||||
if (VRCXUpdaterStore.branch !== 'Nightly') return;
|
if (VRCXUpdaterStore.branch !== 'Nightly') return;
|
||||||
|
|
||||||
const { action: restartAction } = await ElMessageBox.confirm(
|
modalStore
|
||||||
'Error reporting setting has been disabled. Would you like to restart VRCX now for the change to take effect?',
|
.confirm({
|
||||||
'Restart Required',
|
description:
|
||||||
{
|
'Error reporting setting has been disabled. Would you like to restart VRCX now for the change to take effect?',
|
||||||
confirmButtonText: 'Restart Now',
|
title: 'Restart Required',
|
||||||
cancelButtonText: 'Later',
|
confirmText: 'Restart Now',
|
||||||
type: 'info',
|
cancelText: 'Later'
|
||||||
center: true
|
})
|
||||||
}
|
.then(async ({ ok }) => {
|
||||||
).catch(() => ({ action: 'cancel' }));
|
if (!ok) return;
|
||||||
|
|
||||||
if (restartAction === 'cancel') return;
|
sentryErrorReporting.value = !sentryErrorReporting.value;
|
||||||
|
await configRepository.setBool(
|
||||||
sentryErrorReporting.value = !sentryErrorReporting.value;
|
'VRCX_SentryEnabled',
|
||||||
await configRepository.setBool(
|
sentryErrorReporting.value
|
||||||
'VRCX_SentryEnabled',
|
);
|
||||||
sentryErrorReporting.value
|
VRCXUpdaterStore.restartVRCX(false);
|
||||||
);
|
});
|
||||||
VRCXUpdaterStore.restartVRCX(false);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
async function getSqliteTableSizes() {
|
async function getSqliteTableSizes() {
|
||||||
@@ -735,96 +727,87 @@ export const useAdvancedSettingsStore = defineStore('AdvancedSettings', () => {
|
|||||||
|
|
||||||
function cropPrintsChanged() {
|
function cropPrintsChanged() {
|
||||||
if (!cropInstancePrints.value) return;
|
if (!cropInstancePrints.value) return;
|
||||||
ElMessageBox.confirm(
|
modalStore
|
||||||
t(
|
.confirm({
|
||||||
'view.settings.advanced.advanced.save_instance_prints_to_file.crop_convert_old'
|
description: t(
|
||||||
),
|
'view.settings.advanced.advanced.save_instance_prints_to_file.crop_convert_old'
|
||||||
{
|
),
|
||||||
confirmButtonText: t(
|
title: '',
|
||||||
|
confirmText: t(
|
||||||
'view.settings.advanced.advanced.save_instance_prints_to_file.crop_convert_old_confirm'
|
'view.settings.advanced.advanced.save_instance_prints_to_file.crop_convert_old_confirm'
|
||||||
),
|
),
|
||||||
cancelButtonText: t(
|
cancelText: t(
|
||||||
'view.settings.advanced.advanced.save_instance_prints_to_file.crop_convert_old_cancel'
|
'view.settings.advanced.advanced.save_instance_prints_to_file.crop_convert_old_cancel'
|
||||||
),
|
)
|
||||||
type: 'info',
|
})
|
||||||
showInput: false
|
.then(async ({ ok }) => {
|
||||||
}
|
if (!ok) return;
|
||||||
)
|
const msgBox = toast.warning(
|
||||||
.then(async ({ action }) => {
|
'Batch print cropping in progress...',
|
||||||
if (action === 'confirm') {
|
{ duration: Infinity, position: 'bottom-right' }
|
||||||
const msgBox = toast.warning(
|
);
|
||||||
'Batch print cropping in progress...',
|
try {
|
||||||
{ duration: Infinity, position: 'bottom-right' }
|
await AppApi.CropAllPrints(ugcFolderPath.value);
|
||||||
);
|
toast.success('Batch print cropping complete');
|
||||||
try {
|
} catch (err) {
|
||||||
await AppApi.CropAllPrints(ugcFolderPath.value);
|
console.error(err);
|
||||||
toast.success('Batch print cropping complete');
|
toast.error(`Batch print cropping failed: ${err}`);
|
||||||
} catch (err) {
|
} finally {
|
||||||
console.error(err);
|
toast.dismiss(msgBox);
|
||||||
toast.error(`Batch print cropping failed: ${err}`);
|
|
||||||
} finally {
|
|
||||||
toast.dismiss(msgBox);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
.catch(() => {});
|
.catch(() => {});
|
||||||
}
|
}
|
||||||
|
|
||||||
function askDeleteAllScreenshotMetadata() {
|
function askDeleteAllScreenshotMetadata() {
|
||||||
ElMessageBox.confirm(
|
modalStore
|
||||||
t(
|
.confirm({
|
||||||
'view.settings.advanced.advanced.delete_all_screenshot_metadata.ask'
|
description: t(
|
||||||
),
|
'view.settings.advanced.advanced.delete_all_screenshot_metadata.ask'
|
||||||
{
|
),
|
||||||
confirmButtonText: t(
|
title: '',
|
||||||
|
confirmText: t(
|
||||||
'view.settings.advanced.advanced.delete_all_screenshot_metadata.confirm_yes'
|
'view.settings.advanced.advanced.delete_all_screenshot_metadata.confirm_yes'
|
||||||
),
|
),
|
||||||
cancelButtonText: t(
|
cancelText: t(
|
||||||
'view.settings.advanced.advanced.delete_all_screenshot_metadata.confirm_no'
|
'view.settings.advanced.advanced.delete_all_screenshot_metadata.confirm_no'
|
||||||
),
|
)
|
||||||
type: 'warning',
|
})
|
||||||
showInput: false
|
.then(({ ok }) => {
|
||||||
}
|
if (!ok) return;
|
||||||
)
|
deleteAllScreenshotMetadata();
|
||||||
.then(({ action }) => {
|
|
||||||
if (action === 'confirm') {
|
|
||||||
deleteAllScreenshotMetadata();
|
|
||||||
}
|
|
||||||
})
|
})
|
||||||
.catch(() => {});
|
.catch(() => {});
|
||||||
}
|
}
|
||||||
|
|
||||||
function deleteAllScreenshotMetadata() {
|
function deleteAllScreenshotMetadata() {
|
||||||
ElMessageBox.confirm(
|
modalStore
|
||||||
t(
|
.confirm({
|
||||||
'view.settings.advanced.advanced.delete_all_screenshot_metadata.confirm'
|
description: t(
|
||||||
),
|
'view.settings.advanced.advanced.delete_all_screenshot_metadata.confirm'
|
||||||
{
|
),
|
||||||
confirmButtonText: t(
|
title: '',
|
||||||
|
confirmText: t(
|
||||||
'view.settings.advanced.advanced.save_instance_prints_to_file.crop_convert_old_confirm'
|
'view.settings.advanced.advanced.save_instance_prints_to_file.crop_convert_old_confirm'
|
||||||
),
|
),
|
||||||
cancelButtonText: t(
|
cancelText: t(
|
||||||
'view.settings.advanced.advanced.save_instance_prints_to_file.crop_convert_old_cancel'
|
'view.settings.advanced.advanced.save_instance_prints_to_file.crop_convert_old_cancel'
|
||||||
),
|
)
|
||||||
type: 'warning',
|
})
|
||||||
showInput: false
|
.then(async ({ ok }) => {
|
||||||
}
|
if (!ok) return;
|
||||||
)
|
const msgBox = toast.warning(
|
||||||
.then(async ({ action }) => {
|
'Batch metadata removal in progress...',
|
||||||
if (action === 'confirm') {
|
{ duration: Infinity, position: 'bottom-right' }
|
||||||
const msgBox = toast.warning(
|
);
|
||||||
'Batch metadata removal in progress...',
|
try {
|
||||||
{ duration: Infinity, position: 'bottom-right' }
|
await AppApi.DeleteAllScreenshotMetadata();
|
||||||
);
|
toast.success('Batch metadata removal complete');
|
||||||
try {
|
} catch (err) {
|
||||||
await AppApi.DeleteAllScreenshotMetadata();
|
console.error(err);
|
||||||
toast.success('Batch metadata removal complete');
|
toast.error(`Batch metadata removal failed: ${err}`);
|
||||||
} catch (err) {
|
} finally {
|
||||||
console.error(err);
|
toast.dismiss(msgBox);
|
||||||
toast.error(`Batch metadata removal failed: ${err}`);
|
|
||||||
} finally {
|
|
||||||
toast.dismiss(msgBox);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
.catch(() => {});
|
.catch(() => {});
|
||||||
|
|||||||
@@ -1,5 +1,4 @@
|
|||||||
import { reactive, ref, watch } from 'vue';
|
import { reactive, ref, watch } from 'vue';
|
||||||
import { ElMessageBox } from 'element-plus';
|
|
||||||
import { defineStore } from 'pinia';
|
import { defineStore } from 'pinia';
|
||||||
import { toast } from 'vue-sonner';
|
import { toast } from 'vue-sonner';
|
||||||
import { useI18n } from 'vue-i18n';
|
import { useI18n } from 'vue-i18n';
|
||||||
@@ -26,6 +25,7 @@ import { useGameStore } from './game';
|
|||||||
import { useGroupStore } from './group';
|
import { useGroupStore } from './group';
|
||||||
import { useInstanceStore } from './instance';
|
import { useInstanceStore } from './instance';
|
||||||
import { useLocationStore } from './location';
|
import { useLocationStore } from './location';
|
||||||
|
import { useModalStore } from './modal';
|
||||||
import { useNotificationStore } from './notification';
|
import { useNotificationStore } from './notification';
|
||||||
import { usePhotonStore } from './photon';
|
import { usePhotonStore } from './photon';
|
||||||
import { useSearchStore } from './search';
|
import { useSearchStore } from './search';
|
||||||
@@ -58,6 +58,7 @@ export const useVrcxStore = defineStore('Vrcx', () => {
|
|||||||
const vrcStatusStore = useVrcStatusStore();
|
const vrcStatusStore = useVrcStatusStore();
|
||||||
const galleryStore = useGalleryStore();
|
const galleryStore = useGalleryStore();
|
||||||
const { t } = useI18n();
|
const { t } = useI18n();
|
||||||
|
const modalStore = useModalStore();
|
||||||
|
|
||||||
const state = reactive({
|
const state = reactive({
|
||||||
databaseVersion: 0,
|
databaseVersion: 0,
|
||||||
@@ -711,10 +712,10 @@ export const useVrcxStore = defineStore('Vrcx', () => {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
// popup message about auto restore
|
// popup message about auto restore
|
||||||
ElMessageBox.alert(
|
modalStore.alert({
|
||||||
t('dialog.registry_backup.restore_prompt'),
|
description: t('dialog.registry_backup.restore_prompt'),
|
||||||
t('dialog.registry_backup.header')
|
title: t('dialog.registry_backup.header')
|
||||||
).catch(() => {});
|
});
|
||||||
showRegistryBackupDialog();
|
showRegistryBackupDialog();
|
||||||
await AppApi.FocusWindow();
|
await AppApi.FocusWindow();
|
||||||
await configRepository.setString(
|
await configRepository.setString(
|
||||||
|
|||||||
@@ -142,16 +142,21 @@
|
|||||||
import { Field, FieldContent, FieldDescription, FieldGroup, FieldLabel } from '@/components/ui/field';
|
import { Field, FieldContent, FieldDescription, FieldGroup, FieldLabel } from '@/components/ui/field';
|
||||||
import { NumberField, NumberFieldContent, NumberFieldInput } from '@/components/ui/number-field';
|
import { NumberField, NumberFieldContent, NumberFieldInput } from '@/components/ui/number-field';
|
||||||
import { Button } from '@/components/ui/button';
|
import { Button } from '@/components/ui/button';
|
||||||
import { ElMessageBox } from 'element-plus';
|
|
||||||
import { Settings } from 'lucide-vue-next';
|
|
||||||
import { Progress } from '@/components/ui/progress';
|
import { Progress } from '@/components/ui/progress';
|
||||||
|
import { Settings } from 'lucide-vue-next';
|
||||||
import { Spinner } from '@/components/ui/spinner';
|
import { Spinner } from '@/components/ui/spinner';
|
||||||
import { onBeforeRouteLeave } from 'vue-router';
|
import { onBeforeRouteLeave } from 'vue-router';
|
||||||
import { storeToRefs } from 'pinia';
|
import { storeToRefs } from 'pinia';
|
||||||
import { toast } from 'vue-sonner';
|
import { toast } from 'vue-sonner';
|
||||||
import { useI18n } from 'vue-i18n';
|
import { useI18n } from 'vue-i18n';
|
||||||
|
|
||||||
import { useAppearanceSettingsStore, useChartsStore, useFriendStore, useUserStore } from '../../../stores';
|
import {
|
||||||
|
useAppearanceSettingsStore,
|
||||||
|
useChartsStore,
|
||||||
|
useFriendStore,
|
||||||
|
useModalStore,
|
||||||
|
useUserStore
|
||||||
|
} from '../../../stores';
|
||||||
import { applyForceOverrides, computeForceOptions, useMutualGraphChart } from '../composables/useMutualGraphChart';
|
import { applyForceOverrides, computeForceOptions, useMutualGraphChart } from '../composables/useMutualGraphChart';
|
||||||
import { createRateLimiter, executeWithBackoff } from '../../../shared/utils';
|
import { createRateLimiter, executeWithBackoff } from '../../../shared/utils';
|
||||||
import { database } from '../../../service/database';
|
import { database } from '../../../service/database';
|
||||||
@@ -164,6 +169,7 @@
|
|||||||
const { t } = useI18n();
|
const { t } = useI18n();
|
||||||
const friendStore = useFriendStore();
|
const friendStore = useFriendStore();
|
||||||
const userStore = useUserStore();
|
const userStore = useUserStore();
|
||||||
|
const modalStore = useModalStore();
|
||||||
const chartsStore = useChartsStore();
|
const chartsStore = useChartsStore();
|
||||||
const appearanceStore = useAppearanceSettingsStore();
|
const appearanceStore = useAppearanceSettingsStore();
|
||||||
const { friends } = storeToRefs(friendStore);
|
const { friends } = storeToRefs(friendStore);
|
||||||
@@ -396,39 +402,35 @@
|
|||||||
if (isFetching.value || hasFetched.value || !totalFriends.value) {
|
if (isFetching.value || hasFetched.value || !totalFriends.value) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
try {
|
|
||||||
await ElMessageBox.confirm(
|
modalStore
|
||||||
t('view.charts.mutual_friend.prompt.message'),
|
.confirm({
|
||||||
t('view.charts.mutual_friend.prompt.title'),
|
description: t('view.charts.mutual_friend.prompt.message'),
|
||||||
{
|
title: t('view.charts.mutual_friend.prompt.title'),
|
||||||
confirmButtonText: t('view.charts.mutual_friend.prompt.confirm'),
|
confirmText: t('view.charts.mutual_friend.prompt.confirm'),
|
||||||
cancelButtonText: t('view.charts.mutual_friend.prompt.cancel'),
|
cancelText: t('view.charts.mutual_friend.prompt.cancel')
|
||||||
type: 'warning'
|
})
|
||||||
}
|
.then(async ({ ok }) => {
|
||||||
);
|
if (!ok) return;
|
||||||
await startFetch();
|
|
||||||
} catch {
|
await startFetch();
|
||||||
// cancelled
|
});
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function promptEnableMutualFriendsSharing() {
|
function promptEnableMutualFriendsSharing() {
|
||||||
ElMessageBox.confirm(
|
modalStore
|
||||||
t('view.charts.mutual_friend.enable_sharing_prompt.message'),
|
.confirm({
|
||||||
t('view.charts.mutual_friend.enable_sharing_prompt.title'),
|
description: t('view.charts.mutual_friend.enable_sharing_prompt.message'),
|
||||||
{
|
title: t('view.charts.mutual_friend.enable_sharing_prompt.title'),
|
||||||
confirmButtonText: t('view.charts.mutual_friend.enable_sharing_prompt.confirm'),
|
confirmText: t('view.charts.mutual_friend.enable_sharing_prompt.confirm'),
|
||||||
cancelButtonText: t('view.charts.mutual_friend.enable_sharing_prompt.cancel'),
|
cancelText: t('view.charts.mutual_friend.enable_sharing_prompt.cancel')
|
||||||
type: 'info'
|
})
|
||||||
}
|
.then(({ ok }) => {
|
||||||
)
|
if (!ok) return;
|
||||||
.then(() => {
|
|
||||||
userStore.toggleSharedConnectionsOptOut();
|
userStore.toggleSharedConnectionsOptOut();
|
||||||
promptInitialFetch();
|
promptInitialFetch();
|
||||||
})
|
})
|
||||||
.catch(() => {
|
.catch(() => {});
|
||||||
// cancelled
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function cancelFetch() {
|
function cancelFetch() {
|
||||||
|
|||||||
@@ -521,18 +521,7 @@
|
|||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup>
|
<script setup>
|
||||||
import {
|
import { computed, markRaw, nextTick, onBeforeMount, onBeforeUnmount, onMounted, reactive, ref, watch } from 'vue';
|
||||||
computed,
|
|
||||||
h,
|
|
||||||
markRaw,
|
|
||||||
nextTick,
|
|
||||||
onBeforeMount,
|
|
||||||
onBeforeUnmount,
|
|
||||||
onMounted,
|
|
||||||
reactive,
|
|
||||||
ref,
|
|
||||||
watch
|
|
||||||
} from 'vue';
|
|
||||||
import { Ellipsis, Loader, RefreshCcw } from 'lucide-vue-next';
|
import { Ellipsis, Loader, RefreshCcw } from 'lucide-vue-next';
|
||||||
import { MoreFilled, Plus, Refresh } from '@element-plus/icons-vue';
|
import { MoreFilled, Plus, Refresh } from '@element-plus/icons-vue';
|
||||||
import { InputGroupField, InputGroupSearch } from '@/components/ui/input-group';
|
import { InputGroupField, InputGroupSearch } from '@/components/ui/input-group';
|
||||||
@@ -558,7 +547,13 @@
|
|||||||
DropdownMenuSeparator,
|
DropdownMenuSeparator,
|
||||||
DropdownMenuTrigger
|
DropdownMenuTrigger
|
||||||
} from '../../components/ui/dropdown-menu';
|
} from '../../components/ui/dropdown-menu';
|
||||||
import { useAppearanceSettingsStore, useAvatarStore, useFavoriteStore, useUserStore } from '../../stores';
|
import {
|
||||||
|
useAppearanceSettingsStore,
|
||||||
|
useAvatarStore,
|
||||||
|
useFavoriteStore,
|
||||||
|
useModalStore,
|
||||||
|
useUserStore
|
||||||
|
} from '../../stores';
|
||||||
import { Popover, PopoverContent, PopoverTrigger } from '../../components/ui/popover';
|
import { Popover, PopoverContent, PopoverTrigger } from '../../components/ui/popover';
|
||||||
import { ResizableHandle, ResizablePanel, ResizablePanelGroup } from '../../components/ui/resizable';
|
import { ResizableHandle, ResizablePanel, ResizablePanelGroup } from '../../components/ui/resizable';
|
||||||
import { avatarRequest, favoriteRequest } from '../../api';
|
import { avatarRequest, favoriteRequest } from '../../api';
|
||||||
@@ -597,6 +592,7 @@
|
|||||||
const { sortFavorites } = storeToRefs(useAppearanceSettingsStore());
|
const { sortFavorites } = storeToRefs(useAppearanceSettingsStore());
|
||||||
const { setSortFavorites } = useAppearanceSettingsStore();
|
const { setSortFavorites } = useAppearanceSettingsStore();
|
||||||
const favoriteStore = useFavoriteStore();
|
const favoriteStore = useFavoriteStore();
|
||||||
|
const modalStore = useModalStore();
|
||||||
const {
|
const {
|
||||||
favoriteAvatars,
|
favoriteAvatars,
|
||||||
favoriteAvatarGroups,
|
favoriteAvatarGroups,
|
||||||
@@ -1183,26 +1179,22 @@
|
|||||||
showAvatarImportDialog();
|
showAvatarImportDialog();
|
||||||
}
|
}
|
||||||
|
|
||||||
function showAvatarBulkUnfavoriteSelectionConfirm() {
|
async function showAvatarBulkUnfavoriteSelectionConfirm() {
|
||||||
if (!selectedFavoriteAvatars.value.length) {
|
if (!selectedFavoriteAvatars.value.length) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
const total = selectedFavoriteAvatars.value.length;
|
const total = selectedFavoriteAvatars.value.length;
|
||||||
ElMessageBox.confirm(
|
|
||||||
`Are you sure you want to unfavorite ${total} favorites?\n This action cannot be undone.`,
|
const result = await modalStore.confirm({
|
||||||
`Delete ${total} favorites?`,
|
description: `Are you sure you want to unfavorite ${total} favorites?\nThis action cannot be undone.`,
|
||||||
{
|
title: `Delete ${total} favorites?`
|
||||||
confirmButtonText: 'Confirm',
|
});
|
||||||
cancelButtonText: 'Cancel',
|
|
||||||
type: 'info'
|
if (!result.ok) {
|
||||||
}
|
return;
|
||||||
)
|
}
|
||||||
.then((action) => {
|
|
||||||
if (action === 'confirm') {
|
bulkUnfavoriteSelectedAvatars([...selectedFavoriteAvatars.value]);
|
||||||
bulkUnfavoriteSelectedAvatars([...selectedFavoriteAvatars.value]);
|
|
||||||
}
|
|
||||||
})
|
|
||||||
.catch(() => {});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function bulkUnfavoriteSelectedAvatars(ids) {
|
function bulkUnfavoriteSelectedAvatars(ids) {
|
||||||
@@ -1252,17 +1244,14 @@
|
|||||||
async function handleCheckInvalidAvatars(groupName) {
|
async function handleCheckInvalidAvatars(groupName) {
|
||||||
handleGroupMenuVisible(localGroupMenuKey(groupName), false);
|
handleGroupMenuVisible(localGroupMenuKey(groupName), false);
|
||||||
|
|
||||||
try {
|
const startCheckResult = await modalStore.confirm({
|
||||||
await ElMessageBox.confirm(
|
description: t('view.favorite.avatars.check_description'),
|
||||||
t('view.favorite.avatars.check_description'),
|
title: t('view.favorite.avatars.check_invalid'),
|
||||||
t('view.favorite.avatars.check_invalid'),
|
confirmText: t('confirm.confirm_button'),
|
||||||
{
|
cancelText: t('confirm.cancel_button')
|
||||||
confirmButtonText: t('confirm.confirm_button'),
|
});
|
||||||
cancelButtonText: t('confirm.cancel_button'),
|
|
||||||
type: 'info'
|
if (!startCheckResult.ok) {
|
||||||
}
|
|
||||||
);
|
|
||||||
} catch {
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1299,54 +1288,29 @@
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const confirmDelete = await ElMessageBox.confirm(
|
const invalidIdsText = result.invalidIds.join('\n');
|
||||||
h('div', [
|
|
||||||
h(
|
|
||||||
'p',
|
|
||||||
{ style: 'margin-bottom: 12px;' },
|
|
||||||
t('view.favorite.avatars.confirm_delete_description', { count: result.invalid })
|
|
||||||
),
|
|
||||||
h(
|
|
||||||
'div',
|
|
||||||
{ style: 'margin-top: 12px; margin-bottom: 8px; font-weight: 600;' },
|
|
||||||
t('view.favorite.avatars.removed_list_header')
|
|
||||||
),
|
|
||||||
h(
|
|
||||||
'div',
|
|
||||||
{
|
|
||||||
style: 'max-height: 200px; overflow-y: auto; background: var(--el-fill-color-lighter); padding: 8px; border-radius: 4px;'
|
|
||||||
},
|
|
||||||
result.invalidIds.map((id) =>
|
|
||||||
h('div', { style: 'font-family: monospace; font-size: 12px; padding: 2px 0;' }, id)
|
|
||||||
)
|
|
||||||
)
|
|
||||||
]),
|
|
||||||
t('view.favorite.avatars.confirm_delete_invalid'),
|
|
||||||
{
|
|
||||||
confirmButtonText: t('confirm.confirm_button'),
|
|
||||||
cancelButtonText: t('view.favorite.avatars.copy_removed_ids'),
|
|
||||||
distinguishCancelAndClose: true,
|
|
||||||
type: 'warning',
|
|
||||||
beforeClose: (action, instance, done) => {
|
|
||||||
if (action === 'cancel') {
|
|
||||||
navigator.clipboard
|
|
||||||
.writeText(result.invalidIds.join('\n'))
|
|
||||||
.then(() => {
|
|
||||||
toast.success(t('view.favorite.avatars.copied_ids'));
|
|
||||||
})
|
|
||||||
.catch(() => {
|
|
||||||
toast.error(t('view.favorite.avatars.copy_failed'));
|
|
||||||
});
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
done();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
)
|
|
||||||
.then(() => true)
|
|
||||||
.catch(() => false);
|
|
||||||
|
|
||||||
if (!confirmDelete) {
|
const confirmDeleteResult = await modalStore.confirm({
|
||||||
|
description:
|
||||||
|
`${t('view.favorite.avatars.confirm_delete_description', { count: result.invalid })}` +
|
||||||
|
`\n\n${t('view.favorite.avatars.removed_list_header')}\n` +
|
||||||
|
invalidIdsText,
|
||||||
|
title: t('view.favorite.avatars.confirm_delete_invalid'),
|
||||||
|
confirmText: t('confirm.confirm_button'),
|
||||||
|
cancelText: t('view.favorite.avatars.copy_removed_ids')
|
||||||
|
});
|
||||||
|
|
||||||
|
if (!confirmDeleteResult.ok) {
|
||||||
|
if (confirmDeleteResult.reason === 'cancel') {
|
||||||
|
navigator.clipboard
|
||||||
|
.writeText(invalidIdsText)
|
||||||
|
.then(() => {
|
||||||
|
toast.success(t('view.favorite.avatars.copied_ids'));
|
||||||
|
})
|
||||||
|
.catch(() => {
|
||||||
|
toast.error(t('view.favorite.avatars.copy_failed'));
|
||||||
|
});
|
||||||
|
}
|
||||||
toast.info(t('view.favorite.avatars.delete_cancelled'));
|
toast.info(t('view.favorite.avatars.delete_cancelled'));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -1434,18 +1398,16 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
function clearFavoriteGroup(ctx) {
|
function clearFavoriteGroup(ctx) {
|
||||||
ElMessageBox.confirm('Continue? Clear Group', 'Confirm', {
|
modalStore
|
||||||
confirmButtonText: 'Confirm',
|
.confirm({
|
||||||
cancelButtonText: 'Cancel',
|
description: 'Continue? Clear Group',
|
||||||
type: 'info'
|
title: 'Confirm'
|
||||||
})
|
})
|
||||||
.then((action) => {
|
.then(() => {
|
||||||
if (action === 'confirm') {
|
favoriteRequest.clearFavoriteGroup({
|
||||||
favoriteRequest.clearFavoriteGroup({
|
type: ctx.type,
|
||||||
type: ctx.type,
|
group: ctx.name
|
||||||
group: ctx.name
|
});
|
||||||
});
|
|
||||||
}
|
|
||||||
})
|
})
|
||||||
.catch(() => {});
|
.catch(() => {});
|
||||||
}
|
}
|
||||||
@@ -1477,16 +1439,12 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
function promptLocalAvatarFavoriteGroupDelete(group) {
|
function promptLocalAvatarFavoriteGroupDelete(group) {
|
||||||
ElMessageBox.confirm(`Delete Group? ${group}`, 'Confirm', {
|
modalStore
|
||||||
confirmButtonText: 'Confirm',
|
.confirm({
|
||||||
cancelButtonText: 'Cancel',
|
description: `Delete Group? ${group}`,
|
||||||
type: 'info'
|
title: 'Confirm'
|
||||||
})
|
|
||||||
.then((action) => {
|
|
||||||
if (action === 'confirm') {
|
|
||||||
deleteLocalAvatarFavoriteGroup(group);
|
|
||||||
}
|
|
||||||
})
|
})
|
||||||
|
.then(() => deleteLocalAvatarFavoriteGroup(group))
|
||||||
.catch(() => {});
|
.catch(() => {});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -331,9 +331,9 @@
|
|||||||
DropdownMenuSeparator,
|
DropdownMenuSeparator,
|
||||||
DropdownMenuTrigger
|
DropdownMenuTrigger
|
||||||
} from '../../components/ui/dropdown-menu';
|
} from '../../components/ui/dropdown-menu';
|
||||||
|
import { useAppearanceSettingsStore, useFavoriteStore, useModalStore, useUserStore } from '../../stores';
|
||||||
import { Popover, PopoverContent, PopoverTrigger } from '../../components/ui/popover';
|
import { Popover, PopoverContent, PopoverTrigger } from '../../components/ui/popover';
|
||||||
import { ResizableHandle, ResizablePanel, ResizablePanelGroup } from '../../components/ui/resizable';
|
import { ResizableHandle, ResizablePanel, ResizablePanelGroup } from '../../components/ui/resizable';
|
||||||
import { useAppearanceSettingsStore, useFavoriteStore, useUserStore } from '../../stores';
|
|
||||||
import { Badge } from '../../components/ui/badge';
|
import { Badge } from '../../components/ui/badge';
|
||||||
import { Slider } from '../../components/ui/slider';
|
import { Slider } from '../../components/ui/slider';
|
||||||
import { Switch } from '../../components/ui/switch';
|
import { Switch } from '../../components/ui/switch';
|
||||||
@@ -358,6 +358,7 @@
|
|||||||
const { sortFavorites } = storeToRefs(useAppearanceSettingsStore());
|
const { sortFavorites } = storeToRefs(useAppearanceSettingsStore());
|
||||||
const { setSortFavorites } = useAppearanceSettingsStore();
|
const { setSortFavorites } = useAppearanceSettingsStore();
|
||||||
const favoriteStore = useFavoriteStore();
|
const favoriteStore = useFavoriteStore();
|
||||||
|
const modalStore = useModalStore();
|
||||||
const {
|
const {
|
||||||
favoriteFriends,
|
favoriteFriends,
|
||||||
favoriteFriendGroups,
|
favoriteFriendGroups,
|
||||||
@@ -751,20 +752,12 @@
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
const total = selectedFavoriteFriends.value.length;
|
const total = selectedFavoriteFriends.value.length;
|
||||||
ElMessageBox.confirm(
|
modalStore
|
||||||
`Are you sure you want to unfavorite ${total} favorites?\n This action cannot be undone.`,
|
.confirm({
|
||||||
`Delete ${total} favorites?`,
|
description: `Are you sure you want to unfavorite ${total} favorites?\n This action cannot be undone.`,
|
||||||
{
|
title: `Delete ${total} favorites?`
|
||||||
confirmButtonText: 'Confirm',
|
|
||||||
cancelButtonText: 'Cancel',
|
|
||||||
type: 'info'
|
|
||||||
}
|
|
||||||
)
|
|
||||||
.then((action) => {
|
|
||||||
if (action === 'confirm') {
|
|
||||||
bulkUnfavoriteSelectedFriends([...selectedFavoriteFriends.value]);
|
|
||||||
}
|
|
||||||
})
|
})
|
||||||
|
.then(({ ok }) => ok && bulkUnfavoriteSelectedFriends([...selectedFavoriteFriends.value]))
|
||||||
.catch(() => {});
|
.catch(() => {});
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -779,18 +772,16 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
function clearFavoriteGroup(ctx) {
|
function clearFavoriteGroup(ctx) {
|
||||||
ElMessageBox.confirm('Continue? Clear Group', 'Confirm', {
|
modalStore
|
||||||
confirmButtonText: 'Confirm',
|
.confirm({
|
||||||
cancelButtonText: 'Cancel',
|
description: 'Continue? Clear Group',
|
||||||
type: 'info'
|
title: 'Confirm'
|
||||||
})
|
})
|
||||||
.then((action) => {
|
.then(() => {
|
||||||
if (action === 'confirm') {
|
favoriteRequest.clearFavoriteGroup({
|
||||||
favoriteRequest.clearFavoriteGroup({
|
type: ctx.type,
|
||||||
type: ctx.type,
|
group: ctx.name
|
||||||
group: ctx.name
|
});
|
||||||
});
|
|
||||||
}
|
|
||||||
})
|
})
|
||||||
.catch(() => {});
|
.catch(() => {});
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -461,9 +461,9 @@
|
|||||||
DropdownMenuSeparator,
|
DropdownMenuSeparator,
|
||||||
DropdownMenuTrigger
|
DropdownMenuTrigger
|
||||||
} from '../../components/ui/dropdown-menu';
|
} from '../../components/ui/dropdown-menu';
|
||||||
|
import { useAppearanceSettingsStore, useFavoriteStore, useModalStore, useWorldStore } from '../../stores';
|
||||||
import { Popover, PopoverContent, PopoverTrigger } from '../../components/ui/popover';
|
import { Popover, PopoverContent, PopoverTrigger } from '../../components/ui/popover';
|
||||||
import { ResizableHandle, ResizablePanel, ResizablePanelGroup } from '../../components/ui/resizable';
|
import { ResizableHandle, ResizablePanel, ResizablePanelGroup } from '../../components/ui/resizable';
|
||||||
import { useAppearanceSettingsStore, useFavoriteStore, useWorldStore } from '../../stores';
|
|
||||||
import { favoriteRequest, worldRequest } from '../../api';
|
import { favoriteRequest, worldRequest } from '../../api';
|
||||||
import { Badge } from '../../components/ui/badge';
|
import { Badge } from '../../components/ui/badge';
|
||||||
import { Slider } from '../../components/ui/slider';
|
import { Slider } from '../../components/ui/slider';
|
||||||
@@ -490,6 +490,7 @@
|
|||||||
const { sortFavorites } = storeToRefs(useAppearanceSettingsStore());
|
const { sortFavorites } = storeToRefs(useAppearanceSettingsStore());
|
||||||
const { setSortFavorites } = useAppearanceSettingsStore();
|
const { setSortFavorites } = useAppearanceSettingsStore();
|
||||||
const favoriteStore = useFavoriteStore();
|
const favoriteStore = useFavoriteStore();
|
||||||
|
const modalStore = useModalStore();
|
||||||
const {
|
const {
|
||||||
favoriteWorlds,
|
favoriteWorlds,
|
||||||
favoriteWorldGroups,
|
favoriteWorldGroups,
|
||||||
@@ -1054,21 +1055,13 @@
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
const total = selectedFavoriteWorlds.value.length;
|
const total = selectedFavoriteWorlds.value.length;
|
||||||
ElMessageBox.confirm(
|
modalStore
|
||||||
`Are you sure you want to unfavorite ${total} favorites?
|
.confirm({
|
||||||
|
description: `Are you sure you want to unfavorite ${total} favorites?
|
||||||
This action cannot be undone.`,
|
This action cannot be undone.`,
|
||||||
`Delete ${total} favorites?`,
|
title: `Delete ${total} favorites?`
|
||||||
{
|
|
||||||
confirmButtonText: 'Confirm',
|
|
||||||
cancelButtonText: 'Cancel',
|
|
||||||
type: 'info'
|
|
||||||
}
|
|
||||||
)
|
|
||||||
.then((action) => {
|
|
||||||
if (action === 'confirm') {
|
|
||||||
bulkUnfavoriteSelectedWorlds([...selectedFavoriteWorlds.value]);
|
|
||||||
}
|
|
||||||
})
|
})
|
||||||
|
.then(() => bulkUnfavoriteSelectedWorlds([...selectedFavoriteWorlds.value]))
|
||||||
.catch(() => {});
|
.catch(() => {});
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1175,32 +1168,26 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
function promptLocalWorldFavoriteGroupDelete(group) {
|
function promptLocalWorldFavoriteGroupDelete(group) {
|
||||||
ElMessageBox.confirm(`Delete Group? ${group}`, 'Confirm', {
|
modalStore
|
||||||
confirmButtonText: 'Confirm',
|
.confirm({
|
||||||
cancelButtonText: 'Cancel',
|
description: `Delete Group? ${group}`,
|
||||||
type: 'info'
|
title: 'Confirm'
|
||||||
})
|
|
||||||
.then((action) => {
|
|
||||||
if (action === 'confirm') {
|
|
||||||
deleteLocalWorldFavoriteGroup(group);
|
|
||||||
}
|
|
||||||
})
|
})
|
||||||
|
.then(() => deleteLocalWorldFavoriteGroup(group))
|
||||||
.catch(() => {});
|
.catch(() => {});
|
||||||
}
|
}
|
||||||
|
|
||||||
function clearFavoriteGroup(ctx) {
|
function clearFavoriteGroup(ctx) {
|
||||||
ElMessageBox.confirm('Continue? Clear Group', 'Confirm', {
|
modalStore
|
||||||
confirmButtonText: 'Confirm',
|
.confirm({
|
||||||
cancelButtonText: 'Cancel',
|
description: 'Continue? Clear Group',
|
||||||
type: 'info'
|
title: 'Confirm'
|
||||||
})
|
})
|
||||||
.then((action) => {
|
.then(() => {
|
||||||
if (action === 'confirm') {
|
favoriteRequest.clearFavoriteGroup({
|
||||||
favoriteRequest.clearFavoriteGroup({
|
type: ctx.type,
|
||||||
type: ctx.type,
|
group: ctx.name
|
||||||
group: ctx.name
|
});
|
||||||
});
|
|
||||||
}
|
|
||||||
})
|
})
|
||||||
.catch(() => {});
|
.catch(() => {});
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -108,7 +108,6 @@
|
|||||||
import { Select, SelectContent, SelectGroup, SelectItem, SelectTrigger, SelectValue } from '@/components/ui/select';
|
import { Select, SelectContent, SelectGroup, SelectItem, SelectTrigger, SelectValue } from '@/components/ui/select';
|
||||||
import { computed, nextTick, ref, watch } from 'vue';
|
import { computed, nextTick, ref, watch } from 'vue';
|
||||||
import { Button } from '@/components/ui/button';
|
import { Button } from '@/components/ui/button';
|
||||||
import { ElMessageBox } from 'element-plus';
|
|
||||||
import { InputGroupField } from '@/components/ui/input-group';
|
import { InputGroupField } from '@/components/ui/input-group';
|
||||||
import { Progress } from '@/components/ui/progress';
|
import { Progress } from '@/components/ui/progress';
|
||||||
import { storeToRefs } from 'pinia';
|
import { storeToRefs } from 'pinia';
|
||||||
@@ -119,6 +118,7 @@
|
|||||||
import {
|
import {
|
||||||
useAppearanceSettingsStore,
|
useAppearanceSettingsStore,
|
||||||
useFriendStore,
|
useFriendStore,
|
||||||
|
useModalStore,
|
||||||
useSearchStore,
|
useSearchStore,
|
||||||
useUserStore,
|
useUserStore,
|
||||||
useVrcxStore
|
useVrcxStore
|
||||||
@@ -138,6 +138,7 @@
|
|||||||
const emit = defineEmits(['lookup-user']);
|
const emit = defineEmits(['lookup-user']);
|
||||||
|
|
||||||
const { friends } = storeToRefs(useFriendStore());
|
const { friends } = storeToRefs(useFriendStore());
|
||||||
|
const modalStore = useModalStore();
|
||||||
const { getAllUserStats, getAllUserMutualCount, confirmDeleteFriend, handleFriendDelete } = useFriendStore();
|
const { getAllUserStats, getAllUserMutualCount, confirmDeleteFriend, handleFriendDelete } = useFriendStore();
|
||||||
const { randomUserColours } = storeToRefs(useAppearanceSettingsStore());
|
const { randomUserColours } = storeToRefs(useAppearanceSettingsStore());
|
||||||
const vrcxStore = useVrcxStore();
|
const vrcxStore = useVrcxStore();
|
||||||
@@ -324,25 +325,18 @@
|
|||||||
.filter((item) => selectedFriends.value.has(item.id))
|
.filter((item) => selectedFriends.value.has(item.id))
|
||||||
.map((item) => item.displayName);
|
.map((item) => item.displayName);
|
||||||
if (!pending.length) return;
|
if (!pending.length) return;
|
||||||
ElMessageBox.confirm(
|
const description =
|
||||||
`Are you sure you want to delete ${pending.length} friends?
|
`Are you sure you want to delete ${pending.length} friends?\n` +
|
||||||
This can negatively affect your trust rank,
|
'This can negatively affect your trust rank,\n' +
|
||||||
This action cannot be undone.`,
|
'This action cannot be undone.\n\n' +
|
||||||
`Delete ${pending.length} friends?`,
|
pending.join('\n');
|
||||||
{
|
|
||||||
confirmButtonText: 'Confirm',
|
modalStore
|
||||||
cancelButtonText: 'Cancel',
|
.confirm({
|
||||||
type: 'info',
|
description,
|
||||||
showInput: true,
|
title: `Delete ${pending.length} friends?`
|
||||||
inputType: 'textarea',
|
|
||||||
inputValue: pending.join('\r\n')
|
|
||||||
}
|
|
||||||
)
|
|
||||||
.then(({ action }) => {
|
|
||||||
if (action === 'confirm') {
|
|
||||||
bulkUnfriendSelection();
|
|
||||||
}
|
|
||||||
})
|
})
|
||||||
|
.then(({ ok }) => ok && bulkUnfriendSelection())
|
||||||
.catch(() => {});
|
.catch(() => {});
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -355,9 +349,9 @@
|
|||||||
selectedFriends.value.delete(item.id);
|
selectedFriends.value.delete(item.id);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
ElMessageBox.alert(`Unfriended ${selectedFriends.value.size} friends.`, 'Bulk Unfriend Complete', {
|
modalStore.alert({
|
||||||
confirmButtonText: 'OK',
|
description: `Unfriended ${selectedFriends.value.size} friends.`,
|
||||||
type: 'success'
|
title: 'Bulk Unfriend Complete'
|
||||||
});
|
});
|
||||||
selectedFriends.value.clear();
|
selectedFriends.value.clear();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -47,7 +47,6 @@
|
|||||||
|
|
||||||
<script setup>
|
<script setup>
|
||||||
import { computed, ref, watch } from 'vue';
|
import { computed, ref, watch } from 'vue';
|
||||||
import { ElMessageBox } from 'element-plus';
|
|
||||||
import { storeToRefs } from 'pinia';
|
import { storeToRefs } from 'pinia';
|
||||||
import { useI18n } from 'vue-i18n';
|
import { useI18n } from 'vue-i18n';
|
||||||
|
|
||||||
@@ -61,7 +60,7 @@
|
|||||||
SelectTrigger,
|
SelectTrigger,
|
||||||
SelectValue
|
SelectValue
|
||||||
} from '../../components/ui/select';
|
} from '../../components/ui/select';
|
||||||
import { useAppearanceSettingsStore, useFriendStore, useVrcxStore } from '../../stores';
|
import { useAppearanceSettingsStore, useFriendStore, useModalStore, useVrcxStore } from '../../stores';
|
||||||
import { DataTableLayout } from '../../components/ui/data-table';
|
import { DataTableLayout } from '../../components/ui/data-table';
|
||||||
import { InputGroupField } from '../../components/ui/input-group';
|
import { InputGroupField } from '../../components/ui/input-group';
|
||||||
import { createColumns } from './columns.jsx';
|
import { createColumns } from './columns.jsx';
|
||||||
@@ -74,6 +73,7 @@
|
|||||||
|
|
||||||
const appearanceSettingsStore = useAppearanceSettingsStore();
|
const appearanceSettingsStore = useAppearanceSettingsStore();
|
||||||
const vrcxStore = useVrcxStore();
|
const vrcxStore = useVrcxStore();
|
||||||
|
const modalStore = useModalStore();
|
||||||
const { hideUnfriends } = storeToRefs(appearanceSettingsStore);
|
const { hideUnfriends } = storeToRefs(appearanceSettingsStore);
|
||||||
const { friendLogTable } = storeToRefs(useFriendStore());
|
const { friendLogTable } = storeToRefs(useFriendStore());
|
||||||
|
|
||||||
@@ -149,16 +149,12 @@
|
|||||||
saveTableFilters();
|
saveTableFilters();
|
||||||
}
|
}
|
||||||
function deleteFriendLogPrompt(row) {
|
function deleteFriendLogPrompt(row) {
|
||||||
ElMessageBox.confirm('Continue? Delete Log', 'Confirm', {
|
modalStore
|
||||||
confirmButtonText: 'Confirm',
|
.confirm({
|
||||||
cancelButtonText: 'Cancel',
|
description: 'Continue? Delete Log',
|
||||||
type: 'info'
|
title: 'Confirm'
|
||||||
})
|
|
||||||
.then((action) => {
|
|
||||||
if (action === 'confirm') {
|
|
||||||
deleteFriendLog(row);
|
|
||||||
}
|
|
||||||
})
|
})
|
||||||
|
.then(({ ok }) => ok && deleteFriendLog(row))
|
||||||
.catch(() => {});
|
.catch(() => {});
|
||||||
}
|
}
|
||||||
function deleteFriendLog(row) {
|
function deleteFriendLog(row) {
|
||||||
|
|||||||
@@ -57,14 +57,13 @@
|
|||||||
<script setup>
|
<script setup>
|
||||||
import { Select, SelectContent, SelectGroup, SelectItem, SelectTrigger, SelectValue } from '@/components/ui/select';
|
import { Select, SelectContent, SelectGroup, SelectItem, SelectTrigger, SelectValue } from '@/components/ui/select';
|
||||||
import { computed, ref, watch } from 'vue';
|
import { computed, ref, watch } from 'vue';
|
||||||
import { ElMessageBox } from 'element-plus';
|
|
||||||
import { Switch } from '@/components/ui/switch';
|
import { Switch } from '@/components/ui/switch';
|
||||||
import { storeToRefs } from 'pinia';
|
import { storeToRefs } from 'pinia';
|
||||||
import { useI18n } from 'vue-i18n';
|
import { useI18n } from 'vue-i18n';
|
||||||
|
|
||||||
import dayjs from 'dayjs';
|
import dayjs from 'dayjs';
|
||||||
|
|
||||||
import { useAppearanceSettingsStore, useGameLogStore, useVrcxStore } from '../../stores';
|
import { useAppearanceSettingsStore, useGameLogStore, useModalStore, useVrcxStore } from '../../stores';
|
||||||
import { DataTableLayout } from '../../components/ui/data-table';
|
import { DataTableLayout } from '../../components/ui/data-table';
|
||||||
import { InputGroupField } from '../../components/ui/input-group';
|
import { InputGroupField } from '../../components/ui/input-group';
|
||||||
import { createColumns } from './columns.jsx';
|
import { createColumns } from './columns.jsx';
|
||||||
@@ -77,6 +76,7 @@
|
|||||||
const { gameLogTable } = storeToRefs(useGameLogStore());
|
const { gameLogTable } = storeToRefs(useGameLogStore());
|
||||||
const appearanceSettingsStore = useAppearanceSettingsStore();
|
const appearanceSettingsStore = useAppearanceSettingsStore();
|
||||||
const vrcxStore = useVrcxStore();
|
const vrcxStore = useVrcxStore();
|
||||||
|
const modalStore = useModalStore();
|
||||||
|
|
||||||
function getGameLogCreatedAt(row) {
|
function getGameLogCreatedAt(row) {
|
||||||
if (typeof row?.created_at === 'string' && row.created_at.length > 0) {
|
if (typeof row?.created_at === 'string' && row.created_at.length > 0) {
|
||||||
@@ -134,16 +134,12 @@
|
|||||||
});
|
});
|
||||||
|
|
||||||
function deleteGameLogEntryPrompt(row) {
|
function deleteGameLogEntryPrompt(row) {
|
||||||
ElMessageBox.confirm('Continue? Delete Log', 'Confirm', {
|
modalStore
|
||||||
confirmButtonText: 'Confirm',
|
.confirm({
|
||||||
cancelButtonText: 'Cancel',
|
description: 'Continue? Delete Log',
|
||||||
type: 'info'
|
title: 'Confirm'
|
||||||
})
|
|
||||||
.then((action) => {
|
|
||||||
if (action === 'confirm') {
|
|
||||||
deleteGameLogEntry(row);
|
|
||||||
}
|
|
||||||
})
|
})
|
||||||
|
.then(({ ok }) => ok && deleteGameLogEntry(row))
|
||||||
.catch(() => {});
|
.catch(() => {});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -51,14 +51,13 @@
|
|||||||
import { Select, SelectContent, SelectGroup, SelectItem, SelectTrigger, SelectValue } from '@/components/ui/select';
|
import { Select, SelectContent, SelectGroup, SelectItem, SelectTrigger, SelectValue } from '@/components/ui/select';
|
||||||
import { computed, ref, watch } from 'vue';
|
import { computed, ref, watch } from 'vue';
|
||||||
import { Button } from '@/components/ui/button';
|
import { Button } from '@/components/ui/button';
|
||||||
import { ElMessageBox } from 'element-plus';
|
|
||||||
import { InputGroupField } from '@/components/ui/input-group';
|
import { InputGroupField } from '@/components/ui/input-group';
|
||||||
import { Refresh } from '@element-plus/icons-vue';
|
import { Refresh } from '@element-plus/icons-vue';
|
||||||
import { Spinner } from '@/components/ui/spinner';
|
import { Spinner } from '@/components/ui/spinner';
|
||||||
import { storeToRefs } from 'pinia';
|
import { storeToRefs } from 'pinia';
|
||||||
import { useI18n } from 'vue-i18n';
|
import { useI18n } from 'vue-i18n';
|
||||||
|
|
||||||
import { useAppearanceSettingsStore, useModerationStore, useVrcxStore } from '../../stores';
|
import { useAppearanceSettingsStore, useModalStore, useModerationStore, useVrcxStore } from '../../stores';
|
||||||
import { DataTableLayout } from '../../components/ui/data-table';
|
import { DataTableLayout } from '../../components/ui/data-table';
|
||||||
import { createColumns } from './columns.jsx';
|
import { createColumns } from './columns.jsx';
|
||||||
import { moderationTypes } from '../../shared/constants';
|
import { moderationTypes } from '../../shared/constants';
|
||||||
@@ -73,6 +72,7 @@
|
|||||||
const { refreshPlayerModerations, handlePlayerModerationDelete } = useModerationStore();
|
const { refreshPlayerModerations, handlePlayerModerationDelete } = useModerationStore();
|
||||||
const appearanceSettingsStore = useAppearanceSettingsStore();
|
const appearanceSettingsStore = useAppearanceSettingsStore();
|
||||||
const vrcxStore = useVrcxStore();
|
const vrcxStore = useVrcxStore();
|
||||||
|
const modalStore = useModalStore();
|
||||||
|
|
||||||
const moderationRef = ref(null);
|
const moderationRef = ref(null);
|
||||||
const { tableStyle: tableHeightStyle } = useDataTableScrollHeight(moderationRef, {
|
const { tableStyle: tableHeightStyle } = useDataTableScrollHeight(moderationRef, {
|
||||||
@@ -110,16 +110,12 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
function deletePlayerModerationPrompt(row) {
|
function deletePlayerModerationPrompt(row) {
|
||||||
ElMessageBox.confirm(`Continue? Delete Moderation ${row.type}`, 'Confirm', {
|
modalStore
|
||||||
confirmButtonText: 'Confirm',
|
.confirm({
|
||||||
cancelButtonText: 'Cancel',
|
description: `Continue? Delete Moderation ${row.type}`,
|
||||||
type: 'info'
|
title: 'Confirm'
|
||||||
})
|
|
||||||
.then((action) => {
|
|
||||||
if (action === 'confirm') {
|
|
||||||
deletePlayerModeration(row);
|
|
||||||
}
|
|
||||||
})
|
})
|
||||||
|
.then(({ ok }) => ok && deletePlayerModeration(row))
|
||||||
.catch(() => {});
|
.catch(() => {});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -85,7 +85,6 @@
|
|||||||
import { Select, SelectContent, SelectGroup, SelectItem, SelectTrigger, SelectValue } from '@/components/ui/select';
|
import { Select, SelectContent, SelectGroup, SelectItem, SelectTrigger, SelectValue } from '@/components/ui/select';
|
||||||
import { computed, ref, watch } from 'vue';
|
import { computed, ref, watch } from 'vue';
|
||||||
import { Button } from '@/components/ui/button';
|
import { Button } from '@/components/ui/button';
|
||||||
import { ElMessageBox } from 'element-plus';
|
|
||||||
import { InputGroupField } from '@/components/ui/input-group';
|
import { InputGroupField } from '@/components/ui/input-group';
|
||||||
import { Refresh } from '@element-plus/icons-vue';
|
import { Refresh } from '@element-plus/icons-vue';
|
||||||
import { Spinner } from '@/components/ui/spinner';
|
import { Spinner } from '@/components/ui/spinner';
|
||||||
@@ -102,6 +101,7 @@
|
|||||||
useGroupStore,
|
useGroupStore,
|
||||||
useInviteStore,
|
useInviteStore,
|
||||||
useLocationStore,
|
useLocationStore,
|
||||||
|
useModalStore,
|
||||||
useNotificationStore,
|
useNotificationStore,
|
||||||
useUserStore,
|
useUserStore,
|
||||||
useVrcxStore
|
useVrcxStore
|
||||||
@@ -129,6 +129,7 @@
|
|||||||
const { currentUser } = storeToRefs(useUserStore());
|
const { currentUser } = storeToRefs(useUserStore());
|
||||||
const appearanceSettingsStore = useAppearanceSettingsStore();
|
const appearanceSettingsStore = useAppearanceSettingsStore();
|
||||||
const vrcxStore = useVrcxStore();
|
const vrcxStore = useVrcxStore();
|
||||||
|
const modalStore = useModalStore();
|
||||||
|
|
||||||
const { t } = useI18n();
|
const { t } = useI18n();
|
||||||
|
|
||||||
@@ -321,17 +322,18 @@
|
|||||||
|
|
||||||
function acceptFriendRequestNotification(row) {
|
function acceptFriendRequestNotification(row) {
|
||||||
// FIXME: 메시지 수정
|
// FIXME: 메시지 수정
|
||||||
ElMessageBox.confirm('Continue? Accept Friend Request', 'Confirm', {
|
modalStore
|
||||||
confirmButtonText: 'Confirm',
|
.confirm({
|
||||||
cancelButtonText: 'Cancel',
|
description: 'Continue? Accept Friend Request',
|
||||||
type: 'info'
|
title: 'Confirm'
|
||||||
})
|
})
|
||||||
.then((action) => {
|
.then(({ ok }) => {
|
||||||
if (action === 'confirm') {
|
if (!ok) {
|
||||||
notificationRequest.acceptFriendRequestNotification({
|
return;
|
||||||
notificationId: row.id
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
notificationRequest.acceptFriendRequestNotification({
|
||||||
|
notificationId: row.id
|
||||||
|
});
|
||||||
})
|
})
|
||||||
.catch(() => {});
|
.catch(() => {});
|
||||||
}
|
}
|
||||||
@@ -345,46 +347,47 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
function acceptRequestInvite(row) {
|
function acceptRequestInvite(row) {
|
||||||
ElMessageBox.confirm('Continue? Send Invite', 'Confirm', {
|
modalStore
|
||||||
confirmButtonText: 'Confirm',
|
.confirm({
|
||||||
cancelButtonText: 'Cancel',
|
description: 'Continue? Send Invite',
|
||||||
type: 'info'
|
title: 'Confirm'
|
||||||
})
|
})
|
||||||
.then((action) => {
|
.then(({ ok }) => {
|
||||||
if (action === 'confirm') {
|
if (!ok) {
|
||||||
let currentLocation = lastLocation.value.location;
|
return;
|
||||||
if (lastLocation.value.location === 'traveling') {
|
|
||||||
currentLocation = lastLocationDestination.value;
|
|
||||||
}
|
|
||||||
if (!currentLocation) {
|
|
||||||
// game log disabled, use API location
|
|
||||||
currentLocation = currentUser.$locationTag;
|
|
||||||
}
|
|
||||||
const L = parseLocation(currentLocation);
|
|
||||||
worldRequest
|
|
||||||
.getCachedWorld({
|
|
||||||
worldId: L.worldId
|
|
||||||
})
|
|
||||||
.then((args) => {
|
|
||||||
notificationRequest
|
|
||||||
.sendInvite(
|
|
||||||
{
|
|
||||||
instanceId: L.tag,
|
|
||||||
worldId: L.tag,
|
|
||||||
worldName: args.ref.name,
|
|
||||||
rsvp: true
|
|
||||||
},
|
|
||||||
row.senderUserId
|
|
||||||
)
|
|
||||||
.then((_args) => {
|
|
||||||
toast('Invite sent');
|
|
||||||
notificationRequest.hideNotification({
|
|
||||||
notificationId: row.id
|
|
||||||
});
|
|
||||||
return _args;
|
|
||||||
});
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
let currentLocation = lastLocation.value.location;
|
||||||
|
if (lastLocation.value.location === 'traveling') {
|
||||||
|
currentLocation = lastLocationDestination.value;
|
||||||
|
}
|
||||||
|
if (!currentLocation) {
|
||||||
|
// game log disabled, use API location
|
||||||
|
currentLocation = currentUser.$locationTag;
|
||||||
|
}
|
||||||
|
const L = parseLocation(currentLocation);
|
||||||
|
worldRequest
|
||||||
|
.getCachedWorld({
|
||||||
|
worldId: L.worldId
|
||||||
|
})
|
||||||
|
.then((args) => {
|
||||||
|
notificationRequest
|
||||||
|
.sendInvite(
|
||||||
|
{
|
||||||
|
instanceId: L.tag,
|
||||||
|
worldId: L.tag,
|
||||||
|
worldName: args.ref.name,
|
||||||
|
rsvp: true
|
||||||
|
},
|
||||||
|
row.senderUserId
|
||||||
|
)
|
||||||
|
.then((_args) => {
|
||||||
|
toast('Invite sent');
|
||||||
|
notificationRequest.hideNotification({
|
||||||
|
notificationId: row.id
|
||||||
|
});
|
||||||
|
return _args;
|
||||||
|
});
|
||||||
|
});
|
||||||
})
|
})
|
||||||
.catch(() => {});
|
.catch(() => {});
|
||||||
}
|
}
|
||||||
@@ -454,13 +457,13 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
function hideNotificationPrompt(row) {
|
function hideNotificationPrompt(row) {
|
||||||
ElMessageBox.confirm(`Continue? Decline ${row.type}`, 'Confirm', {
|
modalStore
|
||||||
confirmButtonText: 'Confirm',
|
.confirm({
|
||||||
cancelButtonText: 'Cancel',
|
description: `Continue? Decline ${row.type}`,
|
||||||
type: 'info'
|
title: 'Confirm'
|
||||||
})
|
})
|
||||||
.then((action) => {
|
.then(({ ok }) => {
|
||||||
if (action === 'confirm') {
|
if (ok) {
|
||||||
hideNotification(row);
|
hideNotification(row);
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
@@ -478,13 +481,13 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
function deleteNotificationLogPrompt(row) {
|
function deleteNotificationLogPrompt(row) {
|
||||||
ElMessageBox.confirm(`Continue? Delete ${row.type}`, 'Confirm', {
|
modalStore
|
||||||
confirmButtonText: 'Confirm',
|
.confirm({
|
||||||
cancelButtonText: 'Cancel',
|
description: `Continue? Delete ${row.type}`,
|
||||||
type: 'info'
|
title: 'Confirm'
|
||||||
})
|
})
|
||||||
.then((action) => {
|
.then(({ ok }) => {
|
||||||
if (action === 'confirm') {
|
if (ok) {
|
||||||
deleteNotificationLog(row);
|
deleteNotificationLog(row);
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -55,8 +55,8 @@
|
|||||||
import { toast } from 'vue-sonner';
|
import { toast } from 'vue-sonner';
|
||||||
import { useI18n } from 'vue-i18n';
|
import { useI18n } from 'vue-i18n';
|
||||||
|
|
||||||
|
import { useAdvancedSettingsStore, useModalStore, useVrcxStore } from '../../../stores';
|
||||||
import { downloadAndSaveJson, removeFromArray } from '../../../shared/utils';
|
import { downloadAndSaveJson, removeFromArray } from '../../../shared/utils';
|
||||||
import { useAdvancedSettingsStore, useVrcxStore } from '../../../stores';
|
|
||||||
import { Switch } from '../../../components/ui/switch';
|
import { Switch } from '../../../components/ui/switch';
|
||||||
import { createColumns } from './registryBackupColumns.jsx';
|
import { createColumns } from './registryBackupColumns.jsx';
|
||||||
import { useVrcxVueTable } from '../../../lib/table/useVrcxVueTable';
|
import { useVrcxVueTable } from '../../../lib/table/useVrcxVueTable';
|
||||||
@@ -67,6 +67,7 @@
|
|||||||
const { isRegistryBackupDialogVisible } = storeToRefs(useVrcxStore());
|
const { isRegistryBackupDialogVisible } = storeToRefs(useVrcxStore());
|
||||||
const { vrcRegistryAutoBackup, vrcRegistryAskRestore } = storeToRefs(useAdvancedSettingsStore());
|
const { vrcRegistryAutoBackup, vrcRegistryAskRestore } = storeToRefs(useAdvancedSettingsStore());
|
||||||
const { setVrcRegistryAutoBackup, setVrcRegistryAskRestore } = useAdvancedSettingsStore();
|
const { setVrcRegistryAutoBackup, setVrcRegistryAskRestore } = useAdvancedSettingsStore();
|
||||||
|
const modalStore = useModalStore();
|
||||||
|
|
||||||
const { t } = useI18n();
|
const { t } = useI18n();
|
||||||
|
|
||||||
@@ -121,13 +122,13 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
function restoreVrcRegistryBackup(row) {
|
function restoreVrcRegistryBackup(row) {
|
||||||
ElMessageBox.confirm('Continue? Restore Backup', 'Confirm', {
|
modalStore
|
||||||
confirmButtonText: 'Confirm',
|
.confirm({
|
||||||
cancelButtonText: 'Cancel',
|
description: 'Continue? Restore Backup',
|
||||||
type: 'warning'
|
title: 'Confirm'
|
||||||
})
|
})
|
||||||
.then((action) => {
|
.then(({ ok }) => {
|
||||||
if (action !== 'confirm') {
|
if (!ok) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
const data = JSON.stringify(row.data);
|
const data = JSON.stringify(row.data);
|
||||||
@@ -155,13 +156,13 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
function deleteVrcRegistry() {
|
function deleteVrcRegistry() {
|
||||||
ElMessageBox.confirm('Continue? Delete VRC Registry Settings', 'Confirm', {
|
modalStore
|
||||||
confirmButtonText: 'Confirm',
|
.confirm({
|
||||||
cancelButtonText: 'Cancel',
|
description: 'Continue? Delete VRC Registry Settings',
|
||||||
type: 'warning'
|
title: 'Confirm'
|
||||||
})
|
})
|
||||||
.then((action) => {
|
.then(({ ok }) => {
|
||||||
if (action !== 'confirm') {
|
if (!ok) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
AppApi.DeleteVRChatRegistryFolder().then(() => {
|
AppApi.DeleteVRChatRegistryFolder().then(() => {
|
||||||
@@ -178,8 +179,6 @@
|
|||||||
|
|
||||||
function promptVrcRegistryBackupName() {
|
function promptVrcRegistryBackupName() {
|
||||||
ElMessageBox.prompt('Enter a name for the backup', 'Backup Name', {
|
ElMessageBox.prompt('Enter a name for the backup', 'Backup Name', {
|
||||||
confirmButtonText: 'Confirm',
|
|
||||||
cancelButtonText: 'Cancel',
|
|
||||||
inputPattern: /\S+/,
|
inputPattern: /\S+/,
|
||||||
inputErrorMessage: 'Name is required',
|
inputErrorMessage: 'Name is required',
|
||||||
inputValue: 'Backup'
|
inputValue: 'Backup'
|
||||||
|
|||||||
@@ -173,23 +173,23 @@
|
|||||||
import { Select, SelectContent, SelectGroup, SelectItem, SelectTrigger, SelectValue } from '@/components/ui/select';
|
import { Select, SelectContent, SelectGroup, SelectItem, SelectTrigger, SelectValue } from '@/components/ui/select';
|
||||||
import { computed, ref, watch } from 'vue';
|
import { computed, ref, watch } from 'vue';
|
||||||
import { Button } from '@/components/ui/button';
|
import { Button } from '@/components/ui/button';
|
||||||
import { InputGroupAction } from '@/components/ui/input-group';
|
|
||||||
import { Checkbox } from '@/components/ui/checkbox';
|
import { Checkbox } from '@/components/ui/checkbox';
|
||||||
import { ElMessageBox } from 'element-plus';
|
import { InputGroupAction } from '@/components/ui/input-group';
|
||||||
import { Refresh } from '@element-plus/icons-vue';
|
import { Refresh } from '@element-plus/icons-vue';
|
||||||
import { Spinner } from '@/components/ui/spinner';
|
import { Spinner } from '@/components/ui/spinner';
|
||||||
import { storeToRefs } from 'pinia';
|
import { storeToRefs } from 'pinia';
|
||||||
import { toast } from 'vue-sonner';
|
import { toast } from 'vue-sonner';
|
||||||
import { useI18n } from 'vue-i18n';
|
import { useI18n } from 'vue-i18n';
|
||||||
|
|
||||||
|
import { useAdvancedSettingsStore, useGameStore, useModalStore } from '../../../stores';
|
||||||
import { VRChatCameraResolutions, VRChatScreenshotResolutions } from '../../../shared/constants';
|
import { VRChatCameraResolutions, VRChatScreenshotResolutions } from '../../../shared/constants';
|
||||||
import { getVRChatResolution, openExternalLink } from '../../../shared/utils';
|
import { getVRChatResolution, openExternalLink } from '../../../shared/utils';
|
||||||
import { useAdvancedSettingsStore, useGameStore } from '../../../stores';
|
|
||||||
|
|
||||||
const { VRChatUsedCacheSize, VRChatTotalCacheSize, VRChatCacheSizeLoading } = storeToRefs(useGameStore());
|
const { VRChatUsedCacheSize, VRChatTotalCacheSize, VRChatCacheSizeLoading } = storeToRefs(useGameStore());
|
||||||
const { sweepVRChatCache, getVRChatCacheSize } = useGameStore();
|
const { sweepVRChatCache, getVRChatCacheSize } = useGameStore();
|
||||||
const { folderSelectorDialog } = useAdvancedSettingsStore();
|
const { folderSelectorDialog } = useAdvancedSettingsStore();
|
||||||
const { isVRChatConfigDialogVisible } = storeToRefs(useAdvancedSettingsStore());
|
const { isVRChatConfigDialogVisible } = storeToRefs(useAdvancedSettingsStore());
|
||||||
|
const modalStore = useModalStore();
|
||||||
|
|
||||||
const { t } = useI18n();
|
const { t } = useI18n();
|
||||||
|
|
||||||
@@ -322,13 +322,13 @@
|
|||||||
});
|
});
|
||||||
|
|
||||||
function showDeleteAllVRChatCacheConfirm() {
|
function showDeleteAllVRChatCacheConfirm() {
|
||||||
ElMessageBox.confirm(`Continue? Delete all VRChat cache`, 'Confirm', {
|
modalStore
|
||||||
confirmButtonText: 'Confirm',
|
.confirm({
|
||||||
cancelButtonText: 'Cancel',
|
description: 'Continue? Delete all VRChat cache',
|
||||||
type: 'info'
|
title: 'Confirm'
|
||||||
})
|
})
|
||||||
.then((action) => {
|
.then(({ ok }) => {
|
||||||
if (action === 'confirm') {
|
if (ok) {
|
||||||
deleteAllVRChatCache();
|
deleteAllVRChatCache();
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -91,7 +91,7 @@
|
|||||||
<div v-for="friendArr in friendsInSameInstance" :key="friendArr[0].ref.$location.tag">
|
<div v-for="friendArr in friendsInSameInstance" :key="friendArr[0].ref.$location.tag">
|
||||||
<div class="mb-1 flex items-center">
|
<div class="mb-1 flex items-center">
|
||||||
<Location
|
<Location
|
||||||
class="extra text-neutral-300!"
|
class="extra text-muted-foreground!"
|
||||||
:location="getFriendsLocations(friendArr)"
|
:location="getFriendsLocations(friendArr)"
|
||||||
style="display: inline" />
|
style="display: inline" />
|
||||||
<span class="extra" style="margin-left: 5px">{{ `(${friendArr.length})` }}</span>
|
<span class="extra" style="margin-left: 5px">{{ `(${friendArr.length})` }}</span>
|
||||||
|
|||||||
Reference in New Issue
Block a user