Upgrade dependencies.
Use user_id in places we were using username. Still debating this. Start getting this working with API backend, until there were calls to /api/sticker which don't exist in the API yet. Then I rediscovered the local json-server. So now there are 2 api backends. We'll incrementally migrate from the first version to the second. SCSS and tailwind weren't working for nav-items.css. The browser just saw the raw version. So for now, just inlined that. Probably these nav items will become components (if they are shared).
This commit is contained in:
parent
5b48c5a8c5
commit
929f22abeb
22 changed files with 2360 additions and 1445 deletions
3540
package-lock.json
generated
3540
package-lock.json
generated
File diff suppressed because it is too large
Load diff
43
package.json
43
package.json
|
|
@ -15,41 +15,44 @@
|
|||
"format": "prettier --write src/"
|
||||
},
|
||||
"dependencies": {
|
||||
"@pinia/colada": "^0.13.0",
|
||||
"@pinia/colada": "^0.17.6",
|
||||
"@primevue/forms": "^4.2.2",
|
||||
"@primevue/themes": "^4.2.2",
|
||||
"pinia": "^2.2.6",
|
||||
"@primevue/themes": "^4.4.1",
|
||||
"@tailwindcss/postcss": "^4.1.15",
|
||||
"pinia": "^3.0.3",
|
||||
"primeicons": "^7.0.0",
|
||||
"primevue": "^4.2.2",
|
||||
"tailwindcss-primeui": "^0.3.4",
|
||||
"primevue": "^4.4.1",
|
||||
"tailwindcss-primeui": "^0.6.1",
|
||||
"uqr": "^0.1.2",
|
||||
"vue": "^3.5.12",
|
||||
"vue": "^3.5.22",
|
||||
"vue-router": "^4.4.5"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@tailwindcss/vite": "^4.1.15",
|
||||
"@tsconfig/node22": "^22.0.0",
|
||||
"@types/jsdom": "^21.1.7",
|
||||
"@types/node": "^22.9.0",
|
||||
"@vitejs/plugin-vue": "^5.1.4",
|
||||
"@vitest/eslint-plugin": "1.1.7",
|
||||
"@types/jsdom": "^27.0.0",
|
||||
"@types/node": "^24.9.0",
|
||||
"@vitejs/plugin-vue": "^6.0.1",
|
||||
"@vitest/eslint-plugin": "1.3.23",
|
||||
"@vue/eslint-config-prettier": "^10.1.0",
|
||||
"@vue/eslint-config-typescript": "^14.1.3",
|
||||
"@vue/language-server": "^3.1.1",
|
||||
"@vue/test-utils": "^2.4.6",
|
||||
"@vue/tsconfig": "^0.5.1",
|
||||
"@vue/tsconfig": "^0.8.1",
|
||||
"autoprefixer": "^10.4.20",
|
||||
"eslint": "^9.14.0",
|
||||
"eslint-plugin-vue": "^9.30.0",
|
||||
"jsdom": "^25.0.1",
|
||||
"eslint-plugin-vue": "^10.5.1",
|
||||
"jsdom": "^27.0.1",
|
||||
"json-server": "^1.0.0-beta.3",
|
||||
"npm-run-all2": "^7.0.1",
|
||||
"npm-run-all2": "^8.0.4",
|
||||
"postcss": "^8.4.49",
|
||||
"prettier": "^3.3.3",
|
||||
"sass-embedded": "^1.81.0",
|
||||
"tailwindcss": "^3.4.15",
|
||||
"typescript": "~5.6.3",
|
||||
"vite": "^5.4.10",
|
||||
"vite-plugin-vue-devtools": "^7.5.4",
|
||||
"vitest": "^2.1.4",
|
||||
"vue-tsc": "^2.1.10"
|
||||
"tailwindcss": "^4.1.15",
|
||||
"typescript": "~5.9.3",
|
||||
"vite": "^7.1.11",
|
||||
"vite-plugin-vue-devtools": "^8.0.3",
|
||||
"vitest": "^3.2.4",
|
||||
"vue-tsc": "^3.1.1"
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,6 +1,5 @@
|
|||
export default {
|
||||
plugins: {
|
||||
tailwindcss: {},
|
||||
autoprefixer: {},
|
||||
'@tailwindcss/postcss': {},
|
||||
},
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,3 +1,4 @@
|
|||
@tailwind base;
|
||||
@tailwind components;
|
||||
@tailwind utilities;
|
||||
@import "tailwindcss";
|
||||
@import "tailwindcss/preflight";
|
||||
@import "tailwindcss-primeui";
|
||||
@import 'primeicons/primeicons.css';
|
||||
|
|
|
|||
|
|
@ -1,14 +0,0 @@
|
|||
.nav-item {
|
||||
align-items: center;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
padding: 16px;
|
||||
@apply hover:bg-surface-800 rounded-border text-surface-300 hover:text-white;
|
||||
span {
|
||||
@apply text-base;
|
||||
text-align: center;
|
||||
}
|
||||
}
|
||||
.nav-icon {
|
||||
@apply text-base;
|
||||
}
|
||||
|
|
@ -1,3 +1,5 @@
|
|||
<!--Only displays for > sm screens -->
|
||||
|
||||
<script lang="ts" setup>
|
||||
</script>
|
||||
|
||||
|
|
@ -8,13 +10,14 @@
|
|||
</template>
|
||||
|
||||
<style scoped>
|
||||
@import "@/assets/nav-items.css";
|
||||
@reference "tailwindcss";
|
||||
|
||||
footer {
|
||||
background-color: #E0E0E0;
|
||||
color: #777;
|
||||
padding: 20px;
|
||||
}
|
||||
@media (screen(sm)) {
|
||||
@media (min-width: 640px) {
|
||||
aside {
|
||||
flex-direction: column;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -3,16 +3,14 @@
|
|||
|
||||
<template>
|
||||
<nav>
|
||||
<RouterLink
|
||||
class="nav-item"
|
||||
to="/">
|
||||
<RouterLink class="nav-item" to="/">
|
||||
<i class="pi pi-home nav-icon" />
|
||||
<span>Home</span>
|
||||
</RouterLink>
|
||||
<RouterLink class="nav-item" to="/sticker">
|
||||
<a class="nav-item">
|
||||
<i class="pi pi-image nav-icon" />
|
||||
<span>Sticker</span>
|
||||
</RouterLink>
|
||||
</a>
|
||||
<a class="nav-item">
|
||||
<i class="pi pi-users nav-icon" />
|
||||
<span>Team</span>
|
||||
|
|
@ -21,9 +19,7 @@
|
|||
<i class="pi pi-calendar nav-icon" />
|
||||
<span>Events</span>
|
||||
</a>
|
||||
<RouterLink
|
||||
class="nav-item"
|
||||
to="/profile">
|
||||
<RouterLink class="nav-item" to="/profile">
|
||||
<i class="pi pi-user nav-icon" />
|
||||
<span>Profile</span>
|
||||
</RouterLink>
|
||||
|
|
@ -31,12 +27,37 @@
|
|||
</template>
|
||||
|
||||
<style scoped>
|
||||
@import "@/assets/nav-items.css";
|
||||
@reference "tailwindcss";
|
||||
@reference "tailwindcss-primeui";
|
||||
|
||||
nav {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
}
|
||||
@media (screen(sm)) {
|
||||
|
||||
|
||||
|
||||
/* Duplicated in Sidebar.vue. */
|
||||
.nav-item {
|
||||
align-items: center;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
padding: 16px;
|
||||
|
||||
@apply hover:bg-surface-800 rounded-border text-surface-300 hover:text-white;
|
||||
span {
|
||||
@apply text-base;
|
||||
text-align: center;
|
||||
}
|
||||
}
|
||||
.nav-icon {
|
||||
@apply text-base;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
@media (min-width: 640px) {
|
||||
nav {
|
||||
flex-direction: column;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -41,6 +41,7 @@ const toggle = (event: Event) => { menu.value.toggle(event); };
|
|||
<aside>
|
||||
<Navigation></Navigation>
|
||||
<div class="mt-auto act-avatar">
|
||||
<!-- TODO -->
|
||||
<a class="nav-item" @click="toggle">
|
||||
<div v-if="sessionStore.isAnonymous">
|
||||
<Avatar icon="pi pi-user" size="large" shape="circle" />
|
||||
|
|
@ -67,7 +68,9 @@ const toggle = (event: Event) => { menu.value.toggle(event); };
|
|||
</template>
|
||||
|
||||
<style scoped>
|
||||
@import "@/assets/nav-items.css";
|
||||
@reference "tailwindcss";
|
||||
@reference "tailwindcss-primeui";
|
||||
|
||||
aside {
|
||||
background-color: #333;
|
||||
display: flex;
|
||||
|
|
@ -77,7 +80,20 @@ aside {
|
|||
display: none;
|
||||
}
|
||||
}
|
||||
@media (screen(sm)) {
|
||||
/* Duplicated in Navigation.vue. */
|
||||
.nav-item {
|
||||
align-items: center;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
padding: 16px;
|
||||
|
||||
@apply hover:bg-surface-800 rounded-border text-surface-300 hover:text-white;
|
||||
span {
|
||||
@apply text-base;
|
||||
text-align: center;
|
||||
}
|
||||
}
|
||||
@media (min-width: 640px) {
|
||||
aside {
|
||||
flex-direction: column;
|
||||
.act-avatar {
|
||||
|
|
|
|||
|
|
@ -133,7 +133,7 @@ header {
|
|||
.act-menubar-end {
|
||||
margin-left: 0 !important;
|
||||
}
|
||||
@media (screen(sm)) {
|
||||
@media (min-width: 640px) {
|
||||
.act-useraction {
|
||||
background-color: red;
|
||||
display: none; // sidebar will have them
|
||||
|
|
|
|||
|
|
@ -57,7 +57,7 @@ $sidebar-size: 90px !default;
|
|||
top: 0;
|
||||
z-index: 20;
|
||||
}
|
||||
@media (screen(sm)) {
|
||||
@media (min-width: 640px) {
|
||||
margin-bottom: 0;
|
||||
margin-left: v-bind(sidebarSize);
|
||||
.act-footer {
|
||||
|
|
|
|||
|
|
@ -41,7 +41,7 @@ const router = createRouter({
|
|||
title: 'Print',
|
||||
},
|
||||
name: 'print',
|
||||
path: '/print/:username',
|
||||
path: '/print/:user_id',
|
||||
},
|
||||
{
|
||||
component: ProfileView,
|
||||
|
|
@ -49,7 +49,7 @@ const router = createRouter({
|
|||
title: 'Profile',
|
||||
},
|
||||
name: 'profile',
|
||||
path: '/profile/:username?',
|
||||
path: '/profile/:user_id?',
|
||||
},
|
||||
{
|
||||
component: StickerBuilderView,
|
||||
|
|
|
|||
|
|
@ -1,17 +1,16 @@
|
|||
import {acceptHMRUpdate, defineStore} from 'pinia'
|
||||
import { useUserStore } from '@/stores/userStore'
|
||||
|
||||
|
||||
export interface User {
|
||||
name: string,
|
||||
sticker_ids: string[],
|
||||
username: string,
|
||||
user_id: string,
|
||||
}
|
||||
|
||||
const anonymous: User = {
|
||||
name: 'Anonymous',
|
||||
sticker_ids: [],
|
||||
username: 'anonymous',
|
||||
user_id: 'anonymous',
|
||||
};
|
||||
|
||||
export interface State {
|
||||
|
|
@ -21,22 +20,25 @@ export interface State {
|
|||
export const useSessionStore = defineStore('session', {
|
||||
actions: {
|
||||
async login(username: string, password: string) {
|
||||
const formData = new FormData();
|
||||
formData.append('username', username);
|
||||
formData.append('password', password);
|
||||
const response = await fetch(
|
||||
`/api/session`,
|
||||
`/api-2/sessions`,
|
||||
{
|
||||
method: 'POST',
|
||||
body: JSON.stringify({username, password}),
|
||||
body: formData,
|
||||
},
|
||||
);
|
||||
const json = await response.json();
|
||||
console.log('session created', json);
|
||||
const payload = parseJwt(json.access_token);
|
||||
// Fetch the user record.
|
||||
const userStore= useUserStore();
|
||||
let user = await userStore.fetch(json.username);
|
||||
console.log('user', user);
|
||||
let user = await userStore.fetch(payload.user_id);
|
||||
if (user) {
|
||||
this.user = user;
|
||||
}
|
||||
console.log('session started');
|
||||
},
|
||||
logout() {
|
||||
console.log('logout');
|
||||
|
|
@ -53,7 +55,7 @@ export const useSessionStore = defineStore('session', {
|
|||
return state.user.name[0] || '';
|
||||
},
|
||||
isAnonymous: (state: State): boolean => {
|
||||
return state.user.username === 'anonymous';
|
||||
return state.user.user_id === 'anonymous';
|
||||
},
|
||||
},
|
||||
state: (): State => {
|
||||
|
|
@ -63,6 +65,20 @@ export const useSessionStore = defineStore('session', {
|
|||
},
|
||||
})
|
||||
|
||||
|
||||
function parseJwt(token: string) {
|
||||
var base64Url = token.split('.')[1];
|
||||
if (!base64Url) {
|
||||
return undefined;
|
||||
}
|
||||
var base64 = base64Url.replace(/-/g, '+').replace(/_/g, '/');
|
||||
var jsonPayload = decodeURIComponent(window.atob(base64).split('').map(function(c) {
|
||||
return '%' + ('00' + c.charCodeAt(0).toString(16)).slice(-2);
|
||||
}).join(''));
|
||||
|
||||
return JSON.parse(jsonPayload);
|
||||
}
|
||||
|
||||
if (import.meta.hot) {
|
||||
import.meta.hot.accept(acceptHMRUpdate(useSessionStore, import.meta.hot))
|
||||
}
|
||||
|
|
|
|||
|
|
@ -46,8 +46,8 @@ export interface State {
|
|||
stickers: Sticker[];
|
||||
}
|
||||
|
||||
function randomColor() {
|
||||
return colors[Math.floor(Math.random() * colors.length)];
|
||||
function randomColor(): string {
|
||||
return colors[Math.floor(Math.random() * colors.length)] as string;
|
||||
}
|
||||
|
||||
export const useStickersStore = defineStore('stickers', {
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
export interface User {
|
||||
name: string,
|
||||
sticker_ids: string[],
|
||||
username: string,
|
||||
user_id: string,
|
||||
}
|
||||
|
|
|
|||
|
|
@ -10,8 +10,8 @@ export interface State {
|
|||
|
||||
export const useUserStore = defineStore('user', {
|
||||
actions: {
|
||||
addSticker(username: string, id: string) {
|
||||
let user = this.getUser(username);
|
||||
addSticker(user_id: string, id: string) {
|
||||
let user = this.getUser(user_id);
|
||||
if (user) {
|
||||
user.sticker_ids.push(id);
|
||||
}
|
||||
|
|
@ -19,20 +19,28 @@ export const useUserStore = defineStore('user', {
|
|||
addUser(user: User) {
|
||||
this.users.push(user);
|
||||
},
|
||||
async fetch(username: string) {
|
||||
let user = this.getUser(username);
|
||||
async fetch(user_id: string) {
|
||||
let user = this.getUser(user_id);
|
||||
if (!user) {
|
||||
// TODO: Check if we have it already and if it's stale.
|
||||
const response = await fetch(
|
||||
`/api/user/${username}`,
|
||||
`/api-2/user/${user_id}`,
|
||||
);
|
||||
user = await response.json();
|
||||
if (user) {
|
||||
this.users.push(user);
|
||||
if (!response.ok) {
|
||||
throw new Error(`HTTP error! status: ${response.status}`);
|
||||
}
|
||||
const user_data = await response.json();
|
||||
if (user_data !== undefined) {
|
||||
user = {
|
||||
user_id: user_data.id,
|
||||
name: user_data.display_name,
|
||||
sticker_ids: [],
|
||||
};
|
||||
this.addUser(user);
|
||||
|
||||
// prepop sticker store with user stickers
|
||||
// pre-pop sticker store with user stickers
|
||||
const stickersStore = useStickersStore();
|
||||
user.sticker_ids.forEach((sticker_id: string) => {
|
||||
user.sticker_ids?.forEach((sticker_id: string) => {
|
||||
stickersStore.fetch(sticker_id);
|
||||
})
|
||||
}
|
||||
|
|
@ -42,8 +50,8 @@ export const useUserStore = defineStore('user', {
|
|||
},
|
||||
getters: {
|
||||
getUser: (state: State) => {
|
||||
return (username: string): User | undefined => {
|
||||
return state.users.find((user: User) => user.username === username)
|
||||
return (user_id: string): User | undefined => {
|
||||
return state.users.find((user: User) => user.user_id === user_id)
|
||||
};
|
||||
},
|
||||
},
|
||||
|
|
|
|||
|
|
@ -8,15 +8,15 @@ import Button from "primevue/button";
|
|||
<Panel header="user1 contributed to project1">
|
||||
<Button
|
||||
as="router-link"
|
||||
to="/profile/joe">
|
||||
to="/profile/b356ab50-4657-4b60-aba9-71a2baab3bfe">
|
||||
Joe's Profile
|
||||
</Button>
|
||||
</Panel>
|
||||
<Panel header="user2 contributed to project2">
|
||||
<Button
|
||||
as="router-link"
|
||||
to="/profile/jen">
|
||||
Jen's Profile
|
||||
to="/profile/2f0ad329-4f24-4d22-8827-d1a5d3237a4d">
|
||||
Kim's Profile
|
||||
</Button>
|
||||
</Panel>
|
||||
<Panel header="user3 contributed to project3">
|
||||
|
|
|
|||
|
|
@ -60,7 +60,7 @@ onMounted(async () => {
|
|||
padding: 10px;
|
||||
.sticker {
|
||||
width: 300px;
|
||||
@media (screen(sm)) {
|
||||
@media (min-width: 640px) {
|
||||
zoom: 250%;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -21,17 +21,17 @@ const sessionStore = useSessionStore();
|
|||
const userStore = useUserStore();
|
||||
const { getUser } = userStore;
|
||||
const route = useRoute();
|
||||
const username = ref<string>(route.params.username as string);
|
||||
const user_id = ref<string>(route.params.user_id as string);
|
||||
let user = ref<User>();
|
||||
const stickersStore = useStickersStore();
|
||||
|
||||
onMounted(async () => {
|
||||
await userStore.fetch(username.value);
|
||||
user.value = getUser(username.value);
|
||||
await userStore.fetch(user_id.value);
|
||||
user.value = getUser(user_id.value);
|
||||
});
|
||||
|
||||
const myPage = computed(() => {
|
||||
return !sessionStore.isAnonymous && sessionStore.user.username == user.value?.username;
|
||||
return !sessionStore.isAnonymous && sessionStore.user.user_id == user.value?.user_id;
|
||||
});
|
||||
|
||||
const meterValue = ref([
|
||||
|
|
@ -90,11 +90,11 @@ const events = [{
|
|||
</Button>
|
||||
<Button
|
||||
as="router-link"
|
||||
:to="{ name: 'print', params: { username: user?.username }}">
|
||||
:to="{ name: 'print', params: { user_id: user?.user_id }}">
|
||||
Print
|
||||
</Button>
|
||||
<div class="stickers">
|
||||
<div v-for="sticker in stickersStore.getStickersCreatedBy(user?.username)">
|
||||
<div v-for="sticker in stickersStore.getStickersCreatedBy(user?.user_id)">
|
||||
<div class="stickerWrapper">
|
||||
<RouterLink :to="{ name: 'sticker', params: { id: sticker.id }}">
|
||||
<Sticker v-bind="sticker" />
|
||||
|
|
@ -120,7 +120,7 @@ const events = [{
|
|||
:pt="{ eventOpposite: { class: 'hidden' } }"
|
||||
:value="events">
|
||||
<template #marker="slotProps">
|
||||
<span class="flex w-8 h-8 items-center justify-center text-white rounded-full z-10 shadow-sm" :style="{ backgroundColor: slotProps.item.color }">
|
||||
<span class="flex w-8 h-8 items-center justify-center text-white rounded-full z-10 shadow-xs" :style="{ backgroundColor: slotProps.item.color }">
|
||||
<i :class="slotProps.item.icon"></i>
|
||||
</span>
|
||||
</template>
|
||||
|
|
@ -160,6 +160,8 @@ const events = [{
|
|||
</template>
|
||||
|
||||
<style scoped>
|
||||
@reference "tailwindcss";
|
||||
|
||||
.profilePage {
|
||||
@apply p-2 gap-2;
|
||||
display: flex;
|
||||
|
|
@ -177,7 +179,7 @@ const events = [{
|
|||
padding: 10px;
|
||||
.sticker {
|
||||
width: 300px;
|
||||
@media (screen(sm)) {
|
||||
@media (min-width: 640px) {
|
||||
zoom: 250%;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -206,6 +206,9 @@ const orgOptions = computed(() => {
|
|||
</template>
|
||||
|
||||
<style scoped lang="scss">
|
||||
@reference "tailwindcss";
|
||||
@reference "tailwindcss-primeui";
|
||||
|
||||
label {
|
||||
@apply font-medium text-surface-900 dark:text-surface-0 mb-1 block;
|
||||
}
|
||||
|
|
@ -228,7 +231,7 @@ label {
|
|||
top: 60px;
|
||||
.medium {
|
||||
width: 300px;
|
||||
@media (screen(sm)) {
|
||||
@media (min-width: 640px) {
|
||||
zoom: 250%;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -97,7 +97,7 @@ function claimSticker() {
|
|||
padding: 10px;
|
||||
#Sticker {
|
||||
width: 300px;
|
||||
@media (screen(sm)) {
|
||||
@media (min-width: 640px) {
|
||||
zoom: 250%;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,8 +1,11 @@
|
|||
/** @type {import('tailwindcss').Config} */
|
||||
import primeui from 'tailwindcss-primeui'
|
||||
|
||||
export default {
|
||||
content: [
|
||||
"./index.html",
|
||||
"./src/**/*.{vue,js,ts,jsx,tsx}",
|
||||
"./node_modules/**/*.{vue,js,ts,jsx,tsx}",
|
||||
],
|
||||
theme: {
|
||||
extend: {
|
||||
|
|
@ -13,5 +16,5 @@ export default {
|
|||
},
|
||||
},
|
||||
},
|
||||
plugins: [require('tailwindcss-primeui')],
|
||||
plugins: [primeui],
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,18 +1,20 @@
|
|||
import { fileURLToPath, URL } from 'node:url'
|
||||
|
||||
import { defineConfig } from 'vite'
|
||||
import tailwindcss from '@tailwindcss/vite';
|
||||
import vue from '@vitejs/plugin-vue'
|
||||
import vueDevTools from 'vite-plugin-vue-devtools'
|
||||
// import vueDevTools from 'vite-plugin-vue-devtools'
|
||||
|
||||
// https://vite.dev/config/
|
||||
export default defineConfig({
|
||||
plugins: [
|
||||
vue(),
|
||||
// vueDevTools(),
|
||||
tailwindcss(),
|
||||
],
|
||||
resolve: {
|
||||
alias: {
|
||||
'@': fileURLToPath(new URL('./src', import.meta.url))
|
||||
'@': fileURLToPath(new URL('./src', import.meta.url)),
|
||||
},
|
||||
},
|
||||
server: {
|
||||
|
|
@ -22,6 +24,12 @@ export default defineConfig({
|
|||
changeOrigin: true,
|
||||
secure: false,
|
||||
rewrite: (path) => path.replace(/^\/api/, ''),
|
||||
},
|
||||
'^/api-2/': {
|
||||
target: 'http://127.0.0.1:5000',
|
||||
changeOrigin: true,
|
||||
secure: false,
|
||||
rewrite: (path) => path.replace(/^\/api-2/, ''),
|
||||
}
|
||||
},
|
||||
},
|
||||
|
|
|
|||
Loading…
Reference in a new issue