mirror of
https://github.com/directus/directus.git
synced 2026-01-27 17:38:00 -05:00
Switch to history mode in app (#594)
* Switch to history mode in pp * Remove broken tests * Install asset manifest * Only build to modern * Remove override files in favor of settings * Build assets json * Use dynamic routing based on api basepath * Remove override files * Set webpack public path based on passed window var * Fix tests
This commit is contained in:
@@ -1,4 +1,12 @@
|
||||
module.exports = {
|
||||
presets: [['@vue/cli-plugin-babel/preset', { jsx: false }]],
|
||||
presets: [
|
||||
[
|
||||
'@vue/app',
|
||||
{
|
||||
targets: { esmodules: true },
|
||||
polyfills: [],
|
||||
},
|
||||
],
|
||||
],
|
||||
plugins: ['@babel/plugin-proposal-optional-chaining'],
|
||||
};
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
"author": "Rijk van Zanten <rijk@rngr.org>",
|
||||
"scripts": {
|
||||
"serve": "vue-cli-service serve",
|
||||
"build": "vue-cli-service build --modern",
|
||||
"build": "vue-cli-service build",
|
||||
"test": "vue-cli-service test:unit",
|
||||
"lint": "vue-cli-service lint",
|
||||
"lint:styles": "stylelint \"**/*.{vue,scss}\"",
|
||||
@@ -104,6 +104,7 @@
|
||||
"vue-template-compiler": "^2.6.10",
|
||||
"vuepress": "^1.5.0",
|
||||
"webpack": "^4.43.0",
|
||||
"webpack-assets-manifest": "^3.1.1",
|
||||
"webpack-merge": "^4.2.2"
|
||||
},
|
||||
"gitHooks": {
|
||||
|
||||
@@ -7,8 +7,6 @@
|
||||
<link rel="shortcut icon" href="favicon.ico">
|
||||
<link rel="manifest" href="manifest.webmanifest" />
|
||||
<title>Directus</title>
|
||||
|
||||
<link rel="stylesheet" href="style.css" />
|
||||
</head>
|
||||
<body class="auto">
|
||||
<noscript>
|
||||
@@ -16,6 +14,5 @@
|
||||
</noscript>
|
||||
<div id="app"></div>
|
||||
<!-- built files will be auto injected -->
|
||||
<script src="script.js"></script>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
@@ -1,5 +0,0 @@
|
||||
/*
|
||||
* This is a custom script file that is loaded for each instance on each page.
|
||||
*
|
||||
* Use to it add whatever client scripts your project might need
|
||||
*/
|
||||
@@ -1,7 +0,0 @@
|
||||
/*
|
||||
Place your custom style overrides here.
|
||||
|
||||
NOTE: The main application's styling is included through JavaScript. Therefore, it gets added to
|
||||
the head _after_ this file. If you want to override the globally used CSS variables, you can either
|
||||
use !important, or increase the specificity from :root
|
||||
*/
|
||||
@@ -1,6 +1,6 @@
|
||||
import Vue from 'vue';
|
||||
import VueCompositionAPI from '@vue/composition-api';
|
||||
import { onRequest, onResponse, onError, getRootPath, RequestError } from './api';
|
||||
import { onRequest, onResponse, onError, RequestError } from './api';
|
||||
import * as auth from '@/auth';
|
||||
import { useRequestsStore } from '@/stores/requests';
|
||||
|
||||
@@ -29,18 +29,6 @@ describe('API', () => {
|
||||
window = Object.create(window);
|
||||
});
|
||||
|
||||
it('Calculates the correct API root URL based on window', () => {
|
||||
Object.defineProperty(window, 'location', {
|
||||
value: {
|
||||
pathname: '/api/nested/admin',
|
||||
},
|
||||
writable: true,
|
||||
});
|
||||
|
||||
const result = getRootPath();
|
||||
expect(result).toBe('/api/nested/');
|
||||
});
|
||||
|
||||
it('Calls startRequest on the store on any request', () => {
|
||||
const store = useRequestsStore({});
|
||||
const spy = jest.spyOn(store, 'startRequest');
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import axios, { AxiosRequestConfig, AxiosResponse, AxiosError } from 'axios';
|
||||
import { useRequestsStore } from '@/stores/requests';
|
||||
import { LogoutReason, logout, checkAuth } from '@/auth';
|
||||
import getRootPath from '@/utils/get-root-path';
|
||||
|
||||
const api = axios.create({
|
||||
baseURL: getRootPath(),
|
||||
@@ -65,12 +66,4 @@ export const onError = async (error: RequestError) => {
|
||||
api.interceptors.request.use(onRequest);
|
||||
api.interceptors.response.use(onResponse, onError);
|
||||
|
||||
export function getRootPath(): string {
|
||||
const path = window.location.pathname;
|
||||
const parts = path.split('/');
|
||||
const adminIndex = parts.indexOf('admin');
|
||||
const rootPath = parts.slice(0, adminIndex).join('/') + '/';
|
||||
return rootPath;
|
||||
}
|
||||
|
||||
export default api;
|
||||
|
||||
@@ -1,79 +0,0 @@
|
||||
import { mount, createLocalVue, Wrapper } from '@vue/test-utils';
|
||||
import VueCompositionAPI from '@vue/composition-api';
|
||||
import VNotice from './v-notice.vue';
|
||||
import VIcon from '@/components/v-icon/';
|
||||
|
||||
const localVue = createLocalVue();
|
||||
localVue.use(VueCompositionAPI);
|
||||
localVue.component('v-icon', VIcon);
|
||||
|
||||
describe('Notice', () => {
|
||||
let component: Wrapper<Vue>;
|
||||
|
||||
beforeEach(() => {
|
||||
component = mount(VNotice, {
|
||||
localVue,
|
||||
slots: {
|
||||
default: 'I like pizza',
|
||||
},
|
||||
});
|
||||
});
|
||||
|
||||
it('Renders the default slot in the notice', () => {
|
||||
expect(component.text()).toContain('I like pizza');
|
||||
});
|
||||
|
||||
it('Uses the right color / icon combo for success', async () => {
|
||||
component.setProps({
|
||||
success: true,
|
||||
});
|
||||
|
||||
await component.vm.$nextTick();
|
||||
|
||||
expect(component.classes()).toContain('success');
|
||||
expect((component.vm as any).iconName).toBe('check_circle');
|
||||
});
|
||||
|
||||
it('Uses the right color / icon combo for warning', async () => {
|
||||
component.setProps({
|
||||
warning: true,
|
||||
});
|
||||
|
||||
await component.vm.$nextTick();
|
||||
|
||||
expect(component.classes()).toContain('warning');
|
||||
expect((component.vm as any).iconName).toBe('warning');
|
||||
});
|
||||
|
||||
it('Uses the right color / icon combo for danger', async () => {
|
||||
component.setProps({
|
||||
danger: true,
|
||||
});
|
||||
|
||||
await component.vm.$nextTick();
|
||||
|
||||
expect(component.classes()).toContain('danger');
|
||||
expect((component.vm as any).iconName).toBe('error');
|
||||
});
|
||||
|
||||
it('Defaults to success if all props are given', async () => {
|
||||
component.setProps({
|
||||
success: true,
|
||||
warning: true,
|
||||
danger: true,
|
||||
});
|
||||
|
||||
await component.vm.$nextTick();
|
||||
|
||||
expect((component.vm as any).iconName).toBe('check_circle');
|
||||
expect(component.classes()).toContain('success');
|
||||
});
|
||||
|
||||
it('Allows setting a custom icon', async () => {
|
||||
component.setProps({
|
||||
icon: 'person',
|
||||
});
|
||||
await component.vm.$nextTick();
|
||||
expect((component.vm as any).iconName).toBe('person');
|
||||
});
|
||||
});
|
||||
@@ -1,3 +1,5 @@
|
||||
__webpack_public_path__ = (window as any).$directusAssetBasePath || '/admin/';
|
||||
|
||||
import Vue from 'vue';
|
||||
|
||||
import { version } from '../package.json';
|
||||
|
||||
@@ -11,6 +11,8 @@ import useAppStore from '@/stores/app';
|
||||
import useUserStore from '@/stores/user';
|
||||
import PrivateNotFoundRoute from '@/routes/private-not-found';
|
||||
|
||||
import getRootPath from '@/utils/get-root-path';
|
||||
|
||||
export const onBeforeEnterProjectChooser: NavigationGuard = (to, from, next) => {
|
||||
const projectsStore = useProjectsStore();
|
||||
projectsStore.state.currentProjectKey = null;
|
||||
@@ -43,6 +45,9 @@ export const defaultRoutes: RouteConfig[] = [
|
||||
name: 'login',
|
||||
path: '/:project/login',
|
||||
component: LoginRoute,
|
||||
props: (route) => ({
|
||||
ssoErrorCode: route.query.error,
|
||||
}),
|
||||
meta: {
|
||||
public: true,
|
||||
},
|
||||
@@ -83,13 +88,18 @@ export const defaultRoutes: RouteConfig[] = [
|
||||
];
|
||||
|
||||
const router = new VueRouter({
|
||||
mode: 'hash',
|
||||
mode: 'history',
|
||||
base: getRootPath() + 'admin/',
|
||||
routes: defaultRoutes,
|
||||
});
|
||||
|
||||
export function replaceRoutes(routeFilter: (routes: RouteConfig[]) => RouteConfig[]): void {
|
||||
const newRoutes = routeFilter([...defaultRoutes]);
|
||||
const newRouter = new VueRouter({ routes: newRoutes });
|
||||
const newRouter = new VueRouter({
|
||||
mode: 'history',
|
||||
base: getRootPath() + 'admin/',
|
||||
routes: newRoutes,
|
||||
});
|
||||
|
||||
// @ts-ignore - Matcher is not officially part of the public API (https://github.com/vuejs/vue-router/issues/2844#issuecomment-509529927)
|
||||
router.matcher = newRouter.matcher;
|
||||
|
||||
15
src/utils/get-root-path/get-root-path.test.ts
Normal file
15
src/utils/get-root-path/get-root-path.test.ts
Normal file
@@ -0,0 +1,15 @@
|
||||
import getRootPath from './get-root-path';
|
||||
|
||||
describe('Utils / get root path', () => {
|
||||
it('Calculates the correct API root URL based on window', () => {
|
||||
Object.defineProperty(window, 'location', {
|
||||
value: {
|
||||
pathname: '/api/nested/admin',
|
||||
},
|
||||
writable: true,
|
||||
});
|
||||
|
||||
const result = getRootPath();
|
||||
expect(result).toBe('/api/nested/');
|
||||
});
|
||||
});
|
||||
7
src/utils/get-root-path/get-root-path.ts
Normal file
7
src/utils/get-root-path/get-root-path.ts
Normal file
@@ -0,0 +1,7 @@
|
||||
export default function getRootPath(): string {
|
||||
const path = window.location.pathname;
|
||||
const parts = path.split('/');
|
||||
const adminIndex = parts.indexOf('admin');
|
||||
const rootPath = parts.slice(0, adminIndex).join('/') + '/';
|
||||
return rootPath;
|
||||
}
|
||||
4
src/utils/get-root-path/index.ts
Normal file
4
src/utils/get-root-path/index.ts
Normal file
@@ -0,0 +1,4 @@
|
||||
import getRootPath from './get-root-path';
|
||||
|
||||
export default getRootPath;
|
||||
export { getRootPath };
|
||||
@@ -1,3 +1,8 @@
|
||||
/* @tslint:disable */
|
||||
/* eslint-disable */
|
||||
|
||||
const WebpackAssetsManifest = require('webpack-assets-manifest');
|
||||
|
||||
if (!process.env.API_URL && process.env.NODE_ENV === 'development') {
|
||||
console.log(`
|
||||
⚠️ No API URL passed. Using the demo API as a fallback.
|
||||
@@ -6,7 +11,7 @@ if (!process.env.API_URL && process.env.NODE_ENV === 'development') {
|
||||
|
||||
module.exports = {
|
||||
lintOnSave: false,
|
||||
publicPath: process.env.NODE_ENV === 'production' ? '' : '/admin/',
|
||||
publicPath: '/admin/',
|
||||
|
||||
devServer: {
|
||||
allowedHosts: ['localhost', '.gitpod.io'],
|
||||
@@ -15,10 +20,15 @@ module.exports = {
|
||||
'/': {
|
||||
target: process.env.API_URL ? process.env.API_URL : 'https://demo.directus.io/',
|
||||
changeOrigin: true,
|
||||
bypass: (req) => (req.url.startsWith('/admin') ? req.url : null),
|
||||
},
|
||||
},
|
||||
},
|
||||
|
||||
configureWebpack: {
|
||||
plugins: [new WebpackAssetsManifest({ output: 'assets.json' })],
|
||||
},
|
||||
|
||||
// There are so many chunks (from all the interfaces / layouts) that we need to make sure to not
|
||||
// prefetch them all. Prefetching them all will cause the server to apply rate limits in most cases
|
||||
chainWebpack: (config) => {
|
||||
|
||||
34
yarn.lock
34
yarn.lock
@@ -4240,7 +4240,7 @@ ccount@^1.0.0:
|
||||
resolved "https://registry.yarnpkg.com/ccount/-/ccount-1.0.5.tgz#ac82a944905a65ce204eb03023157edf29425c17"
|
||||
integrity sha512-MOli1W+nfbPLlKEhInaxhRdp7KVLFxLN5ykwzHgLsLI3H3gs5jjFAK4Eoj3OzzcxCtumDaI8onoVDeQyWaNTkw==
|
||||
|
||||
chalk@2.4.2, chalk@^2.0.0, chalk@^2.0.1, chalk@^2.1.0, chalk@^2.3.0, chalk@^2.3.2, chalk@^2.4.1, chalk@^2.4.2:
|
||||
chalk@2.4.2, chalk@^2.0, chalk@^2.0.0, chalk@^2.0.1, chalk@^2.1.0, chalk@^2.3.0, chalk@^2.3.2, chalk@^2.4.1, chalk@^2.4.2:
|
||||
version "2.4.2"
|
||||
resolved "https://registry.yarnpkg.com/chalk/-/chalk-2.4.2.tgz#cd42541677a54333cf541a49108c1432b44c9424"
|
||||
integrity sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==
|
||||
@@ -9369,6 +9369,16 @@ lodash.defaultsdeep@^4.6.1:
|
||||
resolved "https://registry.yarnpkg.com/lodash.defaultsdeep/-/lodash.defaultsdeep-4.6.1.tgz#512e9bd721d272d94e3d3a63653fa17516741ca6"
|
||||
integrity sha512-3j8wdDzYuWO3lM3Reg03MuQR957t287Rpcxp1njpEa8oDrikb+FwGdW3n+FELh/A6qib6yPit0j/pv9G/yeAqA==
|
||||
|
||||
lodash.get@^4.0:
|
||||
version "4.4.2"
|
||||
resolved "https://registry.yarnpkg.com/lodash.get/-/lodash.get-4.4.2.tgz#2d177f652fa31e939b4438d5341499dfa3825e99"
|
||||
integrity sha1-LRd/ZS+jHpObRDjVNBSZ36OCXpk=
|
||||
|
||||
lodash.has@^4.0:
|
||||
version "4.5.2"
|
||||
resolved "https://registry.yarnpkg.com/lodash.has/-/lodash.has-4.5.2.tgz#d19f4dc1095058cccbe2b0cdf4ee0fe4aa37c862"
|
||||
integrity sha1-0Z9NwQlQWMzL4rDN9O4P5Ko3yGI=
|
||||
|
||||
lodash.kebabcase@^4.1.1:
|
||||
version "4.1.1"
|
||||
resolved "https://registry.yarnpkg.com/lodash.kebabcase/-/lodash.kebabcase-4.1.1.tgz#8489b1cb0d29ff88195cceca448ff6d6cc295c36"
|
||||
@@ -10044,6 +10054,13 @@ mkdirp@0.x, mkdirp@^0.5.1, mkdirp@^0.5.3, mkdirp@~0.5.1, mkdirp@~0.5.x:
|
||||
dependencies:
|
||||
minimist "^1.2.5"
|
||||
|
||||
mkdirp@^0.5:
|
||||
version "0.5.5"
|
||||
resolved "https://registry.yarnpkg.com/mkdirp/-/mkdirp-0.5.5.tgz#d91cefd62d1436ca0f41620e251288d420099def"
|
||||
integrity sha512-NKmAlESf6jMGym1++R0Ra7wvhV+wFW63FaSOFPwRahvea0gMUcGUhVeAg/0BC0wiv9ih5NYPB1Wn1UEI1/L+xQ==
|
||||
dependencies:
|
||||
minimist "^1.2.5"
|
||||
|
||||
mockdate@^2.0.5:
|
||||
version "2.0.5"
|
||||
resolved "https://registry.yarnpkg.com/mockdate/-/mockdate-2.0.5.tgz#70c6abf9ed4b2dae65c81dfc170dd1a5cec53620"
|
||||
@@ -15309,6 +15326,19 @@ webidl-conversions@^4.0.2:
|
||||
resolved "https://registry.yarnpkg.com/webidl-conversions/-/webidl-conversions-4.0.2.tgz#a855980b1f0b6b359ba1d5d9fb39ae941faa63ad"
|
||||
integrity sha512-YQ+BmxuTgd6UXZW3+ICGfyqRyHXVlD5GtQr5+qjiNW7bF0cqrzX500HVXPBOvgXb5YnzDd+h0zqyv61KUD7+Sg==
|
||||
|
||||
webpack-assets-manifest@^3.1.1:
|
||||
version "3.1.1"
|
||||
resolved "https://registry.yarnpkg.com/webpack-assets-manifest/-/webpack-assets-manifest-3.1.1.tgz#39bbc3bf2ee57fcd8ba07cda51c9ba4a3c6ae1de"
|
||||
integrity sha512-JV9V2QKc5wEWQptdIjvXDUL1ucbPLH2f27toAY3SNdGZp+xSaStAgpoMcvMZmqtFrBc9a5pTS1058vxyMPOzRQ==
|
||||
dependencies:
|
||||
chalk "^2.0"
|
||||
lodash.get "^4.0"
|
||||
lodash.has "^4.0"
|
||||
mkdirp "^0.5"
|
||||
schema-utils "^1.0.0"
|
||||
tapable "^1.0.0"
|
||||
webpack-sources "^1.0.0"
|
||||
|
||||
webpack-bundle-analyzer@^3.6.1:
|
||||
version "3.6.1"
|
||||
resolved "https://registry.yarnpkg.com/webpack-bundle-analyzer/-/webpack-bundle-analyzer-3.6.1.tgz#bdb637c2304424f2fbff9a950c7be42a839ae73b"
|
||||
@@ -15419,7 +15449,7 @@ webpack-merge@^4.1.2, webpack-merge@^4.2.2:
|
||||
dependencies:
|
||||
lodash "^4.17.15"
|
||||
|
||||
webpack-sources@^1.1.0, webpack-sources@^1.4.0, webpack-sources@^1.4.1, webpack-sources@^1.4.3:
|
||||
webpack-sources@^1.0.0, webpack-sources@^1.1.0, webpack-sources@^1.4.0, webpack-sources@^1.4.1, webpack-sources@^1.4.3:
|
||||
version "1.4.3"
|
||||
resolved "https://registry.yarnpkg.com/webpack-sources/-/webpack-sources-1.4.3.tgz#eedd8ec0b928fbf1cbfe994e22d2d890f330a933"
|
||||
integrity sha512-lgTS3Xhv1lCOKo7SA5TjKXMjpSM4sBjNV5+q2bqesbSPs5FjGmU6jjtBSkX9b4qW87vDIsCIlUPOEhbZrMdjeQ==
|
||||
|
||||
Reference in New Issue
Block a user