Add more typescript definitions

This commit is contained in:
Ramon Wenger 2022-02-23 23:43:43 +01:00
parent 07ac265e43
commit cf9eb76ae2
13 changed files with 94 additions and 57 deletions

12
client/src/@types/graphql.d.ts vendored Normal file
View File

@ -0,0 +1,12 @@
declare module '*.graphql' {
import {DocumentNode} from "graphql";
const Schema: DocumentNode;
export = Schema;
}
declare module '*.gql' {
import {DocumentNode} from "graphql";
const content: DocumentNode;
export default content;
}

8
client/src/@types/vuejs-logger.d.ts vendored Normal file
View File

@ -0,0 +1,8 @@
import Vue from 'vue';
import {Log} from "vuejs-logger";
declare module 'vue/types/vue' {
interface Vue {
$log: Log
}
}

View File

@ -126,11 +126,11 @@
import AddContentLink from '@/components/content-block-form/AddContentLink.vue'; import AddContentLink from '@/components/content-block-form/AddContentLink.vue';
import ContentElement from '@/components/content-block-form/ContentElement.vue'; import ContentElement from '@/components/content-block-form/ContentElement.vue';
import {moveToIndex, removeAtIndex, replaceAtIndex, swapElements} from '@/graphql/immutable-operations.js'; import {moveToIndex, removeAtIndex, replaceAtIndex, swapElements} from '@/graphql/immutable-operations';
import {CHOOSER, transformInnerContents} from '@/components/content-block-form/helpers.js'; import {CHOOSER, transformInnerContents} from '@/components/content-block-form/helpers.js';
import ContentElementActions from '@/components/content-block-form/ContentElementActions.vue'; import ContentElementActions from '@/components/content-block-form/ContentElementActions.vue';
import {ContentBlock, numberOrUndefined} from "@/types"; import {ContentBlock, numberOrUndefined} from "@/@types";
// TODO: refactor this file, it's huuuuuge! // TODO: refactor this file, it's huuuuuge!
@ -170,7 +170,7 @@
}, },
}, },
methods: { methods: {
update(index: number, element: any, parent: numberOrUndefined = undefined) { update(index: number, element: any, parent?: number) {
if (parent === undefined) { if (parent === undefined) {
// element is top level // element is top level
this.localContentBlock.contents = [ this.localContentBlock.contents = [
@ -195,7 +195,7 @@
]; ];
} }
}, },
addBlock(afterOuterIndex: number, innerIndex: numberOrUndefined = undefined) { addBlock(afterOuterIndex: number, innerIndex?: number) {
if (innerIndex !== undefined) { if (innerIndex !== undefined) {
const block = this.localContentBlock.contents[afterOuterIndex]; const block = this.localContentBlock.contents[afterOuterIndex];
this.localContentBlock.contents = [ this.localContentBlock.contents = [
@ -225,7 +225,7 @@
]; ];
} }
}, },
remove(outer: number, inner: numberOrUndefined = undefined, askForConfirmation = true) { remove(outer: number, inner?: number, askForConfirmation = true) {
if(askForConfirmation) { if(askForConfirmation) {
this.$modal.open('confirm') this.$modal.open('confirm')
.then(() => { .then(() => {

View File

@ -55,7 +55,7 @@ import DELETE_PROJECT_MUTATION from '@/graphql/gql/mutations/deleteProject.gql';
import PROJECTS_QUERY from '@/graphql/gql/queries/allProjects.gql'; import PROJECTS_QUERY from '@/graphql/gql/queries/allProjects.gql';
import updateProjectShareState from '@/mixins/update-project-share-state'; import updateProjectShareState from '@/mixins/update-project-share-state';
import {removeAtIndex} from '@/graphql/immutable-operations'; import {removeAtIndex} from '@/graphql/immutable-operations.ts';
const Ellipses = () => import(/* webpackChunkName: "icons" */'@/components/icons/Ellipses.vue'); const Ellipses = () => import(/* webpackChunkName: "icons" */'@/components/icons/Ellipses.vue');
export default { export default {

View File

@ -52,7 +52,7 @@
import DELETE_PROJECT_ENTRY_MUTATION from '@/graphql/gql/mutations/deleteProjectEntry.gql'; import DELETE_PROJECT_ENTRY_MUTATION from '@/graphql/gql/mutations/deleteProjectEntry.gql';
import PROJECT_QUERY from '@/graphql/gql/queries/projectQuery.gql'; import PROJECT_QUERY from '@/graphql/gql/queries/projectQuery.gql';
import {dateFilter, dateTimeFilter} from '@/filters/date-filter'; import {dateFilter, dateTimeFilter} from '@/filters/date-filter';
import {removeAtIndex} from '@/graphql/immutable-operations'; import {removeAtIndex} from '@/graphql/immutable-operations.ts';
const DocumentBlock = () => import(/* webpackChunkName: "content-components" */'@/components/content-blocks/DocumentBlock'); const DocumentBlock = () => import(/* webpackChunkName: "content-components" */'@/components/content-blocks/DocumentBlock');

View File

@ -1,24 +1,24 @@
// signature should be in order: arr, idx, el, for readability // signature should be in order: arr, idx, el, for readability
export const pushToArray = (arr, el) => { export const pushToArray = (arr: any[], el: any) => {
if (!arr) { if (!arr) {
return [el]; return [el];
} }
return [...arr, el]; return [...arr, el];
}; };
export const insertAtIndex = (arr, idx, el) => { export const insertAtIndex = (arr: any[], idx: number, el: any) => {
return [ return [
...arr.slice(0, idx), ...arr.slice(0, idx),
el, el,
...arr.slice(idx) ...arr.slice(idx)
]; ];
}; };
export const removeAtIndex = (arr, idx) => { export const removeAtIndex = (arr: any[], idx: number) => {
return [ return [
...arr.slice(0, idx), ...arr.slice(0, idx),
...arr.slice(idx + 1) , ...arr.slice(idx + 1) ,
]; ];
}; };
export const replaceAtIndex = (arr, idx, el) => { export const replaceAtIndex = (arr: any[], idx: number, el: any) => {
//todo: check array index bounds, numbers //todo: check array index bounds, numbers
return [ return [
...arr.slice(0, idx), ...arr.slice(0, idx),
@ -26,7 +26,7 @@ export const replaceAtIndex = (arr, idx, el) => {
...arr.slice(idx+1) ...arr.slice(idx+1)
]; ];
}; };
export const swapElements = (arr, idx1, idx2)=>{ export const swapElements = (arr: any[], idx1: number, idx2: number)=>{
const maxLength = arr.length - 1; const maxLength = arr.length - 1;
if (idx1 < 0 || idx2 < 0 || idx1 > maxLength || idx2 > maxLength) { if (idx1 < 0 || idx2 < 0 || idx1 > maxLength || idx2 > maxLength) {
return [...arr]; return [...arr];
@ -42,7 +42,7 @@ export const swapElements = (arr, idx1, idx2)=>{
...arr.slice(larger+1) ...arr.slice(larger+1)
]; ];
}; };
export const moveToIndex = (arr, from, to) => { export const moveToIndex = (arr: any[], from: number, to: number) => {
const maxLength = arr.length - 1; const maxLength = arr.length - 1;
if (from < 0 || to < 0 || from > maxLength || to > maxLength) { if (from < 0 || to < 0 || from > maxLength || to > maxLength) {
throw new Error('Index out of bounds'); throw new Error('Index out of bounds');

View File

@ -3,7 +3,7 @@ import Vue from 'vue';
import VueVimeoPlayer from 'vue-vimeo-player'; import VueVimeoPlayer from 'vue-vimeo-player';
import apolloClientFactory from './graphql/client'; import apolloClientFactory from './graphql/client';
import VueApollo from 'vue-apollo'; import VueApollo from 'vue-apollo';
import App from './App'; import App from './App.vue';
import {postLoginRedirectUrlKey, router} from './router'; import {postLoginRedirectUrlKey, router} from './router';
import store from '@/store/index'; import store from '@/store/index';
import VueScrollTo from 'vue-scrollto'; import VueScrollTo from 'vue-scrollto';
@ -15,6 +15,7 @@ import VueRemoveEdges from '@/plugins/edges';
import VueMatomo from 'vue-matomo'; import VueMatomo from 'vue-matomo';
import VueToast from 'vue-toast-notification'; import VueToast from 'vue-toast-notification';
import VueLogger from 'vuejs-logger'; import VueLogger from 'vuejs-logger';
import {joiningClass, loginRequired, unauthorizedAccess} from "@/router/guards";
Vue.config.productionTip = false; Vue.config.productionTip = false;
const isProduction = process.env.NODE_ENV === 'production'; const isProduction = process.env.NODE_ENV === 'production';
@ -60,20 +61,7 @@ const apolloProvider = new VueApollo({
/* guards */ /* guards */
function getCookieValue(cookieName) {
// https://stackoverflow.com/questions/5639346/what-is-the-shortest-function-for-reading-a-cookie-by-name-in-javascript
let cookieValue = document.cookie.match('(^|[^;]+)\\s*' + cookieName + '\\s*=\\s*([^;]+)');
return cookieValue ? cookieValue.pop() : '';
}
function loginRequired(to) {
// public pages have the meta.public property set to true
return !Object.prototype.hasOwnProperty.call(to, 'meta') || !Object.prototype.hasOwnProperty.call(to.meta ,'public') || !to.meta.public;
}
function unauthorizedAccess(to) {
return loginRequired(to) && getCookieValue('loginStatus') !== 'true';
}
function redirectUsersWithoutValidLicense() { function redirectUsersWithoutValidLicense() {
return privateApolloClient.query({ return privateApolloClient.query({
@ -100,9 +88,6 @@ function networkErrorCallback(statusCode) {
} }
} }
function joiningClass(to) {
return to.name && (to.name === 'join-class' || to.name === 'licenseActivation');
}
router.beforeEach(async (to, from, next) => { router.beforeEach(async (to, from, next) => {
Vue.$log.debug('navigation guard called', to, from); Vue.$log.debug('navigation guard called', to, from);

View File

@ -1,13 +0,0 @@
import Vue from 'vue';
interface Modal {
confirm: (res: any) => void,
open: (component: string, payload?: any) => Promise<(resolve: () => any, reject: () => any) => void>,
cancel: () => void
}
declare module 'vue/types/vue' {
interface Vue {
$modal: Modal
}
}

View File

@ -1,8 +1,11 @@
// adapted from // adapted from
// https://stackoverflow.com/questions/41791193/vuejs-reactive-binding-for-a-plugin-how-to/41801107#41801107 // https://stackoverflow.com/questions/41791193/vuejs-reactive-binding-for-a-plugin-how-to/41801107#41801107
import Vue from 'vue'; import Vue, {VueConstructor} from 'vue';
class ModalStore {
vm: Vue;
class ModalStore {
constructor() { constructor() {
this.vm = new Vue({ this.vm = new Vue({
data: () => ({ data: () => ({
@ -17,20 +20,37 @@ class ModalStore {
} }
} }
interface Modal {
state: any,
component: string,
payload?: any,
confirm: (res: any) => void,
open: (component: string, payload?: any) => Promise<(resolve: () => any, reject: () => any) => void>,
cancel: () => void,
_resolve: (r?: any) => any,
_reject: (r?: any) => any
}
declare module 'vue/types/vue' {
interface Vue {
$modal: Modal
}
}
const ModalPlugin = { const ModalPlugin = {
install(Vue) { install(Vue: VueConstructor) {
const store = new ModalStore({}); const store = new ModalStore();
const reset = () => { const reset = () => {
store.state.component = ''; store.state.component = '';
store.state.payload = {}; store.state.payload = {};
}; };
Vue.prototype.$modal = { const modal: Modal = {
state: store.state, state: store.state,
component: store.state.component, component: store.state.component,
payload: store.state.payload, payload: store.state.payload,
open: (component, payload) => { open(component: string, payload?: any) {
store.state.payload = payload; store.state.payload = payload;
store.state.component = component; store.state.component = component;
return new Promise((resolve, reject) => { return new Promise((resolve, reject) => {
@ -38,11 +58,11 @@ const ModalPlugin = {
this._reject = reject; this._reject = reject;
}); });
}, },
confirm: (res) => { confirm(res: any) {
reset(); reset();
this._resolve(res); this._resolve(res);
}, },
cancel: () => { cancel() {
reset(); reset();
this._reject(); this._reject();
}, },
@ -51,6 +71,8 @@ const ModalPlugin = {
_reject: () => { _reject: () => {
}, },
}; };
Vue.prototype.$modal = modal;
} }
}; };

View File

@ -0,0 +1,21 @@
import {Route} from "vue-router";
function getCookieValue(cookieName: string) {
// https://stackoverflow.com/questions/5639346/what-is-the-shortest-function-for-reading-a-cookie-by-name-in-javascript
const cookieValue = document.cookie.match('(^|[^;]+)\\s*' + cookieName + '\\s*=\\s*([^;]+)');
return cookieValue ? cookieValue.pop() : '';
}
export function loginRequired(to: Route) {
// public pages have the meta.public property set to true
const isPublic = to.meta && to.meta.public;
return !isPublic;
}
export function unauthorizedAccess(to: Route) {
return loginRequired(to) && getCookieValue('loginStatus') !== 'true';
}
export function joiningClass(to: Route) {
return to.name && (to.name === 'join-class' || to.name === 'licenseActivation');
}

8
client/src/router/router.d.ts vendored Normal file
View File

@ -0,0 +1,8 @@
import 'vue-router';
declare module 'vue-router' {
interface RouteMeta {
public?: boolean;
}
}

View File

@ -12,12 +12,6 @@
"paths": { "paths": {
"@/*": ["./*"], "@/*": ["./*"],
}, },
"types": [
"cypress"
],
"plugins": [{"name": "typescript-tslint-plugin"}] "plugins": [{"name": "typescript-tslint-plugin"}]
}, },
"include": [
"**/*.*"
]
} }