bt-core-app 1.1.8 → 1.2.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/dist/bt-core-app.js +20837 -14524
- package/dist/components/BT-Btn.vue.d.ts +41 -0
- package/dist/components/BT-Col.vue.d.ts +49 -0
- package/dist/components/Dialog-Confirm.vue.d.ts +2 -2
- package/dist/components/Dialog-Select-Date.vue.d.ts +2 -2
- package/dist/components/Dialog-Select.vue.d.ts +2 -2
- package/dist/components/Dialog-Text.vue.d.ts +2 -2
- package/dist/composables/actions.d.ts +6 -6
- package/dist/composables/api.d.ts +1 -0
- package/dist/composables/auth.d.ts +1 -0
- package/dist/composables/cosmetics.d.ts +3 -1
- package/dist/composables/dates.d.ts +1 -0
- package/dist/composables/demo.d.ts +1 -0
- package/dist/composables/filters.d.ts +1 -0
- package/dist/composables/list.d.ts +2 -2
- package/dist/composables/navigation.d.ts +1 -0
- package/dist/composables/presets.d.ts +1 -0
- package/dist/composables/pwa.d.ts +1 -0
- package/dist/composables/stores.d.ts +17 -6
- package/dist/index.d.ts +11 -12
- package/dist/style.css +1 -1
- package/dist/useApi.d.ts +0 -30
- package/package.json +2 -1
- package/src/components/BT-Btn.vue +1 -1
- package/src/components/BT-Field-Checkbox.vue +70 -0
- package/src/components/BT-Field-Date.vue +112 -0
- package/src/components/BT-Field-Entity.vue +48 -0
- package/src/components/BT-Field-Select.vue +67 -0
- package/src/components/BT-Field-String.vue +78 -0
- package/src/components/BT-Field-Switch.vue +68 -0
- package/src/components/BT-Field-Tags.vue +66 -0
- package/src/components/BT-Field-Textarea.vue +67 -0
- package/src/components/BT-Field-Trigger.vue +315 -0
- package/src/components/BT-Header-Option.vue +39 -0
- package/src/components/BT-Json.vue +67 -0
- package/src/components/BT-Select-List-Box.vue +258 -0
- package/src/components/BT-Select.vue +46 -0
- package/src/components/BT-Snack.vue +31 -0
- package/src/components/Dialog-Select-Date.vue +1 -1
- package/src/composables/actions.ts +6 -6
- package/src/composables/api.ts +9 -1
- package/src/composables/auth.ts +8 -19
- package/src/composables/cosmetics.ts +27 -28
- package/src/composables/dates.ts +9 -1
- package/src/composables/demo.ts +9 -1
- package/src/composables/filters.ts +9 -1
- package/src/composables/list.ts +6 -3
- package/src/composables/navigation.ts +9 -1
- package/src/composables/presets.ts +9 -1
- package/src/composables/pwa.ts +9 -1
- package/src/composables/stores.ts +32 -11
- package/src/core.ts +49 -16
- package/src/index.ts +12 -12
- package/src/types.ts +5 -1
- package/src/useApi.ts +57 -57
- package/vite.config.ts +6 -2
- package/.vscode/extensions.json +0 -3
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<v-card max-height="350" class="overflow-y-auto">
|
|
3
|
+
<v-card-text>
|
|
4
|
+
<div v-for="(j, ind) in display" :key="ind">
|
|
5
|
+
<pre v-html="syntaxHighlight(j)"></pre>
|
|
6
|
+
</div>
|
|
7
|
+
</v-card-text>
|
|
8
|
+
</v-card>
|
|
9
|
+
</template>
|
|
10
|
+
|
|
11
|
+
<script setup lang="ts">
|
|
12
|
+
import { computed } from 'vue'
|
|
13
|
+
|
|
14
|
+
const props = defineProps(['value'])
|
|
15
|
+
|
|
16
|
+
const display = computed(() => {
|
|
17
|
+
if (props.value == null) {
|
|
18
|
+
return []
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
if (Array.isArray(props.value))
|
|
22
|
+
return props.value
|
|
23
|
+
|
|
24
|
+
return [props.value]
|
|
25
|
+
})
|
|
26
|
+
|
|
27
|
+
function syntaxHighlight(json: any) {
|
|
28
|
+
if (typeof json != 'string') {
|
|
29
|
+
json = JSON.stringify(json, undefined, 2); //Object.keys(json).sort(), 2);
|
|
30
|
+
}
|
|
31
|
+
json = json.replace(/&/g, '&').replace(/</g, '<').replace(/>/g, '>');
|
|
32
|
+
|
|
33
|
+
const e = json.replace(/("(\\u[a-zA-Z0-9]{4}|\\[^u]|[^\\"])*"(\s*:)?|\b(true|false|null)\b|-?\d+(?:\.\d*)?(?:[eE][+\-]?\d+)?)/g, function (match: any) {
|
|
34
|
+
var cls = 'number';
|
|
35
|
+
if (/^"/.test(match)) {
|
|
36
|
+
if (/:$/.test(match)) {
|
|
37
|
+
cls = 'key';
|
|
38
|
+
} else {
|
|
39
|
+
cls = 'string';
|
|
40
|
+
}
|
|
41
|
+
} else if (/true|false/.test(match)) {
|
|
42
|
+
cls = 'boolean';
|
|
43
|
+
} else if (/null/.test(match)) {
|
|
44
|
+
cls = 'null';
|
|
45
|
+
}
|
|
46
|
+
return '<span class="' + cls + '">' + match + '</span>';
|
|
47
|
+
});
|
|
48
|
+
|
|
49
|
+
return e
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
</script>
|
|
53
|
+
|
|
54
|
+
<style>
|
|
55
|
+
pre {
|
|
56
|
+
outline: 1px solid #ccc;
|
|
57
|
+
padding: 5px;
|
|
58
|
+
margin: 5px; }
|
|
59
|
+
|
|
60
|
+
pre .string {
|
|
61
|
+
color: green;
|
|
62
|
+
}
|
|
63
|
+
pre .number { color: darkorange; }
|
|
64
|
+
pre .boolean { color: rgb(191, 255, 0); }
|
|
65
|
+
pre .null { color: magenta; }
|
|
66
|
+
pre .key { color: rgb(141, 141, 141); }
|
|
67
|
+
</style>
|
|
@@ -0,0 +1,258 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<v-col
|
|
3
|
+
:class="colClass"
|
|
4
|
+
:lg="mLg"
|
|
5
|
+
:md="mMd"
|
|
6
|
+
:sm="mSm"
|
|
7
|
+
:cols="cols">
|
|
8
|
+
<v-list-item v-if="!alwaysOpen && mIsSelecting" @click="mIsSelecting = false"
|
|
9
|
+
:subtitle="label">
|
|
10
|
+
<template #append>
|
|
11
|
+
<v-row class="ma-0 pa-0">
|
|
12
|
+
<slot name="actions" />
|
|
13
|
+
<v-icon>mdi-chevron-up</v-icon>
|
|
14
|
+
<slot name="actionsRight" />
|
|
15
|
+
<v-menu
|
|
16
|
+
v-if="showSettings"
|
|
17
|
+
offset-y
|
|
18
|
+
:close-on-content-click="false">
|
|
19
|
+
<template v-slot:activator="{ props }">
|
|
20
|
+
<v-btn
|
|
21
|
+
icon="mdi-cog"
|
|
22
|
+
:size="mSize"
|
|
23
|
+
title="Settings"
|
|
24
|
+
v-bind="props" />
|
|
25
|
+
</template>
|
|
26
|
+
<v-list>
|
|
27
|
+
<slot name="settings" />
|
|
28
|
+
</v-list>
|
|
29
|
+
</v-menu>
|
|
30
|
+
</v-row>
|
|
31
|
+
</template>
|
|
32
|
+
</v-list-item>
|
|
33
|
+
<v-slide-y-transition hide-on-leave group>
|
|
34
|
+
<v-text-field
|
|
35
|
+
v-if="(alwaysOpen || mIsSelecting) && showSearch !== false && isLengthyArray(searchProps)"
|
|
36
|
+
@click:prepend-inner="ui.searchString.value = undefined"
|
|
37
|
+
hide-details
|
|
38
|
+
key="1"
|
|
39
|
+
placeholder="Search"
|
|
40
|
+
:prepend-inner-icon="ui.searchString.value != null ? 'mdi-close' : undefined"
|
|
41
|
+
v-model="ui.searchString.value">
|
|
42
|
+
<template #append-inner>
|
|
43
|
+
<v-btn
|
|
44
|
+
v-if="canRefresh"
|
|
45
|
+
@click="ui.refresh({ deepRefresh: true })"
|
|
46
|
+
icon="mdi-refresh"
|
|
47
|
+
:size="mSize"
|
|
48
|
+
variant="text" />
|
|
49
|
+
</template>
|
|
50
|
+
|
|
51
|
+
</v-text-field>
|
|
52
|
+
<v-virtual-scroll
|
|
53
|
+
v-if="(alwaysOpen || mIsSelecting) && useVirtualScroller"
|
|
54
|
+
:height="height"
|
|
55
|
+
:items="ui.filteredItems.value"
|
|
56
|
+
key="2">
|
|
57
|
+
<template #default="{ item }">
|
|
58
|
+
<slot name="item" v-bind:item="item" v-bind:selectItem="selectItem(item)" :active="isActive(item)">
|
|
59
|
+
<v-list-item @click="selectItem(item)" :active="isActive(item)" color="primary">
|
|
60
|
+
<slot v-bind:item="item">
|
|
61
|
+
<v-list-item-title v-if="itemText != null || textFilter != null || textFunction != null">
|
|
62
|
+
{{ displayTitle(item) }}
|
|
63
|
+
</v-list-item-title>
|
|
64
|
+
<v-list-item-subtitle v-if="itemSubtext != null || subtextFilter != null || subtextFunction != null">
|
|
65
|
+
{{ displaySubtitle(item) }}
|
|
66
|
+
</v-list-item-subtitle>
|
|
67
|
+
</slot>
|
|
68
|
+
|
|
69
|
+
</v-list-item>
|
|
70
|
+
</slot>
|
|
71
|
+
</template>
|
|
72
|
+
</v-virtual-scroll>
|
|
73
|
+
<v-list
|
|
74
|
+
v-else-if="alwaysOpen || mIsSelecting"
|
|
75
|
+
:bg-color="transparent ? 'transparent' : undefined"
|
|
76
|
+
:height="height"
|
|
77
|
+
key="3">
|
|
78
|
+
<v-list-item
|
|
79
|
+
v-if="canSelectNone"
|
|
80
|
+
key="-1"
|
|
81
|
+
density="compact"
|
|
82
|
+
@click="selectItem(null)"
|
|
83
|
+
subtitle="(Select None)" />
|
|
84
|
+
|
|
85
|
+
<template v-for="(fItem, fInd) in ui.filteredItems.value">
|
|
86
|
+
<slot name="item" :items="fItem" :index="fInd" :size="mSize">
|
|
87
|
+
<v-list-item
|
|
88
|
+
:active="isActive(fItem)"
|
|
89
|
+
:key="fInd"
|
|
90
|
+
:value="fItem"
|
|
91
|
+
@click="selectItem(fItem)">
|
|
92
|
+
<slot :item="fItem" :index="fInd" :size="mSize">
|
|
93
|
+
<v-list-item-title v-if="itemText != null || textFilter != null || textFunction != null">
|
|
94
|
+
{{ displayTitle(fItem) }}
|
|
95
|
+
</v-list-item-title>
|
|
96
|
+
<v-list-item-subtitle v-if="itemSubtext != null || subtextFilter != null || subtextFunction != null">
|
|
97
|
+
{{ displaySubtitle(fItem) }}
|
|
98
|
+
</v-list-item-subtitle>
|
|
99
|
+
</slot>
|
|
100
|
+
</v-list-item>
|
|
101
|
+
</slot>
|
|
102
|
+
</template>
|
|
103
|
+
</v-list>
|
|
104
|
+
<slot v-else name="selected" :item="selectedItem" :open="openList">
|
|
105
|
+
<v-list-item
|
|
106
|
+
@click="openList"
|
|
107
|
+
key="4"
|
|
108
|
+
:title="label"
|
|
109
|
+
:subtitle="displayTitle(selectedItem) ?? placeholder">
|
|
110
|
+
<template #append>
|
|
111
|
+
<v-row no-gutters>
|
|
112
|
+
<slot name="actions" />
|
|
113
|
+
<v-icon>mdi-chevron-down</v-icon>
|
|
114
|
+
<slot name="actionsRight" />
|
|
115
|
+
<v-menu
|
|
116
|
+
v-if="showSettings"
|
|
117
|
+
offset-y
|
|
118
|
+
:close-on-content-click="false">
|
|
119
|
+
<template v-slot:activator="{ props }">
|
|
120
|
+
<v-btn
|
|
121
|
+
icon
|
|
122
|
+
v-bind="props"
|
|
123
|
+
:size="mSize"
|
|
124
|
+
title="Settings" />
|
|
125
|
+
</template>
|
|
126
|
+
<v-list>
|
|
127
|
+
<slot name="settings" />
|
|
128
|
+
</v-list>
|
|
129
|
+
</v-menu>
|
|
130
|
+
</v-row>
|
|
131
|
+
</template>
|
|
132
|
+
</v-list-item>
|
|
133
|
+
</slot>
|
|
134
|
+
|
|
135
|
+
</v-slide-y-transition>
|
|
136
|
+
|
|
137
|
+
<v-overlay
|
|
138
|
+
v-model="ui.isLoading.value"
|
|
139
|
+
class="align-center justify-center text-center"
|
|
140
|
+
contained
|
|
141
|
+
persistent>
|
|
142
|
+
<v-progress-circular indeterminate />
|
|
143
|
+
<p>{{ ui.loadingMsg.value }}</p>
|
|
144
|
+
</v-overlay>
|
|
145
|
+
</v-col>
|
|
146
|
+
|
|
147
|
+
</template>
|
|
148
|
+
|
|
149
|
+
<script setup lang="ts">
|
|
150
|
+
import { type ListProps, useList } from '../composables/list'
|
|
151
|
+
import { computed, inject, ref } from 'vue'
|
|
152
|
+
import { useFilters } from '../composables/filters'
|
|
153
|
+
import { isLengthyArray, nestedValue } from '../composables/helpers'
|
|
154
|
+
|
|
155
|
+
defineOptions({
|
|
156
|
+
inheritAttrs: false
|
|
157
|
+
})
|
|
158
|
+
|
|
159
|
+
interface SelectProps extends ListProps {
|
|
160
|
+
alwaysOpen?: boolean
|
|
161
|
+
canRefresh?: boolean
|
|
162
|
+
canSearch?: boolean
|
|
163
|
+
canSelectNone?: boolean
|
|
164
|
+
colClass?: string
|
|
165
|
+
cols?: string | boolean
|
|
166
|
+
height?: string
|
|
167
|
+
isMobile?: boolean
|
|
168
|
+
isEditing?: boolean
|
|
169
|
+
isSelecting?: boolean
|
|
170
|
+
items?: [],
|
|
171
|
+
itemSubtext?: string
|
|
172
|
+
itemText?: string
|
|
173
|
+
itemValue?: string //inherited
|
|
174
|
+
label?: string
|
|
175
|
+
lg?: string | boolean
|
|
176
|
+
modelValue?: any
|
|
177
|
+
md?: string | boolean
|
|
178
|
+
nav?: string
|
|
179
|
+
placeholder?: string
|
|
180
|
+
showSettings?: boolean
|
|
181
|
+
sm?: string | boolean
|
|
182
|
+
subtextFilter?: string
|
|
183
|
+
subtextFunction?: Function
|
|
184
|
+
textFilter?: string
|
|
185
|
+
textFunction?: Function
|
|
186
|
+
transparent?: boolean
|
|
187
|
+
useVirtualScroller?: boolean
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
const emit = defineEmits(['update:modelValue', 'change'])
|
|
191
|
+
|
|
192
|
+
const props = withDefaults(defineProps<SelectProps>(), {
|
|
193
|
+
canRefresh: true,
|
|
194
|
+
height: '400',
|
|
195
|
+
isEditing: undefined,
|
|
196
|
+
sortOrder: 'Ascending',
|
|
197
|
+
cols: '12',
|
|
198
|
+
lg: false,
|
|
199
|
+
md: false,
|
|
200
|
+
sm: '6'
|
|
201
|
+
})
|
|
202
|
+
|
|
203
|
+
const mIsSelecting = ref(props.alwaysOpen ?? props.isSelecting ?? false)
|
|
204
|
+
const mSize = inject('size', () => ref('small'), true)
|
|
205
|
+
const mIsEditing = inject('isEditing', () => ref(false), true)
|
|
206
|
+
const cIsEditing = computed(() => props.isEditing ?? mIsEditing.value)
|
|
207
|
+
|
|
208
|
+
const ui = useList(props, undefined, {
|
|
209
|
+
useBladeSrc: false,
|
|
210
|
+
useRouteSrc: false
|
|
211
|
+
})
|
|
212
|
+
|
|
213
|
+
const filters = useFilters()
|
|
214
|
+
|
|
215
|
+
const displaySubtitle = computed(() => (item: any) => {
|
|
216
|
+
let v = props.subtextFunction != null ? props.subtextFunction(item) : item
|
|
217
|
+
v = props.itemSubtext != null ? nestedValue(v, props.itemSubtext) : v
|
|
218
|
+
return props.subtextFilter != null ? filters.findFilter(props.subtextFilter)(v) : v
|
|
219
|
+
})
|
|
220
|
+
|
|
221
|
+
const displayTitle = computed(() => (item: any) => {
|
|
222
|
+
let v = props.textFunction != null ? props.textFunction(item) : item
|
|
223
|
+
v = props.itemText != null ? nestedValue(v, props.itemText) : v
|
|
224
|
+
return props.textFilter != null ? filters.findFilter(props.textFilter)(v) : v
|
|
225
|
+
})
|
|
226
|
+
|
|
227
|
+
const isActive = computed(() => (item: any) => {
|
|
228
|
+
return (props.itemValue ? item[props.itemValue] : item) == props.modelValue
|
|
229
|
+
})
|
|
230
|
+
|
|
231
|
+
function openList() {
|
|
232
|
+
if (cIsEditing.value)
|
|
233
|
+
mIsSelecting.value = true
|
|
234
|
+
}
|
|
235
|
+
|
|
236
|
+
function selectItem(item: any) {
|
|
237
|
+
mIsSelecting.value = false
|
|
238
|
+
|
|
239
|
+
if (item != null || props.canSelectNone) {
|
|
240
|
+
let v = item
|
|
241
|
+
|
|
242
|
+
if (item != null && props.itemValue != null)
|
|
243
|
+
v = item[props.itemValue]
|
|
244
|
+
|
|
245
|
+
emit('update:modelValue', v)
|
|
246
|
+
emit('change', v)
|
|
247
|
+
}
|
|
248
|
+
}
|
|
249
|
+
|
|
250
|
+
const selectedItem = computed(() => {
|
|
251
|
+
return props.modelValue != null ? ui.asyncItems.value.find((x: any) => (x.id == props.modelValue)) : null
|
|
252
|
+
})
|
|
253
|
+
|
|
254
|
+
const mIsMobile = inject('isMobile', () => ref(false), true)
|
|
255
|
+
const mLg = computed(() => (props.isMobile ?? mIsMobile.value) ? false : props.lg)
|
|
256
|
+
const mMd = computed(() => (props.isMobile ?? mIsMobile.value) ? false : props.md)
|
|
257
|
+
const mSm = computed(() => (props.isMobile ?? mIsMobile.value) ? false : props.sm)
|
|
258
|
+
</script>
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<v-select
|
|
3
|
+
:append-icon="canRefresh ? 'mdi-refresh' : undefined"
|
|
4
|
+
:clearable="canSelectNone"
|
|
5
|
+
@click:append-icon="ui.refresh({ deepRefresh: true })"
|
|
6
|
+
hide-details
|
|
7
|
+
:items="ui.filteredItems.value"
|
|
8
|
+
:item-title="itemText"
|
|
9
|
+
:item-value="itemValue"
|
|
10
|
+
:variant="fieldVariant" />
|
|
11
|
+
</template>
|
|
12
|
+
|
|
13
|
+
<script setup lang="ts">
|
|
14
|
+
import { type ListProps, type ListEvents, useList } from '../composables/list';
|
|
15
|
+
import { type FieldVariant } from '../types'
|
|
16
|
+
|
|
17
|
+
interface SelectEvents extends ListEvents {
|
|
18
|
+
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
interface SelectProps extends ListProps {
|
|
22
|
+
additionalUrl?: string
|
|
23
|
+
canRefresh?: boolean
|
|
24
|
+
canSelectNone?: boolean
|
|
25
|
+
fieldVariant?: FieldVariant
|
|
26
|
+
items?: [],
|
|
27
|
+
itemText?: string
|
|
28
|
+
itemValue?: string //inherited
|
|
29
|
+
multiple?: boolean
|
|
30
|
+
nav?: string
|
|
31
|
+
onFilter?: Function
|
|
32
|
+
textFilter?: string
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
const emit = defineEmits<SelectEvents>()
|
|
36
|
+
|
|
37
|
+
const props = withDefaults(defineProps<SelectProps>(), {
|
|
38
|
+
sortOrder: 'Ascending'
|
|
39
|
+
})
|
|
40
|
+
|
|
41
|
+
const ui = useList(props, emit, {
|
|
42
|
+
useBladeSrc: false,
|
|
43
|
+
useRouteSrc: false
|
|
44
|
+
})
|
|
45
|
+
|
|
46
|
+
</script>
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<v-snackbar
|
|
3
|
+
v-model="showSnack"
|
|
4
|
+
:timeout="cTimeout">
|
|
5
|
+
{{ modelValue }}
|
|
6
|
+
</v-snackbar>
|
|
7
|
+
</template>
|
|
8
|
+
|
|
9
|
+
<script setup lang="ts">
|
|
10
|
+
import { computed, ref, watch } from 'vue';
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
interface SnackProps {
|
|
14
|
+
isTimed?: boolean
|
|
15
|
+
modelValue?: string
|
|
16
|
+
timeout?: string,
|
|
17
|
+
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
const props = withDefaults(defineProps<SnackProps>(), {
|
|
21
|
+
isTimed: true,
|
|
22
|
+
timeout: '5000'
|
|
23
|
+
})
|
|
24
|
+
|
|
25
|
+
const cTimeout = computed(() => { return props.isTimed ? props.timeout : -1 })
|
|
26
|
+
const showSnack = ref(false)
|
|
27
|
+
watch(() => props.modelValue, () => {
|
|
28
|
+
showSnack.value = true
|
|
29
|
+
})
|
|
30
|
+
|
|
31
|
+
</script>
|
|
@@ -40,7 +40,7 @@
|
|
|
40
40
|
import { computed, onMounted, ref } from 'vue'
|
|
41
41
|
import VueDatePicker from '@vuepic/vue-datepicker'
|
|
42
42
|
import '@vuepic/vue-datepicker/dist/main.css'
|
|
43
|
-
import { useAuth } from '../
|
|
43
|
+
import { useAuth } from '../composables/auth'
|
|
44
44
|
import { type SelectDateProps } from '../composables/dialogs'
|
|
45
45
|
|
|
46
46
|
const props = withDefaults(defineProps<SelectDateProps>(), {
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import type { BladeMode } from '../types'
|
|
2
|
-
import {
|
|
2
|
+
import { BTStoreDefinition } from '../composables/stores'
|
|
3
3
|
import { BTApi, type PathOptions } from '../composables/api'
|
|
4
4
|
import { useActionsTracker, type DoActionOptions } from '../composables/actions-tracker'
|
|
5
5
|
import { ShallowRef, ComputedRef } from 'vue'
|
|
@@ -15,7 +15,7 @@ export interface GetOptions extends PathOptions, DoActionOptions {
|
|
|
15
15
|
onGetAsync?: OnGetAsync
|
|
16
16
|
/**called after get occurs successfully */
|
|
17
17
|
onGetSuccessAsync?: OnGetSuccessAsync
|
|
18
|
-
store?:
|
|
18
|
+
store?: BTStoreDefinition
|
|
19
19
|
}
|
|
20
20
|
|
|
21
21
|
export interface DeleteOptions extends PathOptions, DoActionOptions {
|
|
@@ -25,7 +25,7 @@ export interface DeleteOptions extends PathOptions, DoActionOptions {
|
|
|
25
25
|
onDeleteAsync?: OnDoAsync
|
|
26
26
|
/**Will open a dialog box requesting user confirmation for delete action */
|
|
27
27
|
onDeleteSuccessAsync?: OnDoAsync
|
|
28
|
-
store?:
|
|
28
|
+
store?: BTStoreDefinition
|
|
29
29
|
}
|
|
30
30
|
|
|
31
31
|
export interface RestoreOptions extends PathOptions, DoActionOptions {
|
|
@@ -35,7 +35,7 @@ export interface RestoreOptions extends PathOptions, DoActionOptions {
|
|
|
35
35
|
onRestoreAsync?: OnDoSuccessAsync
|
|
36
36
|
/**Called after restore succeeds */
|
|
37
37
|
onRestoreSuccessAsync?: OnDoSuccessAsync
|
|
38
|
-
store?:
|
|
38
|
+
store?: BTStoreDefinition
|
|
39
39
|
}
|
|
40
40
|
|
|
41
41
|
export interface SaveOptions extends PathOptions, DoActionOptions {
|
|
@@ -52,7 +52,7 @@ export interface SaveOptions extends PathOptions, DoActionOptions {
|
|
|
52
52
|
onSaveAsync?: OnDoSuccessAsync
|
|
53
53
|
/**Called after save succeeds */
|
|
54
54
|
onSaveSuccessAsync?: OnDoSuccessAsync
|
|
55
|
-
store?:
|
|
55
|
+
store?: BTStoreDefinition
|
|
56
56
|
}
|
|
57
57
|
|
|
58
58
|
export interface ApiActionOptions extends PathOptions, DoActionOptions {
|
|
@@ -63,7 +63,7 @@ export interface UseActionsOptions extends DoActionOptions {
|
|
|
63
63
|
nav?: string
|
|
64
64
|
proxyID?: string
|
|
65
65
|
refresh?: boolean
|
|
66
|
-
store?:
|
|
66
|
+
store?: BTStoreDefinition
|
|
67
67
|
throwError?: boolean
|
|
68
68
|
url?: string
|
|
69
69
|
}
|
package/src/composables/api.ts
CHANGED
|
@@ -91,6 +91,12 @@ export interface BTApi {
|
|
|
91
91
|
patch: <T>(pathOptions: PathOptions) => Promise<T | undefined>
|
|
92
92
|
}
|
|
93
93
|
|
|
94
|
+
let current: BTApi
|
|
95
|
+
|
|
96
|
+
export function useApi(): BTApi {
|
|
97
|
+
return current
|
|
98
|
+
}
|
|
99
|
+
|
|
94
100
|
export function createApi(options?: UseApiOptions): BTApi {
|
|
95
101
|
const buildHeaders = options?.buildHeaders ?? defaultBuildHeaders
|
|
96
102
|
const buildQuery = options?.buildQuery ?? defaultBuildQuery
|
|
@@ -458,7 +464,7 @@ export function createApi(options?: UseApiOptions): BTApi {
|
|
|
458
464
|
}
|
|
459
465
|
}
|
|
460
466
|
|
|
461
|
-
|
|
467
|
+
current = {
|
|
462
468
|
buildHeaders,
|
|
463
469
|
buildQuery,
|
|
464
470
|
buildUrl,
|
|
@@ -468,4 +474,6 @@ export function createApi(options?: UseApiOptions): BTApi {
|
|
|
468
474
|
patch,
|
|
469
475
|
post
|
|
470
476
|
}
|
|
477
|
+
|
|
478
|
+
return current
|
|
471
479
|
}
|
package/src/composables/auth.ts
CHANGED
|
@@ -31,11 +31,8 @@ export interface BaseAuthCredentials {
|
|
|
31
31
|
userPermissions?: string[]
|
|
32
32
|
}
|
|
33
33
|
|
|
34
|
-
// const state = useStorage<BaseAuthCredentials>('auth-credentials', {})
|
|
35
|
-
// let defaultsSet = false
|
|
36
34
|
let defaultTimeZone = 'Australia/Melbourne'
|
|
37
35
|
|
|
38
|
-
// export type FindAuthItem = (navName?: string | AuthItem) => AuthItem | undefined
|
|
39
36
|
export type GetAuthUrl = (redirectPath?: string, state?: string) => string
|
|
40
37
|
|
|
41
38
|
export interface CreateAuthOptions {
|
|
@@ -70,28 +67,17 @@ export interface BTAuth {
|
|
|
70
67
|
tryLogin: () => boolean | undefined
|
|
71
68
|
}
|
|
72
69
|
|
|
73
|
-
|
|
74
|
-
// export function useTimeZone() {
|
|
75
|
-
// return state.value.timeZone ?? defaultTimeZone
|
|
76
|
-
// }
|
|
70
|
+
let current: BTAuth
|
|
77
71
|
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
72
|
+
export function useAuth(): BTAuth {
|
|
73
|
+
return current
|
|
74
|
+
}
|
|
81
75
|
|
|
82
76
|
export function createAuth(options: CreateAuthOptions): BTAuth {
|
|
83
|
-
const router = useRouter()
|
|
84
77
|
const expiryFormat = options.expiryTokenFormat ?? 'd/MM/yyyy h:mm:ss a'
|
|
85
78
|
const authState = useStorage<string>('auth-credentials-state', (Math.random().toString(36).substring(4, 19) + Math.random().toString(12).substring(1, 11)))
|
|
86
79
|
const state = useStorage<BaseAuthCredentials>('auth-credentials', {})
|
|
87
|
-
|
|
88
|
-
// if (!defaultsSet) {
|
|
89
|
-
// setDefaults()
|
|
90
|
-
// defaultsSet = true
|
|
91
|
-
// }
|
|
92
80
|
|
|
93
|
-
// const { endDemo, isDemoing } = useDemo()
|
|
94
|
-
|
|
95
81
|
/**can edit if navName is undefined, isGlobalAdmin, not suspended, or user permissions allow editing of this navItem */
|
|
96
82
|
function canEdit(navName?: string): boolean {
|
|
97
83
|
if (navName == null) return true
|
|
@@ -286,6 +272,7 @@ export function createAuth(options: CreateAuthOptions): BTAuth {
|
|
|
286
272
|
|
|
287
273
|
//maybe redirect
|
|
288
274
|
if (navNameRedirect != null) {
|
|
275
|
+
const router = useRouter()
|
|
289
276
|
if (router.currentRoute.value.name != navNameRedirect) {
|
|
290
277
|
router.push({ name: navNameRedirect })
|
|
291
278
|
}
|
|
@@ -363,7 +350,7 @@ export function createAuth(options: CreateAuthOptions): BTAuth {
|
|
|
363
350
|
return e1 <= e2
|
|
364
351
|
}
|
|
365
352
|
|
|
366
|
-
|
|
353
|
+
current = {
|
|
367
354
|
authState: authState.value,
|
|
368
355
|
canEdit,
|
|
369
356
|
canEditPermit,
|
|
@@ -379,4 +366,6 @@ export function createAuth(options: CreateAuthOptions): BTAuth {
|
|
|
379
366
|
setAuth,
|
|
380
367
|
tryLogin
|
|
381
368
|
}
|
|
369
|
+
|
|
370
|
+
return current
|
|
382
371
|
}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { useStorage } from '@vueuse/core'
|
|
1
|
+
import { RemovableRef, useStorage } from '@vueuse/core'
|
|
2
2
|
import { useTheme } from 'vuetify';
|
|
3
3
|
|
|
4
4
|
interface CosmeticData {
|
|
@@ -49,6 +49,7 @@ export interface UseCosmeticsOptions<T extends BaseCosmeticTheme> {
|
|
|
49
49
|
|
|
50
50
|
export interface BTCosmetics {
|
|
51
51
|
state: CosmeticData
|
|
52
|
+
initiate: () => void
|
|
52
53
|
resetCosmetics: (toDefault: boolean) => void
|
|
53
54
|
setTemporaryColor: (color: string) => void
|
|
54
55
|
toggleDrawer: () => void
|
|
@@ -57,27 +58,14 @@ export interface BTCosmetics {
|
|
|
57
58
|
undoTemporaryColor: () => void
|
|
58
59
|
}
|
|
59
60
|
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
dark: options.defaultDarkTheme ?? defaultDark,
|
|
66
|
-
drawer: options.defaultDrawer ?? true,
|
|
67
|
-
drawerStick: options.defaultDrawerStick ?? false
|
|
68
|
-
})
|
|
61
|
+
let defaults: any = {}
|
|
62
|
+
let state: RemovableRef<CosmeticData>
|
|
63
|
+
|
|
64
|
+
export function useCosmetics(): BTCosmetics {
|
|
65
|
+
const themeManager = useTheme()
|
|
69
66
|
|
|
70
|
-
// if (!defaultsSet) {
|
|
71
|
-
// state.value.theme ??= (options.defaultTheme ?? 'light')
|
|
72
|
-
// state.value.light ??= (options.defaultLightTheme ?? defaultLight)
|
|
73
|
-
// state.value.dark ??= (options.defaultDarkTheme ?? defaultDark)
|
|
74
|
-
// state.value.drawer ??= (options.defaultDrawer ?? true)
|
|
75
|
-
// state.value.drawerStick ??= (options.defaultDrawerStick ?? false)
|
|
76
|
-
// defaultsSet = true
|
|
77
|
-
// }
|
|
78
|
-
|
|
79
67
|
/**used for initiating the themes and colors from storage when the web app is loaded */
|
|
80
|
-
|
|
68
|
+
function loadCosmetics() {
|
|
81
69
|
themeManager.global.name.value = state.value.theme!
|
|
82
70
|
|
|
83
71
|
//load dark colors
|
|
@@ -96,17 +84,16 @@ export function createCosmetics<T extends BaseCosmeticTheme>(options: UseCosmeti
|
|
|
96
84
|
const lKey = lightKey as keyof typeof storedLightTheme
|
|
97
85
|
lightColors[lKey] = storedLightTheme[lKey]
|
|
98
86
|
})
|
|
99
|
-
|
|
100
|
-
|
|
87
|
+
}
|
|
88
|
+
|
|
101
89
|
/**resets to the default colors or last saved colors of the current theme */
|
|
102
90
|
function resetCosmetics(toDefault: boolean) {
|
|
103
|
-
|
|
104
91
|
themeManager.global.name.value = state.value.theme!
|
|
105
92
|
|
|
106
93
|
if (themeManager.global.name.value == 'dark') {
|
|
107
94
|
//dark
|
|
108
95
|
if (toDefault)
|
|
109
|
-
state.value.dark = { ...(
|
|
96
|
+
state.value.dark = { ...(defaults.defaultDarkTheme ?? defaultDark) };
|
|
110
97
|
|
|
111
98
|
themeManager.themes.value.dark = {
|
|
112
99
|
...themeManager.themes.value.dark,
|
|
@@ -119,7 +106,7 @@ export function createCosmetics<T extends BaseCosmeticTheme>(options: UseCosmeti
|
|
|
119
106
|
else {
|
|
120
107
|
//light
|
|
121
108
|
if (toDefault)
|
|
122
|
-
state.value.light = { ...(
|
|
109
|
+
state.value.light = { ...(defaults.defaultLightTheme ?? defaultLight) };
|
|
123
110
|
|
|
124
111
|
themeManager.themes.value.light = {
|
|
125
112
|
...themeManager.themes.value.light,
|
|
@@ -159,15 +146,15 @@ export function createCosmetics<T extends BaseCosmeticTheme>(options: UseCosmeti
|
|
|
159
146
|
const dark = themeManager.themes.value.dark
|
|
160
147
|
const light = themeManager.themes.value.light
|
|
161
148
|
|
|
162
|
-
dark.colors.primary = (state.value.dark ??
|
|
163
|
-
light.colors.primary = (state.value.light ??
|
|
149
|
+
dark.colors.primary = (state.value.dark ?? defaults.defaultDarkTheme ?? defaultDark).primary
|
|
150
|
+
light.colors.primary = (state.value.light ?? defaults.defaultLightTheme ?? defaultLight).primary
|
|
164
151
|
|
|
165
152
|
document.querySelector('meta[name="theme-color"]')?.setAttribute("content", '')
|
|
166
153
|
}
|
|
167
154
|
|
|
168
155
|
return {
|
|
169
156
|
state: state.value,
|
|
170
|
-
|
|
157
|
+
initiate: loadCosmetics,
|
|
171
158
|
resetCosmetics,
|
|
172
159
|
setTemporaryColor,
|
|
173
160
|
toggleDrawer,
|
|
@@ -175,4 +162,16 @@ export function createCosmetics<T extends BaseCosmeticTheme>(options: UseCosmeti
|
|
|
175
162
|
toggleLightDark,
|
|
176
163
|
undoTemporaryColor
|
|
177
164
|
}
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
export function createCosmetics<T extends BaseCosmeticTheme>(options: UseCosmeticsOptions<T>) {
|
|
168
|
+
state = useStorage<CosmeticData>('cosmetics', {
|
|
169
|
+
theme: options.defaultTheme ?? 'light',
|
|
170
|
+
light: options.defaultLightTheme ?? defaultLight,
|
|
171
|
+
dark: options.defaultDarkTheme ?? defaultDark,
|
|
172
|
+
drawer: options.defaultDrawer ?? true,
|
|
173
|
+
drawerStick: options.defaultDrawerStick ?? false
|
|
174
|
+
})
|
|
175
|
+
|
|
176
|
+
defaults = options
|
|
178
177
|
}
|