restructure admin pages

This commit is contained in:
Phillip Thelen
2025-06-18 14:24:38 +02:00
parent 2a2bea07ab
commit e9b2c1b51a
36 changed files with 246 additions and 218 deletions

View File

@@ -1,7 +1,7 @@
<template>
<div class="row standard-page col-12 d-flex justify-content-center">
<div class="admin-panel-content">
<h1>Admin Panel</h1>
<h1>{{ $t("adminPanel") }}</h1>
<form
class="form-inline"
@submit.prevent="searchUsers(userIdentifier)"
@@ -72,7 +72,7 @@ export default {
},
mounted () {
this.$store.dispatch('common:setTitle', {
section: 'Admin Panel',
section: this.$t('adminPanel'),
});
},
methods: {

View File

@@ -147,7 +147,7 @@ import markdownDirective from '@/directives/markdown';
import saveHero from '../mixins/saveHero';
import { mapState } from '@/libs/store';
import { userStateMixin } from '../../../mixins/userState';
import { userStateMixin } from '../../../../mixins/userState';
const permissionList = [
{

View File

@@ -149,7 +149,7 @@ import Achievements from './achievements.vue';
import UserHistory from './userHistory.vue';
import Stats from './stats.vue';
import { userStateMixin } from '../../../mixins/userState';
import { userStateMixin } from '../../../../mixins/userState';
export default {
components: {

View File

@@ -189,7 +189,7 @@ import markdownDirective from '@/directives/markdown';
import saveHero from '../mixins/saveHero';
import { mapState } from '@/libs/store';
import { userStateMixin } from '../../../mixins/userState';
import { userStateMixin } from '../../../../mixins/userState';
import StatsRow from './stats-row';

View File

@@ -421,7 +421,7 @@ import isUUID from 'validator/es/lib/isUUID';
import moment from 'moment';
import { getPlanContext } from '@/../../common/script/cron';
import saveHero from '../mixins/saveHero';
import subscriptionBlocks from '../../../../../common/script/content/subscriptionBlocks';
import subscriptionBlocks from '@/../../common/script/content/subscriptionBlocks';
import LoadingSpinner from '@/components/ui/loadingSpinner';
export default {

View File

@@ -22,8 +22,8 @@
</template>
<script>
import PurchaseHistoryTable from '../../ui/purchaseHistoryTable.vue';
import { userStateMixin } from '../../../mixins/userState';
import PurchaseHistoryTable from '../../../ui/purchaseHistoryTable.vue';
import { userStateMixin } from '../../../../mixins/userState';
export default {
components: {

View File

@@ -180,7 +180,7 @@
<script>
import moment from 'moment';
import { userStateMixin } from '../../../mixins/userState';
import { userStateMixin } from '../../../../mixins/userState';
export default {
filters: {

View File

@@ -86,7 +86,7 @@ import markdownDirective from '@/directives/markdown';
import saveHero from '../mixins/saveHero';
import { mapState } from '@/libs/store';
import { userStateMixin } from '../../../mixins/userState';
import { userStateMixin } from '../../../../mixins/userState';
function resetData (self) {
self.expand = false;

View File

@@ -3,12 +3,11 @@
<td></td>
<td><select class="form-control" v-model="blocker.type">
<option value="ipaddress">IP-Address</option>
<option value="email">E-Mail</option>
<option value="client">Client Identifier</option>
</select>
</td>
<td><select class="form-control" v-model="blocker.area">
<option value="full">Full</option>
<option value="payments">Payments</option>
</select></td>
<td><input v-model="blocker.value"></td>
<td><input v-model="blocker.reason"></td>

View File

@@ -101,7 +101,7 @@ export default {
showCreateForm: false,
newBlocker: {
type: '',
area: '',
area: 'full',
value: '',
reason: '',
},
@@ -118,7 +118,7 @@ export default {
},
mounted () {
this.$store.dispatch('common:setTitle', {
section: 'Admin Panel',
section: this.$t('siteBlockers'),
});
this.loadBlockers();
},
@@ -144,15 +144,23 @@ export default {
async createBlocker (blocker) {
await this.$store.dispatch('blockers:createBlocker', { blocker });
this.showCreateForm = false;
this.newBlocker = {
type: '',
area: 'full',
value: '',
reason: '',
};
this.loadBlockers();
},
getTypeName (type) {
switch (type) {
case 'ipaddress':
return 'IP Address';
return 'IP-Address';
case 'email':
return 'E-Mail';
case 'client':
return 'Client Identifier';
default:
return type;
}

View File

@@ -0,0 +1,30 @@
<template>
<div class="row">
<secondary-menu class="col-12">
<router-link
class="nav-link"
:to="{name: 'adminPanel'}"
>
{{ $t('adminPanel') }}
</router-link><router-link
class="nav-link"
:to="{name: 'blockers'}"
>
{{ $t('siteBlockers') }}
</router-link>
</secondary-menu><div class="col-12">
<router-view />
</div>
</div>
</template>
<script>
import SecondaryMenu from '@/components/secondaryMenu';
export default {
components: {
SecondaryMenu,
},
};
</script>

View File

@@ -286,7 +286,7 @@
:to="{ name: 'adminPanelUser',
params: { userIdentifier: hero._id } }"
>
admin panel
{{ $t("adminPanel") }}
</router-link>
</span>
</td>

View File

@@ -295,14 +295,6 @@
{{ $t('help') }}
</router-link>
<div class="topbar-dropdown">
<router-link
v-if="user.permissions.fullAccess ||
user.permissions.userSupport"
class="topbar-dropdown-item dropdown-item"
:to="{name: 'adminPanel'}"
>
Admin Panel
</router-link>
<router-link
class="topbar-dropdown-item dropdown-item"
:to="{name: 'faq'}"
@@ -336,6 +328,51 @@
>{{ $t('requestFeature') }}</a>
</div>
</li>
<li
class="topbar-item droppable"
v-if="user.permissions.fullAccess ||
user.permissions.userSupport"
:class="{
'active': $route.path.startsWith('/admin')}"
>
<div
class="chevron rotate"
@click="dropdownMobile($event)"
>
<div
v-once
class="chevron-icon-down"
v-html="icons.chevronDown"
></div>
</div>
<router-link
class="nav-link"
:to="{name: 'adminPanel'}"
>
{{ $t('admin') }}
</router-link>
<div class="topbar-dropdown">
<router-link
class="topbar-dropdown-item dropdown-item"
:to="{name: 'adminPanel'}"
>
{{ $t("adminPanel") }}
</router-link>
<router-link
class="topbar-dropdown-item dropdown-item"
:to="{name: 'blockers'}"
>
{{ $t("siteBlockers") }}
</router-link>
<a
class="topbar-dropdown-item dropdown-item"
target="_blank"
href="https://panel.habitica.com"
>
{{ $t('newsroom') }}
</a>
</div>
</li>
</b-navbar-nav>
<div class="currency-tray form-inline">
<div

View File

@@ -19,16 +19,12 @@ const HallPage = () => import(/* webpackChunkName: "hall" */'@/components/hall/i
const PatronsPage = () => import(/* webpackChunkName: "hall" */'@/components/hall/patrons');
const HeroesPage = () => import(/* webpackChunkName: "hall" */'@/components/hall/heroes');
// Admin Panel
const AdminPanelPage = () => import(/* webpackChunkName: "admin-panel" */'@/components/admin-panel');
const AdminPanelUserPage = () => import(/* webpackChunkName: "admin-panel" */'@/components/admin-panel/user-support');
const AdminPanelSearchPage = () => import(/* webpackChunkName: "admin-panel" */'@/components/admin-panel/search');
const BlockerPage = () => import(/* webpackChunkName: "admin-panel" */'@/components/blocker');
// Except for tasks that are always loaded all the other main level
// All the main level
// components are loaded in separate webpack chunks.
// See https://webpack.js.org/guides/code-splitting-async/
// for docs
// Admin Pages
const AdminContainerPage = () => import(/* webpackChunkName: "admin-panel" */'@/components/admin/container');
const AdminPanelPage = () => import(/* webpackChunkName: "admin-panel" */'@/components/admin/admin-panel');
const AdminPanelUserPage = () => import(/* webpackChunkName: "admin-panel" */'@/components/admin/admin-panel/user-support');
const AdminPanelSearchPage = () => import(/* webpackChunkName: "admin-panel" */'@/components/admin/admin-panel/search');
const BlockerPage = () => import(/* webpackChunkName: "admin-panel" */'@/components/admin/blocker');
// Tasks
const UserTasks = () => import(/* webpackChunkName: "userTasks" */'@/components/tasks/user');
@@ -185,8 +181,8 @@ const router = new VueRouter({
{
name: 'adminPanel',
path: '/admin-panel',
component: AdminPanelPage,
path: '/admin',
component: AdminContainerPage,
meta: {
privilegeNeeded: [ // any one of these is enough to give access
'userSupport',
@@ -194,38 +190,51 @@ const router = new VueRouter({
},
children: [
{
name: 'adminPanelSearch',
path: 'search/:userIdentifier',
component: AdminPanelSearchPage,
name: 'adminPanel',
path: 'panel',
component: AdminPanelPage,
meta: {
privilegeNeeded: [
privilegeNeeded: [ // any one of these is enough to give access
'userSupport',
],
},
children: [
{
name: 'adminPanelSearch',
path: 'search/:userIdentifier',
component: AdminPanelSearchPage,
meta: {
privilegeNeeded: [
'userSupport',
],
},
},
{
name: 'adminPanelUser',
path: ':userIdentifier',
component: AdminPanelUserPage,
meta: {
privilegeNeeded: [
'userSupport',
],
},
},
],
},
{
name: 'adminPanelUser',
path: ':userIdentifier',
component: AdminPanelUserPage,
name: 'blockers',
path: 'blockers',
component: BlockerPage,
meta: {
privilegeNeeded: [
privilegeNeeded: [ // any one of these is enough to give access
'userSupport',
],
},
},
],
},
{
name: 'blockers',
path: '/blockers',
component: BlockerPage,
meta: {
privilegeNeeded: [ // any one of these is enough to give access
'userSupport',
],
},
]
},
// Only used to handle some redirects
// See router.beforeEach
{ path: '/static/tavern-and-guilds', redirect: '/static/faq/tavern-and-guilds' },