@inriver/inri 1.0.0
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/.eslintrc.js +5 -0
- package/componentProperties.d.ts +8 -0
- package/configs/base-eslint-config.js +36 -0
- package/configs/base-tailwind-config.js +149 -0
- package/i18n.ts +11 -0
- package/index.ts +25 -0
- package/package.json +36 -0
- package/src/components/CAutoBreadcrumbs.vue +72 -0
- package/src/components/CBtn.vue +98 -0
- package/src/components/CColorPicker.vue +55 -0
- package/src/components/CContextMenu.vue +29 -0
- package/src/components/CDatePicker.vue +51 -0
- package/src/components/CDeleteTileBtn.vue +52 -0
- package/src/components/CDialog.vue +253 -0
- package/src/components/CDialogCloseBtn.vue +9 -0
- package/src/components/CDirtyCheck.vue +68 -0
- package/src/components/CDrawer.vue +44 -0
- package/src/components/CDrawerButton.vue +91 -0
- package/src/components/CExpansionItem.vue +57 -0
- package/src/components/CExpansionItemWithCheckbox.vue +41 -0
- package/src/components/CFileDropzone.vue +114 -0
- package/src/components/CGrid.vue +101 -0
- package/src/components/CHeader.vue +10 -0
- package/src/components/CHeaderLinks.vue +61 -0
- package/src/components/CHeaderMenuLink.vue +51 -0
- package/src/components/CHeaderSearch.vue +142 -0
- package/src/components/CIconBtn.vue +70 -0
- package/src/components/CMenuItem.vue +66 -0
- package/src/components/CPageContainer.vue +11 -0
- package/src/components/CPageError.vue +24 -0
- package/src/components/CPageSpinner.vue +18 -0
- package/src/components/CSearch.vue +45 -0
- package/src/components/CSection.vue +29 -0
- package/src/components/CSectionTitle.vue +8 -0
- package/src/components/CSelect.vue +208 -0
- package/src/components/CSlideEffect.vue +62 -0
- package/src/components/CSpinner.vue +107 -0
- package/src/components/CTableActions.vue +16 -0
- package/src/components/CTileBtn.vue +178 -0
- package/src/components/CTimePicker.vue +42 -0
- package/src/components/CToggleGridView.vue +26 -0
- package/src/components/CToggleSidebarBtn.vue +19 -0
- package/src/components/CTooltip.vue +44 -0
- package/src/components/CTreeNode.vue +39 -0
- package/src/components/cards/CBannerCard.vue +103 -0
- package/src/components/cards/CSmallCard.vue +149 -0
- package/src/components/internal-components/ConfirmDialog.vue +78 -0
- package/src/composables/useDialog.ts +47 -0
- package/src/composables/useDirtyCheck.ts +25 -0
- package/src/composables/useDoubleClickListener.ts +28 -0
- package/src/composables/useSelectable.ts +62 -0
- package/src/composables/useTruncateChips.ts +46 -0
- package/src/i18n/de/index.ts +17 -0
- package/src/i18n/en/index.ts +84 -0
- package/src/i18n/es/index.ts +7 -0
- package/src/i18n/fr/index.ts +7 -0
- package/src/init/initInriFramework.ts +25 -0
- package/src/init/useInriApp.ts +55 -0
- package/src/layouts/CLayoutBlank.vue +7 -0
- package/src/layouts/CLayoutWithBackButton.vue +50 -0
- package/src/layouts/CLayoutWithSidebars.vue +46 -0
- package/src/layouts/layout-fragments/CPageAutoBreadcrumbs.vue +6 -0
- package/src/layouts/layout-fragments/CPageBackButton.vue +18 -0
- package/src/layouts/layout-fragments/CPageBlank.vue +20 -0
- package/src/layouts/layout-fragments/CPageFlexCol.vue +5 -0
- package/src/layouts/layout-fragments/CPageLeftSidebar.vue +5 -0
- package/src/layouts/layout-fragments/CPageMainContent.vue +5 -0
- package/src/layouts/layout-fragments/CPageOuterWrapper.vue +5 -0
- package/src/layouts/layout-fragments/CPageRightSidebar.vue +5 -0
- package/src/layouts/layout-fragments/CPageTitle.vue +34 -0
- package/src/plugins/dialog.ts +45 -0
- package/src/plugins/errors/ErrorFactories.ts +59 -0
- package/src/plugins/errors/Errors.ts +156 -0
- package/src/plugins/errors/Exception.ts +6 -0
- package/src/plugins/errors/globalErrorHandler.ts +21 -0
- package/src/plugins/errors/handleError.ts +34 -0
- package/src/plugins/errors/logger.ts +16 -0
- package/src/plugins/errors/vueErrorHandler.ts +26 -0
- package/src/plugins/globalAppConfig.ts +25 -0
- package/src/plugins/i18n.ts +46 -0
- package/src/plugins/inriIcons.ts +58 -0
- package/src/plugins/inriverQuasarComponentConfigurations.ts +67 -0
- package/src/plugins/library.ts +119 -0
- package/src/plugins/notify.ts +153 -0
- package/src/plugins/quasar-user-options.ts +19 -0
- package/src/plugins/validationRules.ts +292 -0
- package/src/shims-vue.d.ts +6 -0
- package/src/stores/inriStore.ts +54 -0
- package/src/stores/interfaceLanguageStore.ts +27 -0
- package/src/styles/_css-variables.scss +101 -0
- package/src/styles/_reset.scss +67 -0
- package/src/styles/_transitions.scss +9 -0
- package/src/styles/_utils.scss +15 -0
- package/src/styles/components/_breadcrumbs.scss +3 -0
- package/src/styles/components/_checkboxes.scss +17 -0
- package/src/styles/components/_chips.scss +17 -0
- package/src/styles/components/_forms.scss +203 -0
- package/src/styles/components/_menu.scss +12 -0
- package/src/styles/components/_notifications.scss +24 -0
- package/src/styles/components/_q-editor.scss +14 -0
- package/src/styles/components/_radio-buttons.scss +17 -0
- package/src/styles/components/_tables.scss +92 -0
- package/src/styles/components/_tooltips.scss +5 -0
- package/src/styles/components/_tree.scss +86 -0
- package/src/styles/components/_truncated-chips.scss +39 -0
- package/src/styles/main.scss +45 -0
- package/src/styles/quasar.variables.scss +50 -0
- package/src/typings.d.ts +70 -0
- package/src/utils/colorUtils.ts +73 -0
- package/src/utils/errorUtils.ts +37 -0
- package/src/utils/fileUtils.ts +57 -0
- package/src/utils/helpers.ts +6 -0
- package/src/utils/routeUtils.ts +23 -0
- package/tsconfig.json +37 -0
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import '../styles/main.scss'
|
|
2
|
+
import 'windi.css'
|
|
3
|
+
import { App } from 'vue'
|
|
4
|
+
import { Quasar } from 'quasar'
|
|
5
|
+
import quasarUserOptions from '../plugins/quasar-user-options'
|
|
6
|
+
import { registerComponents } from '../plugins/library'
|
|
7
|
+
import { registerAppConfigurations } from '../plugins/globalAppConfig'
|
|
8
|
+
import { i18n } from '../plugins/i18n'
|
|
9
|
+
import logger from '../plugins/errors/logger'
|
|
10
|
+
import { VueErrorHandler } from '../plugins/errors/vueErrorHandler'
|
|
11
|
+
import '../plugins/errors/globalErrorHandler'
|
|
12
|
+
|
|
13
|
+
export const initInriFramework = (Vue: App): void => {
|
|
14
|
+
// Register C-components
|
|
15
|
+
registerComponents(Vue)
|
|
16
|
+
|
|
17
|
+
// Register global application configurations
|
|
18
|
+
registerAppConfigurations(Vue)
|
|
19
|
+
|
|
20
|
+
Vue.use(Quasar, quasarUserOptions)
|
|
21
|
+
Vue.use(i18n)
|
|
22
|
+
Vue.use(VueErrorHandler)
|
|
23
|
+
|
|
24
|
+
logger.init()
|
|
25
|
+
}
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
import { initInriIcons } from '../plugins/inriIcons'
|
|
2
|
+
import { useRouter, RouteLocationNormalized } from 'vue-router'
|
|
3
|
+
import { watch } from 'vue'
|
|
4
|
+
import { getRouteTitle } from '../utils/routeUtils'
|
|
5
|
+
import { useMeta } from 'quasar'
|
|
6
|
+
import { useInriStore } from '../stores/inriStore'
|
|
7
|
+
|
|
8
|
+
export default function useInriApp () {
|
|
9
|
+
const router = useRouter()
|
|
10
|
+
const inriStore = useInriStore()
|
|
11
|
+
|
|
12
|
+
initInriIcons()
|
|
13
|
+
|
|
14
|
+
router.beforeResolve((to) => {
|
|
15
|
+
setPageTitle(to)
|
|
16
|
+
setRouteTheme(to)
|
|
17
|
+
})
|
|
18
|
+
|
|
19
|
+
watch(inriStore.isAnyDirty, (value) => (
|
|
20
|
+
setDirtyPageTitle(value)
|
|
21
|
+
))
|
|
22
|
+
|
|
23
|
+
// Methods
|
|
24
|
+
function setPageTitle (to: RouteLocationNormalized) {
|
|
25
|
+
let pageTitle = ''
|
|
26
|
+
|
|
27
|
+
if (to.meta.title) {
|
|
28
|
+
pageTitle = getRouteTitle(to)
|
|
29
|
+
} else if (to.matched[0]) {
|
|
30
|
+
pageTitle = getRouteTitle(to.matched[0])
|
|
31
|
+
} else {
|
|
32
|
+
pageTitle = ''
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
document.title = pageTitle.length ? `inriver - ${pageTitle}` : 'inriver'
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
function setDirtyPageTitle (isDirty) {
|
|
39
|
+
if (isDirty) {
|
|
40
|
+
document.title = `* ${document.title}`
|
|
41
|
+
} else {
|
|
42
|
+
document.title = document.title.replace('* ', '')
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
function setRouteTheme (to) {
|
|
47
|
+
// This will create something like <body theme="route-demo-theme">
|
|
48
|
+
// It can then be used as a CSS selector for overriding colors
|
|
49
|
+
useMeta({
|
|
50
|
+
bodyAttr: {
|
|
51
|
+
theme: to.meta?.theme ? to.meta.theme : '',
|
|
52
|
+
},
|
|
53
|
+
})
|
|
54
|
+
}
|
|
55
|
+
}
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<c-page-blank class="border-t">
|
|
3
|
+
<c-page-flex-col>
|
|
4
|
+
<div
|
|
5
|
+
v-if="!hideTitle"
|
|
6
|
+
class="flex"
|
|
7
|
+
>
|
|
8
|
+
<c-page-back-button />
|
|
9
|
+
<c-page-title :title="title" />
|
|
10
|
+
</div>
|
|
11
|
+
|
|
12
|
+
<c-page-outer-wrapper>
|
|
13
|
+
<c-page-left-sidebar :style="{ width: leftSidebarWidth + 'px' }">
|
|
14
|
+
<slot name="left-sidebar" />
|
|
15
|
+
</c-page-left-sidebar>
|
|
16
|
+
|
|
17
|
+
<c-page-flex-col>
|
|
18
|
+
<c-page-auto-breadcrumbs v-if="showBreadcrumbs" />
|
|
19
|
+
|
|
20
|
+
<c-page-main-content>
|
|
21
|
+
<slot />
|
|
22
|
+
</c-page-main-content>
|
|
23
|
+
</c-page-flex-col>
|
|
24
|
+
</c-page-outer-wrapper>
|
|
25
|
+
</c-page-flex-col>
|
|
26
|
+
|
|
27
|
+
<c-page-right-sidebar :style="{ width: rightSidebarWidth + 'px' }">
|
|
28
|
+
<slot name="right-sidebar" />
|
|
29
|
+
</c-page-right-sidebar>
|
|
30
|
+
</c-page-blank>
|
|
31
|
+
</template>
|
|
32
|
+
|
|
33
|
+
<script setup lang="ts">
|
|
34
|
+
defineProps({
|
|
35
|
+
title: {
|
|
36
|
+
type: String,
|
|
37
|
+
default: undefined,
|
|
38
|
+
},
|
|
39
|
+
showBreadcrumbs: Boolean,
|
|
40
|
+
hideTitle: Boolean,
|
|
41
|
+
leftSidebarWidth: {
|
|
42
|
+
type: [String, Number],
|
|
43
|
+
default: '60',
|
|
44
|
+
},
|
|
45
|
+
rightSidebarWidth: {
|
|
46
|
+
type: [String, Number],
|
|
47
|
+
default: '60',
|
|
48
|
+
},
|
|
49
|
+
})
|
|
50
|
+
</script>
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<c-page-blank class="border-t">
|
|
3
|
+
<c-page-flex-col>
|
|
4
|
+
<c-page-outer-wrapper>
|
|
5
|
+
<c-page-left-sidebar :style="{ width: leftSidebarWidth + 'px' }">
|
|
6
|
+
<slot name="left-sidebar" />
|
|
7
|
+
</c-page-left-sidebar>
|
|
8
|
+
|
|
9
|
+
<c-page-flex-col>
|
|
10
|
+
<div v-if="!hideTitle">
|
|
11
|
+
<c-page-title :title="title" />
|
|
12
|
+
</div>
|
|
13
|
+
|
|
14
|
+
<c-page-auto-breadcrumbs v-if="showBreadcrumbs" />
|
|
15
|
+
|
|
16
|
+
<c-page-main-content>
|
|
17
|
+
<slot />
|
|
18
|
+
</c-page-main-content>
|
|
19
|
+
</c-page-flex-col>
|
|
20
|
+
</c-page-outer-wrapper>
|
|
21
|
+
</c-page-flex-col>
|
|
22
|
+
|
|
23
|
+
<c-page-right-sidebar :style="{ width: rightSidebarWidth + 'px' }">
|
|
24
|
+
<slot name="right-sidebar" />
|
|
25
|
+
</c-page-right-sidebar>
|
|
26
|
+
</c-page-blank>
|
|
27
|
+
</template>
|
|
28
|
+
|
|
29
|
+
<script setup lang="ts">
|
|
30
|
+
defineProps({
|
|
31
|
+
title: {
|
|
32
|
+
type: String,
|
|
33
|
+
default: undefined,
|
|
34
|
+
},
|
|
35
|
+
showBreadcrumbs: Boolean,
|
|
36
|
+
hideTitle: Boolean,
|
|
37
|
+
leftSidebarWidth: {
|
|
38
|
+
type: [String, Number],
|
|
39
|
+
default: '60',
|
|
40
|
+
},
|
|
41
|
+
rightSidebarWidth: {
|
|
42
|
+
type: [String, Number],
|
|
43
|
+
default: '60',
|
|
44
|
+
},
|
|
45
|
+
})
|
|
46
|
+
</script>
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<c-tile-btn
|
|
3
|
+
v-if="parentRoute"
|
|
4
|
+
data-id="page-back-btn"
|
|
5
|
+
icon="inri-arrow"
|
|
6
|
+
class="rotate-180"
|
|
7
|
+
:tooltip-right="$t('inri.navigate_back')"
|
|
8
|
+
:to="{ name: parentRoute }"
|
|
9
|
+
/>
|
|
10
|
+
</template>
|
|
11
|
+
|
|
12
|
+
<script setup lang="ts">
|
|
13
|
+
import { computed } from 'vue'
|
|
14
|
+
import { useRoute } from 'vue-router'
|
|
15
|
+
|
|
16
|
+
const route = useRoute()
|
|
17
|
+
const parentRoute = computed(() => route.meta?.parent)
|
|
18
|
+
</script>
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<div class="c-page">
|
|
3
|
+
<slot />
|
|
4
|
+
</div>
|
|
5
|
+
</template>
|
|
6
|
+
|
|
7
|
+
<script lang="ts">
|
|
8
|
+
export default {
|
|
9
|
+
name: 'CFragmentPage',
|
|
10
|
+
}
|
|
11
|
+
</script>
|
|
12
|
+
|
|
13
|
+
<style scoped>
|
|
14
|
+
.c-page {
|
|
15
|
+
position: absolute;
|
|
16
|
+
width: 100%;
|
|
17
|
+
height: 100%;
|
|
18
|
+
display: flex;
|
|
19
|
+
}
|
|
20
|
+
</style>
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<div
|
|
3
|
+
class="flex-1 flex h-15 items-center overflow-hidden px-6"
|
|
4
|
+
:class="noBorder || 'border-b'"
|
|
5
|
+
>
|
|
6
|
+
<h1
|
|
7
|
+
data-id="page-title"
|
|
8
|
+
class="truncate flex-1"
|
|
9
|
+
>
|
|
10
|
+
{{ title || routeTitle }}
|
|
11
|
+
</h1>
|
|
12
|
+
</div>
|
|
13
|
+
</template>
|
|
14
|
+
|
|
15
|
+
<script setup lang="ts">
|
|
16
|
+
import { getRouteTitle } from '../../utils/routeUtils'
|
|
17
|
+
import { computed } from 'vue'
|
|
18
|
+
import { useRoute } from 'vue-router'
|
|
19
|
+
|
|
20
|
+
const route = useRoute()
|
|
21
|
+
|
|
22
|
+
defineProps({
|
|
23
|
+
title: {
|
|
24
|
+
type: String,
|
|
25
|
+
default: undefined,
|
|
26
|
+
},
|
|
27
|
+
noBorder: {
|
|
28
|
+
type: Boolean,
|
|
29
|
+
default: false,
|
|
30
|
+
},
|
|
31
|
+
})
|
|
32
|
+
|
|
33
|
+
const routeTitle = computed(() => getRouteTitle(route))
|
|
34
|
+
</script>
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
import { Dialog } from 'quasar'
|
|
2
|
+
import ConfirmDialog from '../components/internal-components/ConfirmDialog.vue'
|
|
3
|
+
import { i18n } from './i18n'
|
|
4
|
+
|
|
5
|
+
const t = i18n.global.t
|
|
6
|
+
|
|
7
|
+
interface ConfirmDialogProps {
|
|
8
|
+
title?: string,
|
|
9
|
+
text: string,
|
|
10
|
+
confirmButtonText?: string,
|
|
11
|
+
cancelButtonText?: string,
|
|
12
|
+
confirmButtonColor?: string,
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
export default {
|
|
16
|
+
confirm: (props: ConfirmDialogProps) => {
|
|
17
|
+
return Dialog.create({
|
|
18
|
+
component: ConfirmDialog,
|
|
19
|
+
componentProps: {
|
|
20
|
+
...props,
|
|
21
|
+
},
|
|
22
|
+
})
|
|
23
|
+
},
|
|
24
|
+
info: (props: ConfirmDialogProps) => {
|
|
25
|
+
return Dialog.create({
|
|
26
|
+
component: ConfirmDialog,
|
|
27
|
+
componentProps: {
|
|
28
|
+
...props,
|
|
29
|
+
confirmButtonText: props.confirmButtonText || t('inri.common.ok'),
|
|
30
|
+
hideCancelButton: true,
|
|
31
|
+
},
|
|
32
|
+
})
|
|
33
|
+
},
|
|
34
|
+
delete: (props: ConfirmDialogProps) => {
|
|
35
|
+
return Dialog.create({
|
|
36
|
+
component: ConfirmDialog,
|
|
37
|
+
componentProps: {
|
|
38
|
+
...props,
|
|
39
|
+
title: props.title || t('inri.dialog.confirm_delete_title'),
|
|
40
|
+
confirmButtonText: props.confirmButtonText || t('inri.common.delete'),
|
|
41
|
+
confirmButtonColor: 'negative',
|
|
42
|
+
},
|
|
43
|
+
})
|
|
44
|
+
},
|
|
45
|
+
}
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
import {
|
|
2
|
+
BaseError,
|
|
3
|
+
BaseErrorArguments,
|
|
4
|
+
GenericError,
|
|
5
|
+
AxiosError,
|
|
6
|
+
UnauthorizedError,
|
|
7
|
+
NotFoundError,
|
|
8
|
+
FolderNotFoundError,
|
|
9
|
+
ServiceUnavailableError,
|
|
10
|
+
} from './Errors'
|
|
11
|
+
import axios from 'axios'
|
|
12
|
+
|
|
13
|
+
export class ErrorFactory {
|
|
14
|
+
static createHelpfulError (args: BaseErrorArguments): BaseError {
|
|
15
|
+
if (axios.isAxiosError(args.err)) {
|
|
16
|
+
return args.err.response
|
|
17
|
+
? this.createHelpfulErrorResponse(args.err.response.status, args)
|
|
18
|
+
: new AxiosError(args)
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
return new GenericError(args)
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
static createHelpfulErrorResponse (errorCode: number, args: BaseErrorArguments): AxiosError {
|
|
25
|
+
switch (errorCode) {
|
|
26
|
+
case 401:
|
|
27
|
+
return new UnauthorizedError(args)
|
|
28
|
+
case 404:
|
|
29
|
+
return new NotFoundError(args)
|
|
30
|
+
case 408:
|
|
31
|
+
case 503:
|
|
32
|
+
case 504:
|
|
33
|
+
return new ServiceUnavailableError(args)
|
|
34
|
+
default:
|
|
35
|
+
return new AxiosError(args)
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
export class FolderErrorFactory extends ErrorFactory {
|
|
41
|
+
static createHelpfulError (args: BaseErrorArguments) {
|
|
42
|
+
return super.createHelpfulError(args)
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
static createHelpfulErrorResponse (errorCode: number, args: BaseErrorArguments): AxiosError {
|
|
46
|
+
switch (errorCode) {
|
|
47
|
+
case 401:
|
|
48
|
+
return new UnauthorizedError(args)
|
|
49
|
+
case 404:
|
|
50
|
+
return new FolderNotFoundError(args)
|
|
51
|
+
case 408:
|
|
52
|
+
case 503:
|
|
53
|
+
case 504:
|
|
54
|
+
return new ServiceUnavailableError(args)
|
|
55
|
+
default:
|
|
56
|
+
return new AxiosError(args)
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
}
|
|
@@ -0,0 +1,156 @@
|
|
|
1
|
+
import { i18n } from '../i18n'
|
|
2
|
+
|
|
3
|
+
const $t = i18n.global.t
|
|
4
|
+
const $te = i18n.global.te
|
|
5
|
+
|
|
6
|
+
// ---------
|
|
7
|
+
// Interfaces
|
|
8
|
+
// ---------
|
|
9
|
+
export interface BaseError {
|
|
10
|
+
title: string,
|
|
11
|
+
msg: string,
|
|
12
|
+
err: any,
|
|
13
|
+
isAxiosError: boolean,
|
|
14
|
+
status?: number
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
export interface BaseErrorArguments {
|
|
18
|
+
defaultTitle?: string,
|
|
19
|
+
defaultMsg?: string,
|
|
20
|
+
title?: string,
|
|
21
|
+
msg?: string,
|
|
22
|
+
err: any
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
// ---------
|
|
26
|
+
// Implementations
|
|
27
|
+
// ---------
|
|
28
|
+
export class GenericError implements BaseError {
|
|
29
|
+
title: string
|
|
30
|
+
msg: string
|
|
31
|
+
err: any
|
|
32
|
+
isAxiosError = false
|
|
33
|
+
|
|
34
|
+
constructor (
|
|
35
|
+
public args: BaseErrorArguments,
|
|
36
|
+
private defaultTitle = $t('inri.error.error'),
|
|
37
|
+
private defaultMsg = $t('inri.error.error_occurred'),
|
|
38
|
+
) {
|
|
39
|
+
this.defaultTitle = args?.defaultTitle || this.defaultTitle
|
|
40
|
+
this.defaultMsg = args?.defaultMsg || this.defaultMsg
|
|
41
|
+
this.title = args?.title ?? this.defaultTitle
|
|
42
|
+
this.msg = args?.msg ?? this.defaultMsg
|
|
43
|
+
this.err = args.err
|
|
44
|
+
|
|
45
|
+
this.processError()
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
private processError () {
|
|
49
|
+
let errorMessage
|
|
50
|
+
|
|
51
|
+
if (this.err.type === 'unhandledrejection') {
|
|
52
|
+
errorMessage = this.err.reason?.toString() || $t('inri.error.unknown_error')
|
|
53
|
+
} else {
|
|
54
|
+
errorMessage = this.err.msg || this.err.toString()
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
if (this.msg === this.defaultMsg) {
|
|
58
|
+
this.msg = errorMessage
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
export class AxiosError implements BaseError {
|
|
64
|
+
title: string
|
|
65
|
+
msg: string
|
|
66
|
+
err: any
|
|
67
|
+
isAxiosError = true
|
|
68
|
+
status = -1
|
|
69
|
+
|
|
70
|
+
constructor (
|
|
71
|
+
public args: BaseErrorArguments,
|
|
72
|
+
private defaultTitle = $t('inri.error.network_error'),
|
|
73
|
+
private defaultMsg = $t('inri.error.error_occurred'),
|
|
74
|
+
) {
|
|
75
|
+
this.title = args?.title ?? this.defaultTitle
|
|
76
|
+
this.msg = args?.msg ?? this.defaultMsg
|
|
77
|
+
this.err = args.err
|
|
78
|
+
|
|
79
|
+
this.processError()
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
private processError () {
|
|
83
|
+
let errorMessage
|
|
84
|
+
|
|
85
|
+
if (this.err.response) {
|
|
86
|
+
// The request was made and the server responded with a status code
|
|
87
|
+
// that falls out of the range of 2xx
|
|
88
|
+
|
|
89
|
+
this.status = this.err.response.status
|
|
90
|
+
errorMessage = $te(`inri.error.${this.err.response.data?.errorDescription}`)
|
|
91
|
+
? $t(`inri.error.${this.err.response.data?.errorDescription}`)
|
|
92
|
+
: null
|
|
93
|
+
} else if (this.err.request) {
|
|
94
|
+
// The request was made but no response was received
|
|
95
|
+
// `this.err.request` is an instance of XMLHttpRequest in the browser and an instance of
|
|
96
|
+
// http.ClientRequest in node.js
|
|
97
|
+
|
|
98
|
+
this.status = this.err.request.status
|
|
99
|
+
errorMessage = this.err.request.statusText
|
|
100
|
+
} else {
|
|
101
|
+
// Something happened in setting up the request that triggered an Error
|
|
102
|
+
|
|
103
|
+
errorMessage = this.err.message
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
if (errorMessage && this.msg === this.defaultMsg) {
|
|
107
|
+
this.msg = errorMessage
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
// ---------
|
|
113
|
+
// Extensions
|
|
114
|
+
// ---------
|
|
115
|
+
export class UnauthorizedError extends AxiosError {
|
|
116
|
+
constructor (public args: BaseErrorArguments) {
|
|
117
|
+
super(
|
|
118
|
+
args,
|
|
119
|
+
$t('inri.error.unauthorized'),
|
|
120
|
+
$t('inri.error.session_expired'),
|
|
121
|
+
)
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
export class NotFoundError extends AxiosError {
|
|
126
|
+
constructor (public args: BaseErrorArguments) {
|
|
127
|
+
super(
|
|
128
|
+
args,
|
|
129
|
+
$t('inri.error.not_found'),
|
|
130
|
+
$t('inri.error.requested_asset_not_found'),
|
|
131
|
+
)
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
export class ServiceUnavailableError extends AxiosError {
|
|
136
|
+
constructor (public args: BaseErrorArguments) {
|
|
137
|
+
super(
|
|
138
|
+
args,
|
|
139
|
+
$t('inri.error.service_unavailable'),
|
|
140
|
+
$t('inri.error.service_unavailable_try_again'),
|
|
141
|
+
)
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
// ---------
|
|
146
|
+
// Specific error subtypes
|
|
147
|
+
// ---------
|
|
148
|
+
export class FolderNotFoundError extends AxiosError {
|
|
149
|
+
constructor (public args: BaseErrorArguments) {
|
|
150
|
+
super(
|
|
151
|
+
args,
|
|
152
|
+
$t('inri.error.not_found'),
|
|
153
|
+
$t('inri.error.could_not_retrieve_assets'),
|
|
154
|
+
)
|
|
155
|
+
}
|
|
156
|
+
}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import handleError from './handleError'
|
|
2
|
+
|
|
3
|
+
// Handle errors outside of components
|
|
4
|
+
window.addEventListener('error', (event) => {
|
|
5
|
+
handleError(
|
|
6
|
+
{
|
|
7
|
+
err: event,
|
|
8
|
+
caughtBy: 'window eventListener on error',
|
|
9
|
+
},
|
|
10
|
+
)
|
|
11
|
+
})
|
|
12
|
+
|
|
13
|
+
// Handle rejected promises outside components
|
|
14
|
+
window.addEventListener('unhandledrejection', (event) => {
|
|
15
|
+
handleError(
|
|
16
|
+
{
|
|
17
|
+
err: event,
|
|
18
|
+
caughtBy: 'window eventListener on unhandledrejection',
|
|
19
|
+
},
|
|
20
|
+
)
|
|
21
|
+
})
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import { Exception } from './Exception'
|
|
2
|
+
import { ErrorFactory } from './ErrorFactories'
|
|
3
|
+
import logger from './logger'
|
|
4
|
+
import notify from '../notify'
|
|
5
|
+
import dialog from '../dialog'
|
|
6
|
+
|
|
7
|
+
export default function handleError (errInfoObj, vueInfoObj?) {
|
|
8
|
+
const err = errInfoObj.err
|
|
9
|
+
|
|
10
|
+
if (err instanceof Exception) {
|
|
11
|
+
const parsedError = ErrorFactory.createHelpfulError({
|
|
12
|
+
defaultMsg: err.msg,
|
|
13
|
+
err: err.error,
|
|
14
|
+
})
|
|
15
|
+
|
|
16
|
+
dialog.info({
|
|
17
|
+
title: parsedError.title,
|
|
18
|
+
text: parsedError.msg,
|
|
19
|
+
})
|
|
20
|
+
|
|
21
|
+
errInfoObj.handledBy = 'handleError'
|
|
22
|
+
logger.logTrace(errInfoObj, vueInfoObj)
|
|
23
|
+
} else if (err) {
|
|
24
|
+
const parsedError = ErrorFactory.createHelpfulError({ err })
|
|
25
|
+
notify.error(parsedError.msg)
|
|
26
|
+
|
|
27
|
+
if (err.type === 'unhandledrejection') {
|
|
28
|
+
errInfoObj.handledBy = '-'
|
|
29
|
+
logger.logTrace(errInfoObj, vueInfoObj)
|
|
30
|
+
} else {
|
|
31
|
+
logger.logException(err)
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
export default {
|
|
2
|
+
init () {
|
|
3
|
+
// TODO: Init logger
|
|
4
|
+
},
|
|
5
|
+
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
6
|
+
logTrace (errInfoObj, vueInfoObj?) {
|
|
7
|
+
console.log('LOGGING TRACE')
|
|
8
|
+
console.log(errInfoObj)
|
|
9
|
+
// TODO: Log something
|
|
10
|
+
},
|
|
11
|
+
logException (error) {
|
|
12
|
+
console.log('LOGGING EXCEPTION')
|
|
13
|
+
console.log(error)
|
|
14
|
+
// TODO: Log something
|
|
15
|
+
},
|
|
16
|
+
}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import handleError from './handleError'
|
|
2
|
+
import { Exception } from './Exception'
|
|
3
|
+
import { ComponentPublicInstance } from 'vue'
|
|
4
|
+
|
|
5
|
+
export function VueErrorHandler (app) {
|
|
6
|
+
// Exception handling within Vue components
|
|
7
|
+
app.config.errorHandler = (err, vm: ComponentPublicInstance | null, info: string) => {
|
|
8
|
+
let exception
|
|
9
|
+
|
|
10
|
+
if (err instanceof Exception) {
|
|
11
|
+
exception = err
|
|
12
|
+
} else {
|
|
13
|
+
exception = new Exception(err.message, err)
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
handleError(
|
|
17
|
+
{
|
|
18
|
+
err: exception,
|
|
19
|
+
caughtBy: 'app.config.errorHandler',
|
|
20
|
+
},
|
|
21
|
+
{
|
|
22
|
+
info: info,
|
|
23
|
+
},
|
|
24
|
+
)
|
|
25
|
+
}
|
|
26
|
+
}
|