@oxygen-cms/ui 1.6.2 → 1.6.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.idea/workspace.xml +37 -0
- package/package.json +1 -1
- package/src/AuthApi.js +7 -0
- package/src/EventsApi.js +5 -0
- package/src/Internationalize.js +12 -0
- package/src/api.js +24 -26
- package/src/components/CodeEditor.vue +34 -1
- package/src/components/LegacyPage.vue +22 -15
- package/src/components/auth/Login.vue +0 -3
- package/src/components/auth/Logout.vue +1 -1
- package/src/components/preferences/Preferences.vue +1 -1
- package/src/components/preferences/PreferencesList.vue +1 -1
- package/src/components/preferences/PreferencesThemeChooser.vue +2 -0
- package/src/icons.js +2 -2
- package/src/main.js +15 -1
- package/src/modules/Events.js +35 -0
- package/src/modules/{LegacyPages.js → PagesPartials.js} +1 -12
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
<?xml version="1.0" encoding="UTF-8"?>
|
|
2
|
+
<project version="4">
|
|
3
|
+
<component name="ChangeListManager">
|
|
4
|
+
<list default="true" id="4ad0dcde-54f6-459b-8ef0-38a17e946358" name="Changes" comment="" />
|
|
5
|
+
<option name="SHOW_DIALOG" value="false" />
|
|
6
|
+
<option name="HIGHLIGHT_CONFLICTS" value="true" />
|
|
7
|
+
<option name="HIGHLIGHT_NON_ACTIVE_CHANGELIST" value="false" />
|
|
8
|
+
<option name="LAST_RESOLUTION" value="IGNORE" />
|
|
9
|
+
</component>
|
|
10
|
+
<component name="ComposerSettings">
|
|
11
|
+
<execution />
|
|
12
|
+
</component>
|
|
13
|
+
<component name="ProjectId" id="27rS1jBVazc5EdthHlwaXfJm1hC" />
|
|
14
|
+
<component name="ProjectViewState">
|
|
15
|
+
<option name="hideEmptyMiddlePackages" value="true" />
|
|
16
|
+
<option name="showLibraryContents" value="true" />
|
|
17
|
+
</component>
|
|
18
|
+
<component name="PropertiesComponent"><![CDATA[{
|
|
19
|
+
"keyToString": {
|
|
20
|
+
"RunOnceActivity.OpenProjectViewOnStart": "true",
|
|
21
|
+
"RunOnceActivity.ShowReadmeOnStart": "true",
|
|
22
|
+
"WebServerToolWindowFactoryState": "false",
|
|
23
|
+
"last_opened_file_path": "/home/chris/code/oxygen/Components/ui"
|
|
24
|
+
}
|
|
25
|
+
}]]></component>
|
|
26
|
+
<component name="SpellCheckerSettings" RuntimeDictionaries="0" Folders="0" CustomDictionaries="0" DefaultDictionary="application-level" UseSingleDictionary="true" transferred="true" />
|
|
27
|
+
<component name="TaskManager">
|
|
28
|
+
<task active="true" id="Default" summary="Default task">
|
|
29
|
+
<changelist id="4ad0dcde-54f6-459b-8ef0-38a17e946358" name="Changes" comment="" />
|
|
30
|
+
<created>1650076498224</created>
|
|
31
|
+
<option name="number" value="Default" />
|
|
32
|
+
<option name="presentableId" value="Default" />
|
|
33
|
+
<updated>1650076498224</updated>
|
|
34
|
+
</task>
|
|
35
|
+
<servers />
|
|
36
|
+
</component>
|
|
37
|
+
</project>
|
package/package.json
CHANGED
package/src/AuthApi.js
CHANGED
|
@@ -2,6 +2,13 @@ import {getApiRoot} from "./CrudApi";
|
|
|
2
2
|
import {FetchBuilder, initCsrfCookie} from "./api";
|
|
3
3
|
import UserPermissions from "./UserPermissions";
|
|
4
4
|
|
|
5
|
+
export const LOGIN_AGAIN_NOTIFICATION = {
|
|
6
|
+
message: 'You need to login again.',
|
|
7
|
+
type: 'is-warning',
|
|
8
|
+
duration: 5000,
|
|
9
|
+
queue: false
|
|
10
|
+
};
|
|
11
|
+
|
|
5
12
|
export default class AuthApi {
|
|
6
13
|
|
|
7
14
|
constructor($buefy) {
|
package/src/EventsApi.js
CHANGED
package/src/Internationalize.js
CHANGED
|
@@ -28,4 +28,16 @@ export default class Internationalize {
|
|
|
28
28
|
}
|
|
29
29
|
return format.format(datetime);
|
|
30
30
|
}
|
|
31
|
+
|
|
32
|
+
static formatDateTimeRange(from, to) {
|
|
33
|
+
let format = new Intl.DateTimeFormat(this.locale , {
|
|
34
|
+
hour: 'numeric', minute: 'numeric'
|
|
35
|
+
});
|
|
36
|
+
|
|
37
|
+
if(from.getDate() === to.getDate() && from.getMonth() === to.getMonth() && from.getYear() === to.getYear()) {
|
|
38
|
+
return this.formatDate(from) + " " + format.format(from) + " - " + format.format(to);
|
|
39
|
+
} else {
|
|
40
|
+
return this.formatDate(from) + " " + format.format(from) + " - " + this.formatDate(to) + format.format(to);
|
|
41
|
+
}
|
|
42
|
+
}
|
|
31
43
|
}
|
package/src/api.js
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import {getApiRoot} from "./CrudApi";
|
|
2
|
+
import {LOGIN_AGAIN_NOTIFICATION} from "./AuthApi";
|
|
2
3
|
|
|
3
4
|
export const getApiHost = () => {
|
|
4
5
|
if (parseInt(window.location.port) >= 3000) {
|
|
@@ -28,6 +29,7 @@ export const initCsrfCookie = async () => {
|
|
|
28
29
|
}
|
|
29
30
|
|
|
30
31
|
export class FetchBuilder {
|
|
32
|
+
|
|
31
33
|
constructor($buefy, method) {
|
|
32
34
|
this.$buefy = $buefy;
|
|
33
35
|
this.method = method;
|
|
@@ -120,7 +122,7 @@ export class FetchBuilder {
|
|
|
120
122
|
return data;
|
|
121
123
|
}
|
|
122
124
|
|
|
123
|
-
handleAPIError(data, this.$buefy, FetchBuilder.router, response);
|
|
125
|
+
await handleAPIError(data, this.$buefy, FetchBuilder.router, FetchBuilder.store, response);
|
|
124
126
|
let e = new Error('Received an error response from API call');
|
|
125
127
|
e.response = data;
|
|
126
128
|
throw e;
|
|
@@ -135,6 +137,10 @@ export class FetchBuilder {
|
|
|
135
137
|
static setRouter(router) {
|
|
136
138
|
FetchBuilder.router = router;
|
|
137
139
|
}
|
|
140
|
+
|
|
141
|
+
static setStore(store) {
|
|
142
|
+
FetchBuilder.store = store;
|
|
143
|
+
}
|
|
138
144
|
}
|
|
139
145
|
|
|
140
146
|
function statusToBueify(status) {
|
|
@@ -155,35 +161,29 @@ export function morphToNotification(data) {
|
|
|
155
161
|
};
|
|
156
162
|
}
|
|
157
163
|
|
|
158
|
-
const handleAPIError =
|
|
159
|
-
console.error('API error: ', content);
|
|
164
|
+
const handleAPIError = async (content, $buefy, $router, $store, response) => {
|
|
165
|
+
console.error('API error: ', content, $router);
|
|
160
166
|
if(response.status === 401 && content.code === 'unauthenticated') {
|
|
161
167
|
// server is telling us to login again
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
return;
|
|
168
|
+
await $store.commit('setUser', null);
|
|
169
|
+
await initCsrfCookie();
|
|
170
|
+
await $buefy.notification.open(LOGIN_AGAIN_NOTIFICATION);
|
|
171
|
+
await $router.push({path: '/auth/login', query: {redirect: $router.currentRoute.fullPath}});
|
|
167
172
|
} else if(response.status === 403 && content.code === 'two_factor_setup_required') {
|
|
168
|
-
$router.push({ path: '/auth/2fa-setup' });
|
|
169
|
-
return;
|
|
173
|
+
await $router.push({ path: '/auth/2fa-setup' });
|
|
170
174
|
} else if(response.status === 403 && content.code === 'email_unverified') {
|
|
171
|
-
$router.push({ path: '/auth/needs-verified-email', query: {redirect: $router.currentRoute.fullPath } });
|
|
172
|
-
return;
|
|
175
|
+
await $router.push({ path: '/auth/needs-verified-email', query: {redirect: $router.currentRoute.fullPath } });
|
|
173
176
|
} else if(response.status === 404) {
|
|
174
|
-
$router.push({ name: 'error404' });
|
|
177
|
+
await $router.push({ name: 'error404' });
|
|
175
178
|
} else if(response.status === 429) {
|
|
176
|
-
$buefy.notification.open({
|
|
179
|
+
await $buefy.notification.open({
|
|
177
180
|
message: 'Too many requests within a short timeframe. Please wait.',
|
|
178
181
|
type: 'is-warning',
|
|
179
182
|
duration: 10000,
|
|
180
183
|
queue: false
|
|
181
184
|
});
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
// handle generic validation errors
|
|
186
|
-
if(typeof content.errors === 'object') {
|
|
185
|
+
} else if(typeof content.errors === 'object') {
|
|
186
|
+
// handle generic validation errors
|
|
187
187
|
for(const [, errors ] of Object.entries(content.errors)) {
|
|
188
188
|
for(let error of errors) {
|
|
189
189
|
$buefy.notification.open({
|
|
@@ -194,13 +194,10 @@ const handleAPIError = function(content, $buefy, $router, response) {
|
|
|
194
194
|
});
|
|
195
195
|
}
|
|
196
196
|
}
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
if(content.content && content.status) {
|
|
201
|
-
$buefy.notification.open(morphToNotification(content));
|
|
197
|
+
} else if(content.content && content.status) {
|
|
198
|
+
await $buefy.notification.open(morphToNotification(content));
|
|
202
199
|
} else if(content.exception) {
|
|
203
|
-
$buefy.notification.open({
|
|
200
|
+
await $buefy.notification.open({
|
|
204
201
|
message:
|
|
205
202
|
'PHP Exception of type <pre class="no-pre">' + content.exception +
|
|
206
203
|
'</pre> with message <pre class="no-pre">' + content.message +
|
|
@@ -211,7 +208,7 @@ const handleAPIError = function(content, $buefy, $router, response) {
|
|
|
211
208
|
type: 'is-danger'
|
|
212
209
|
});
|
|
213
210
|
} else if(response.status === 500) {
|
|
214
|
-
$buefy.notification.open({
|
|
211
|
+
await $buefy.notification.open({
|
|
215
212
|
message:'Whoops, looks like something went wrong.',
|
|
216
213
|
type: 'is-danger',
|
|
217
214
|
animation: 'fade',
|
|
@@ -225,3 +222,4 @@ export function getXsrfToken() {
|
|
|
225
222
|
}
|
|
226
223
|
|
|
227
224
|
FetchBuilder.router = null;
|
|
225
|
+
FetchBuilder.store = null;
|
|
@@ -32,11 +32,44 @@
|
|
|
32
32
|
<script>
|
|
33
33
|
|
|
34
34
|
import AceEditor from 'vue2-ace-editor';
|
|
35
|
-
|
|
35
|
+
// language extension pre-requisite...
|
|
36
|
+
import 'brace/ext/language_tools';
|
|
36
37
|
import 'brace/mode/html';
|
|
37
38
|
import 'brace/mode/twig';
|
|
39
|
+
import 'brace/snippets/html';
|
|
40
|
+
import 'brace/snippets/twig';
|
|
38
41
|
import 'brace/theme/tomorrow_night_eighties';
|
|
39
42
|
import 'brace/theme/tomorrow_night';
|
|
43
|
+
import 'brace/theme/ambiance';
|
|
44
|
+
import 'brace/theme/chaos';
|
|
45
|
+
import 'brace/theme/clouds_midnight';
|
|
46
|
+
import 'brace/theme/cobalt';
|
|
47
|
+
import 'brace/theme/idle_fingers';
|
|
48
|
+
import 'brace/theme/merbivore';
|
|
49
|
+
import 'brace/theme/merbivore_soft';
|
|
50
|
+
import 'brace/theme/mono_industrial';
|
|
51
|
+
import 'brace/theme/monokai';
|
|
52
|
+
import 'brace/theme/pastel_on_dark';
|
|
53
|
+
import 'brace/theme/solarized_dark';
|
|
54
|
+
import 'brace/theme/terminal';
|
|
55
|
+
import 'brace/theme/tomorrow_night';
|
|
56
|
+
import 'brace/theme/tomorrow_night_blue';
|
|
57
|
+
import 'brace/theme/tomorrow_night_bright';
|
|
58
|
+
import 'brace/theme/tomorrow_night_eighties';
|
|
59
|
+
import 'brace/theme/twilight';
|
|
60
|
+
import 'brace/theme/vibrant_ink';
|
|
61
|
+
import 'brace/theme/chrome';
|
|
62
|
+
import 'brace/theme/clouds';
|
|
63
|
+
import 'brace/theme/crimson_editor';
|
|
64
|
+
import 'brace/theme/dawn';
|
|
65
|
+
import 'brace/theme/dreamweaver';
|
|
66
|
+
import 'brace/theme/eclipse';
|
|
67
|
+
import 'brace/theme/github';
|
|
68
|
+
import 'brace/theme/kr_theme';
|
|
69
|
+
import 'brace/theme/solarized_light';
|
|
70
|
+
import 'brace/theme/textmate';
|
|
71
|
+
import 'brace/theme/tomorrow';
|
|
72
|
+
import 'brace/theme/xcode';
|
|
40
73
|
|
|
41
74
|
export default {
|
|
42
75
|
name: "CodeEditor",
|
|
@@ -11,8 +11,9 @@
|
|
|
11
11
|
<script>
|
|
12
12
|
import MediaInsertModal from "./media/MediaInsertModal.vue";
|
|
13
13
|
|
|
14
|
-
import {getApiHost, morphToNotification} from "../api";
|
|
14
|
+
import {getApiHost, initCsrfCookie, morphToNotification} from "../api";
|
|
15
15
|
import MediaApi from "../MediaApi";
|
|
16
|
+
import {LOGIN_AGAIN_NOTIFICATION} from "../AuthApi";
|
|
16
17
|
|
|
17
18
|
// from https://gist.github.com/hdodov/a87c097216718655ead6cf2969b0dcfa
|
|
18
19
|
|
|
@@ -20,15 +21,6 @@ const iframeURLChange = (iframe, callback, legacyPage) => {
|
|
|
20
21
|
var unloadHandler = function() {
|
|
21
22
|
console.log('[LegacyPage] Starting load');
|
|
22
23
|
legacyPage.loadingPath = 'unknown';
|
|
23
|
-
// Timeout needed because the URL changes immediately after
|
|
24
|
-
// the `unload` event is dispatched.
|
|
25
|
-
// TODO: this is rather brittle because I believe it relies upon timing
|
|
26
|
-
// setTimeout(function() {
|
|
27
|
-
// console.log(iframe.contentWindow);
|
|
28
|
-
// if(iframe.contentWindow) {
|
|
29
|
-
// callback(iframe.contentWindow.location.href);
|
|
30
|
-
// }
|
|
31
|
-
// }, 0);
|
|
32
24
|
};
|
|
33
25
|
|
|
34
26
|
function attachUnload() {
|
|
@@ -90,7 +82,7 @@ export default {
|
|
|
90
82
|
iframe.addEventListener('load', this.onLoaded.bind(this));
|
|
91
83
|
if(iframe.contentDocument.readyState === "complete") {
|
|
92
84
|
console.warn('[LegacyPage] mounted: page was already loaded - perhaps this page was cached?');
|
|
93
|
-
this.onLoaded();
|
|
85
|
+
await this.onLoaded();
|
|
94
86
|
}
|
|
95
87
|
},
|
|
96
88
|
unmounted() {
|
|
@@ -126,7 +118,8 @@ export default {
|
|
|
126
118
|
let urlObj = new URL(url);
|
|
127
119
|
let urlString = urlObj.toString();
|
|
128
120
|
if(urlObj.pathname.startsWith(this.legacyPrefix)) {
|
|
129
|
-
|
|
121
|
+
let loc = urlString.split(this.legacyPrefix)[1];
|
|
122
|
+
return { loadInside: 'iframe', location: this.adminPrefix + loc, locationWithoutPrefix: loc };
|
|
130
123
|
} else if(urlObj.pathname.startsWith(this.adminPrefix)) {
|
|
131
124
|
return { loadInside: 'vue', location: urlString.split(this.adminPrefix)[1] };
|
|
132
125
|
} else {
|
|
@@ -155,7 +148,7 @@ export default {
|
|
|
155
148
|
popState() {
|
|
156
149
|
this.$router.back();
|
|
157
150
|
},
|
|
158
|
-
onLoaded() {
|
|
151
|
+
async onLoaded() {
|
|
159
152
|
let path = this.$refs.iframe.contentWindow.location.href;
|
|
160
153
|
if(path === 'about:blank') { return; }
|
|
161
154
|
console.log('[LegacyPage] Loaded', path);
|
|
@@ -166,12 +159,26 @@ export default {
|
|
|
166
159
|
if(loadInside === 'iframe') {
|
|
167
160
|
window.history.pushState({}, "", location);
|
|
168
161
|
} else if(loadInside === 'vue') {
|
|
169
|
-
|
|
162
|
+
if(location.startsWith('/auth/login?location=')) {
|
|
163
|
+
// If the legacy page is redirecting us to login,
|
|
164
|
+
// then that must be because our auth expired/failed.
|
|
165
|
+
// So we explicitly log ourselves out, and redirect to the login page.
|
|
166
|
+
let redirectTo = this.fullURLToVuePath(this.currentPath);
|
|
167
|
+
if(redirectTo.loadInside !== 'iframe') { throw new Error("this.currentPath was not inside iframe"); }
|
|
168
|
+
console.log("Requested redirect to /auth/login . Clearing user state first", redirectTo);
|
|
169
|
+
this.$store.commit('setUser', null);
|
|
170
|
+
this.$buefy.notification.open(LOGIN_AGAIN_NOTIFICATION);
|
|
171
|
+
await initCsrfCookie();
|
|
172
|
+
location = { name: 'login', query: { redirect: redirectTo.locationWithoutPrefix } };
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
await this.$router.push(location);
|
|
176
|
+
return;
|
|
170
177
|
} else {
|
|
171
178
|
// load outside of iframe
|
|
172
179
|
window.location = location;
|
|
180
|
+
return;
|
|
173
181
|
}
|
|
174
|
-
|
|
175
182
|
this.currentPath = path;
|
|
176
183
|
}
|
|
177
184
|
|
|
@@ -89,9 +89,6 @@ export default {
|
|
|
89
89
|
this.submitting = false;
|
|
90
90
|
this.hasFailedLogin = false;
|
|
91
91
|
this.$store.commit('setUser', response.user);
|
|
92
|
-
if(this.$route.query.location) {
|
|
93
|
-
window.location = this.$route.query.location;
|
|
94
|
-
}
|
|
95
92
|
this.$buefy.notification.open({
|
|
96
93
|
message: "You're now logged in.",
|
|
97
94
|
type: 'is-info',
|
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
<b-tab-item v-if="slotProps.canAccessPrefs(['appearance.themes', 'appearance.pages', 'appearance.events'].concat(getExtraPrefsPermissions('appearance')))" label="Website Theme">
|
|
5
5
|
<PreferencesThemeChooser @theme-changed="onThemeChanged" />
|
|
6
6
|
<PreferencesPageTemplates :current-theme="currentTheme" />
|
|
7
|
-
|
|
7
|
+
|
|
8
8
|
<PreferencesSiteAppearance :current-theme="currentTheme" />
|
|
9
9
|
<component :is="pref.component" v-for="pref in getExtraPrefs('appearance')" :key="pref.key" :current-theme="currentTheme" />
|
|
10
10
|
</b-tab-item>
|
|
@@ -4,6 +4,7 @@
|
|
|
4
4
|
<PreferencesField data-key="appearance.themes::theme" label="">
|
|
5
5
|
<template #default="slotProps">
|
|
6
6
|
<b-table
|
|
7
|
+
v-if="Object.values(slotProps.options).length > 0"
|
|
7
8
|
:data="Object.values(slotProps.options)"
|
|
8
9
|
:striped="false">
|
|
9
10
|
<b-table-column v-slot="props" label="Key">
|
|
@@ -26,6 +27,7 @@
|
|
|
26
27
|
<b-button v-else type="is-success" disabled>Theme is already active</b-button>
|
|
27
28
|
</b-table-column>
|
|
28
29
|
</b-table>
|
|
30
|
+
<p v-else class="has-text-centered"><em>No themes loaded.</em></p>
|
|
29
31
|
</template>
|
|
30
32
|
</PreferencesField>
|
|
31
33
|
</ShowIfPermitted>
|
package/src/icons.js
CHANGED
|
@@ -74,7 +74,7 @@ import {
|
|
|
74
74
|
faFolderOpen,
|
|
75
75
|
faImages,
|
|
76
76
|
faMinusCircle,
|
|
77
|
-
faCalendarPlus, faPaperPlane
|
|
77
|
+
faCalendarPlus, faPaperPlane, faHandshakeSlash, faHandshake
|
|
78
78
|
} from "@fortawesome/free-solid-svg-icons";
|
|
79
79
|
|
|
80
80
|
export const addIconsToLibrary = () => {
|
|
@@ -87,5 +87,5 @@ export const addIconsToLibrary = () => {
|
|
|
87
87
|
faFileExcel, faFileCsv, faChevronCircleDown, faChevronCircleUp, faTrash,
|
|
88
88
|
faEye, faEyeSlash, faCaretDown, faCaretUp, faUpload, faUser, faFolder, faHome, faFilePdf, faSignOutAlt, faTag,
|
|
89
89
|
faFolderPlus, faTimes, faQuestionCircle, faFileUpload, faLandmark,
|
|
90
|
-
faFolderOpen, faFile, faFileAudio, faFileImage, faShare, faImages, faCalendarPlus, faPaperPlane);
|
|
90
|
+
faFolderOpen, faFile, faFileAudio, faFileImage, faShare, faImages, faCalendarPlus, faPaperPlane, faHandshake, faHandshakeSlash);
|
|
91
91
|
};
|
package/src/main.js
CHANGED
|
@@ -12,7 +12,7 @@ import { AuthRoutes, makeAuthenticatedRoute } from "./routes";
|
|
|
12
12
|
import createStore from "./store/index";
|
|
13
13
|
import { checkAuthenticated } from "./AuthApi";
|
|
14
14
|
import Error404 from "./components/Error404.vue";
|
|
15
|
-
import
|
|
15
|
+
import Preferences from "./components/preferences/Preferences.vue";
|
|
16
16
|
|
|
17
17
|
/**
|
|
18
18
|
* Creates the Vue.js Oxygen application, allowing for a few points of customization (i.e.: adding modules)
|
|
@@ -29,6 +29,10 @@ export default class OxygenUI {
|
|
|
29
29
|
this.unauthenticatedRoutes = []
|
|
30
30
|
this.mainMenuItems = {}
|
|
31
31
|
this.beforeMountHooks = []
|
|
32
|
+
this.extraPrefs = {
|
|
33
|
+
'appearance': [],
|
|
34
|
+
'external': []
|
|
35
|
+
}
|
|
32
36
|
}
|
|
33
37
|
|
|
34
38
|
addAuthenticatedRoutes(routes) {
|
|
@@ -81,6 +85,15 @@ export default class OxygenUI {
|
|
|
81
85
|
|
|
82
86
|
const store = createStore(this.Vue);
|
|
83
87
|
|
|
88
|
+
this.authenticatedRoutes.push({
|
|
89
|
+
path: '/preferences',
|
|
90
|
+
component: Preferences,
|
|
91
|
+
props: {
|
|
92
|
+
extraPrefs: this.extraPrefs
|
|
93
|
+
},
|
|
94
|
+
meta: { title: 'System Preferences' }
|
|
95
|
+
});
|
|
96
|
+
|
|
84
97
|
const routes = AuthRoutes
|
|
85
98
|
.concat([
|
|
86
99
|
makeAuthenticatedRoute(this.authenticatedRoutes)
|
|
@@ -120,6 +133,7 @@ export default class OxygenUI {
|
|
|
120
133
|
});
|
|
121
134
|
|
|
122
135
|
FetchBuilder.setRouter(router);
|
|
136
|
+
FetchBuilder.setStore(store);
|
|
123
137
|
UserPermissions.setBuefy(this.app.$buefy);
|
|
124
138
|
UserPreferences.setBuefy(this.app.$buefy)
|
|
125
139
|
return this;
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import LegacyPage from "../components/LegacyPage.vue";
|
|
2
|
+
import { WEB_CONTENT } from "../main.js";
|
|
3
|
+
import PreferencesEventTemplates from "../components/preferences/PreferencesEventTemplates.vue";
|
|
4
|
+
|
|
5
|
+
export default function(ui) {
|
|
6
|
+
ui.addMainMenuGroup(WEB_CONTENT, {
|
|
7
|
+
name: 'Events',
|
|
8
|
+
icon: 'calendar-alt',
|
|
9
|
+
listAction: '/upcoming-events',
|
|
10
|
+
listPermission: 'upcomingEvents.getList',
|
|
11
|
+
addIcon: 'calendar-plus',
|
|
12
|
+
addPermission: 'upcomingEvents.postCreate',
|
|
13
|
+
addAction: '/upcoming-events/create',
|
|
14
|
+
items: {
|
|
15
|
+
}
|
|
16
|
+
});
|
|
17
|
+
ui.extraPrefs['appearance'].push({
|
|
18
|
+
key: 'appearance.events',
|
|
19
|
+
component: PreferencesEventTemplates
|
|
20
|
+
});
|
|
21
|
+
ui.addAuthenticatedRoutes([
|
|
22
|
+
{
|
|
23
|
+
// will match everything, try to render a legacy Oxygen page...
|
|
24
|
+
path: 'upcoming-events/:subpath*',
|
|
25
|
+
component: LegacyPage,
|
|
26
|
+
props: (route) => {
|
|
27
|
+
return {
|
|
28
|
+
fullPath: route.fullPath,
|
|
29
|
+
legacyPrefix: '/oxygen/view',
|
|
30
|
+
adminPrefix: '/oxygen'
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
]);
|
|
35
|
+
}
|
|
@@ -24,21 +24,10 @@ export default function(ui) {
|
|
|
24
24
|
items: {
|
|
25
25
|
}
|
|
26
26
|
});
|
|
27
|
-
ui.addMainMenuGroup(WEB_CONTENT, {
|
|
28
|
-
name: 'Events',
|
|
29
|
-
icon: 'calendar-alt',
|
|
30
|
-
listAction: '/upcoming-events',
|
|
31
|
-
listPermission: 'upcomingEvents.getList',
|
|
32
|
-
addIcon: 'calendar-plus',
|
|
33
|
-
addPermission: 'upcomingEvents.postCreate',
|
|
34
|
-
addAction: '/upcoming-events/create',
|
|
35
|
-
items: {
|
|
36
|
-
}
|
|
37
|
-
});
|
|
38
27
|
ui.addAuthenticatedRoutes([
|
|
39
28
|
{
|
|
40
29
|
// will match everything, try to render a legacy Oxygen page...
|
|
41
|
-
path: '(pages|partials
|
|
30
|
+
path: '(pages|partials)/:subpath*',
|
|
42
31
|
component: LegacyPage,
|
|
43
32
|
props: (route) => {
|
|
44
33
|
return {
|