adminforth 1.6.2-next.1 → 1.6.2-next.3
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/index.d.ts.map +1 -1
- package/dist/index.js +1 -0
- package/dist/index.js.map +1 -1
- package/package.json +1 -4
- package/dist/spa/.eslintrc.cjs +0 -14
- package/dist/spa/README.md +0 -39
- package/dist/spa/env.d.ts +0 -1
- package/dist/spa/index.html +0 -23
- package/dist/spa/package-lock.json +0 -5062
- package/dist/spa/package.json +0 -58
- package/dist/spa/postcss.config.js +0 -6
- package/dist/spa/public/assets/favicon.png +0 -0
- package/dist/spa/src/App.vue +0 -432
- package/dist/spa/src/adminforth.ts +0 -160
- package/dist/spa/src/afcl/AreaChart.vue +0 -160
- package/dist/spa/src/afcl/BarChart.vue +0 -170
- package/dist/spa/src/afcl/Button.vue +0 -27
- package/dist/spa/src/afcl/Checkbox.vue +0 -24
- package/dist/spa/src/afcl/Dropzone.vue +0 -128
- package/dist/spa/src/afcl/Input.vue +0 -41
- package/dist/spa/src/afcl/Link.vue +0 -17
- package/dist/spa/src/afcl/LinkButton.vue +0 -25
- package/dist/spa/src/afcl/PieChart.vue +0 -175
- package/dist/spa/src/afcl/ProgressBar.vue +0 -57
- package/dist/spa/src/afcl/Select.vue +0 -246
- package/dist/spa/src/afcl/Skeleton.vue +0 -26
- package/dist/spa/src/afcl/Spinner.vue +0 -9
- package/dist/spa/src/afcl/Table.vue +0 -116
- package/dist/spa/src/afcl/Tooltip.vue +0 -43
- package/dist/spa/src/afcl/VerticalTabs.vue +0 -49
- package/dist/spa/src/afcl/index.ts +0 -20
- package/dist/spa/src/assets/base.css +0 -2
- package/dist/spa/src/assets/logo.svg +0 -19
- package/dist/spa/src/components/AcceptModal.vue +0 -44
- package/dist/spa/src/components/Breadcrumbs.vue +0 -41
- package/dist/spa/src/components/BreadcrumbsWithButtons.vue +0 -25
- package/dist/spa/src/components/CustomDatePicker.vue +0 -180
- package/dist/spa/src/components/CustomDateRangePicker.vue +0 -218
- package/dist/spa/src/components/CustomRangePicker.vue +0 -156
- package/dist/spa/src/components/Filters.vue +0 -232
- package/dist/spa/src/components/GroupsTable.vue +0 -218
- package/dist/spa/src/components/HelloWorld.vue +0 -17
- package/dist/spa/src/components/MenuLink.vue +0 -41
- package/dist/spa/src/components/ResourceForm.vue +0 -260
- package/dist/spa/src/components/ResourceListTable.vue +0 -486
- package/dist/spa/src/components/ShowTable.vue +0 -81
- package/dist/spa/src/components/SingleSkeletLoader.vue +0 -13
- package/dist/spa/src/components/SkeleteLoader.vue +0 -18
- package/dist/spa/src/components/ThreeDotsMenu.vue +0 -43
- package/dist/spa/src/components/Toast.vue +0 -78
- package/dist/spa/src/components/ValueRenderer.vue +0 -141
- package/dist/spa/src/components/icons/IconCalendar.vue +0 -5
- package/dist/spa/src/components/icons/IconCommunity.vue +0 -7
- package/dist/spa/src/components/icons/IconDocumentation.vue +0 -7
- package/dist/spa/src/components/icons/IconEcosystem.vue +0 -7
- package/dist/spa/src/components/icons/IconSupport.vue +0 -7
- package/dist/spa/src/components/icons/IconTime.vue +0 -5
- package/dist/spa/src/components/icons/IconTooling.vue +0 -19
- package/dist/spa/src/composables/useFrontendApi.ts +0 -28
- package/dist/spa/src/i18n.ts +0 -54
- package/dist/spa/src/index.scss +0 -34
- package/dist/spa/src/main.ts +0 -22
- package/dist/spa/src/renderers/CompactField.vue +0 -46
- package/dist/spa/src/renderers/CompactUUID.vue +0 -46
- package/dist/spa/src/renderers/CountryFlag.vue +0 -65
- package/dist/spa/src/renderers/HumanNumber.vue +0 -58
- package/dist/spa/src/renderers/RelativeTime.vue +0 -42
- package/dist/spa/src/renderers/URL.vue +0 -18
- package/dist/spa/src/router/index.ts +0 -70
- package/dist/spa/src/spa_types/core.ts +0 -51
- package/dist/spa/src/stores/core.ts +0 -228
- package/dist/spa/src/stores/filters.ts +0 -27
- package/dist/spa/src/stores/modal.ts +0 -48
- package/dist/spa/src/stores/toast.ts +0 -30
- package/dist/spa/src/stores/user.ts +0 -79
- package/dist/spa/src/types/Adapters.ts +0 -26
- package/dist/spa/src/types/Back.ts +0 -1344
- package/dist/spa/src/types/Common.ts +0 -940
- package/dist/spa/src/types/FrontendAPI.ts +0 -189
- package/dist/spa/src/utils.ts +0 -184
- package/dist/spa/src/views/CreateView.vue +0 -167
- package/dist/spa/src/views/EditView.vue +0 -171
- package/dist/spa/src/views/ListView.vue +0 -442
- package/dist/spa/src/views/LoginView.vue +0 -199
- package/dist/spa/src/views/PageNotFound.vue +0 -20
- package/dist/spa/src/views/ResourceParent.vue +0 -50
- package/dist/spa/src/views/ShowView.vue +0 -209
- package/dist/spa/src/websocket.ts +0 -129
- package/dist/spa/tailwind.config.js +0 -19
- package/dist/spa/tsconfig.app.json +0 -14
- package/dist/spa/tsconfig.json +0 -11
- package/dist/spa/tsconfig.node.json +0 -19
- package/dist/spa/vite.config.ts +0 -52
|
@@ -1,50 +0,0 @@
|
|
|
1
|
-
<template>
|
|
2
|
-
<div :key="`${$route?.params.resourceId}---${$route?.params.primaryKey}`" class="p-4 flex"
|
|
3
|
-
:class="limitHeightToPage ? 'h-[calc(100vh-3.5rem)]': undefined"
|
|
4
|
-
>
|
|
5
|
-
<RouterView/>
|
|
6
|
-
</div>
|
|
7
|
-
</template>
|
|
8
|
-
|
|
9
|
-
<style>
|
|
10
|
-
</style>
|
|
11
|
-
|
|
12
|
-
<script setup>
|
|
13
|
-
|
|
14
|
-
import { useCoreStore } from '@/stores/core';
|
|
15
|
-
import { computed } from 'vue';
|
|
16
|
-
import { useRoute } from 'vue-router';
|
|
17
|
-
|
|
18
|
-
const route = useRoute()
|
|
19
|
-
const coreStore = useCoreStore()
|
|
20
|
-
|
|
21
|
-
const limitHeightToPage = computed(() => {
|
|
22
|
-
if (route.name !== 'resource-list' ) {
|
|
23
|
-
return false;
|
|
24
|
-
}
|
|
25
|
-
// for mobile phones disable shrinking table at all because of the issues with HEADER and general UX
|
|
26
|
-
// use navigator.userAgent to detect mobile phones
|
|
27
|
-
if (navigator.userAgent.match(/Android/i) || navigator.userAgent.match(/iPhone|iPad|iPod/i)) {
|
|
28
|
-
return false;
|
|
29
|
-
}
|
|
30
|
-
|
|
31
|
-
if (!coreStore.resource?.options?.pageInjections?.list) {
|
|
32
|
-
return true;
|
|
33
|
-
}
|
|
34
|
-
const listPageInjects = coreStore.resource.options.pageInjections.list;
|
|
35
|
-
|
|
36
|
-
for (const pi of [listPageInjects.beforeBreadcrumbs, listPageInjects.afterBreadcrumbs, listPageInjects.bottom]) {
|
|
37
|
-
if (pi) {
|
|
38
|
-
for (const piItem of pi) {
|
|
39
|
-
if (!piItem.meta?.thinEnoughToShrinkTable) {
|
|
40
|
-
return false;
|
|
41
|
-
}
|
|
42
|
-
}
|
|
43
|
-
}
|
|
44
|
-
}
|
|
45
|
-
|
|
46
|
-
return true;
|
|
47
|
-
|
|
48
|
-
})
|
|
49
|
-
|
|
50
|
-
</script>
|
|
@@ -1,209 +0,0 @@
|
|
|
1
|
-
<template>
|
|
2
|
-
<div class="relative w-full">
|
|
3
|
-
<component
|
|
4
|
-
v-if="!loading"
|
|
5
|
-
v-for="c in coreStore?.resourceOptions?.pageInjections?.show?.beforeBreadcrumbs || []"
|
|
6
|
-
:is="getCustomComponent(c)"
|
|
7
|
-
:meta="c.meta"
|
|
8
|
-
:record="coreStore.record"
|
|
9
|
-
:resource="coreStore.resource"
|
|
10
|
-
:adminUser="coreStore.adminUser"
|
|
11
|
-
/>
|
|
12
|
-
<BreadcrumbsWithButtons>
|
|
13
|
-
<RouterLink v-if="coreStore.resource?.options?.allowedActions?.create"
|
|
14
|
-
:to="{ name: 'resource-create', params: { resourceId: $route.params.resourceId } }"
|
|
15
|
-
class="flex items-center py-1 px-3 text-sm font-medium text-gray-900 focus:outline-none bg-white rounded border border-gray-300 hover:bg-gray-100 hover:text-lightPrimary focus:z-10 focus:ring-4 focus:ring-gray-100 dark:focus:ring-gray-700 dark:bg-gray-800 dark:text-gray-400 dark:border-gray-600 dark:hover:text-white dark:hover:bg-gray-700 rounded-default"
|
|
16
|
-
>
|
|
17
|
-
<IconPlusOutline class="w-4 h-4 me-2"/>
|
|
18
|
-
{{ $t('Add new') }}
|
|
19
|
-
</RouterLink>
|
|
20
|
-
|
|
21
|
-
<RouterLink v-if="coreStore?.resourceOptions?.allowedActions?.edit" :to="{ name: 'resource-edit', params: { resourceId: $route.params.resourceId, primaryKey: $route.params.primaryKey } }"
|
|
22
|
-
class="flex items-center py-1 px-3 text-sm font-medium text-gray-900 focus:outline-none bg-white rounded-default border border-gray-300 hover:bg-gray-100 hover:text-lightPrimary focus:z-10 focus:ring-4 focus:ring-gray-100 dark:focus:ring-gray-700 dark:bg-gray-800 dark:text-gray-400 dark:border-gray-600 dark:hover:text-white dark:hover:bg-gray-700"
|
|
23
|
-
>
|
|
24
|
-
<IconPenSolid class="w-4 h-4" />
|
|
25
|
-
{{ $t('Edit') }}
|
|
26
|
-
</RouterLink>
|
|
27
|
-
|
|
28
|
-
<button v-if="coreStore?.resourceOptions?.allowedActions?.delete" @click="deleteRecord"
|
|
29
|
-
class="flex items-center py-1 px-3 text-sm font-medium rounded-default text-red-600 focus:outline-none bg-white border border-gray-300 hover:bg-gray-100 hover:text-red-700 focus:z-10 focus:ring-4 focus:ring-gray-100 dark:focus:ring-gray-700 dark:bg-gray-800 dark:text-red-500 dark:border-gray-600 dark:hover:text-white dark:hover:bg-gray-700"
|
|
30
|
-
>
|
|
31
|
-
<IconTrashBinSolid class="w-4 h-4" />
|
|
32
|
-
{{ $t('Delete') }}
|
|
33
|
-
</button>
|
|
34
|
-
|
|
35
|
-
<ThreeDotsMenu
|
|
36
|
-
:threeDotsDropdownItems="coreStore.resourceOptions?.pageInjections?.show?.threeDotsDropdownItems"
|
|
37
|
-
></ThreeDotsMenu>
|
|
38
|
-
</BreadcrumbsWithButtons>
|
|
39
|
-
|
|
40
|
-
<component
|
|
41
|
-
v-for="c in coreStore?.resourceOptions?.pageInjections?.show?.afterBreadcrumbs || []"
|
|
42
|
-
:is="getCustomComponent(c)"
|
|
43
|
-
:meta="c.meta"
|
|
44
|
-
:record="coreStore.record"
|
|
45
|
-
:resource="coreStore.resource"
|
|
46
|
-
:adminUser="coreStore.adminUser"
|
|
47
|
-
/>
|
|
48
|
-
|
|
49
|
-
<div v-if="loading" role="status" class="max-w-sm animate-pulse">
|
|
50
|
-
<div class="h-2.5 bg-gray-200 rounded-full dark:bg-gray-700 w-48 mb-4"></div>
|
|
51
|
-
<div class="h-2 bg-gray-200 rounded-full dark:bg-gray-700 max-w-[360px] mb-2.5"></div>
|
|
52
|
-
<div class="h-2 bg-gray-200 rounded-full dark:bg-gray-700 mb-2.5"></div>
|
|
53
|
-
<div class="h-2 bg-gray-200 rounded-full dark:bg-gray-700 max-w-[330px] mb-2.5"></div>
|
|
54
|
-
<div class="h-2 bg-gray-200 rounded-full dark:bg-gray-700 max-w-[300px] mb-2.5"></div>
|
|
55
|
-
<div class="h-2 bg-gray-200 rounded-full dark:bg-gray-700 max-w-[360px]"></div>
|
|
56
|
-
<span class="sr-only">{{ $t('Loading...') }}</span>
|
|
57
|
-
</div>
|
|
58
|
-
<div
|
|
59
|
-
v-else-if="coreStore.record"
|
|
60
|
-
class="relative w-full flex flex-col gap-4"
|
|
61
|
-
>
|
|
62
|
-
<div v-if="!groups.length && allColumns.length">
|
|
63
|
-
<ShowTable
|
|
64
|
-
:columns="allColumns"
|
|
65
|
-
:resource="coreStore.resource"
|
|
66
|
-
:record="coreStore.record"
|
|
67
|
-
/>
|
|
68
|
-
</div>
|
|
69
|
-
<template v-else>
|
|
70
|
-
<template v-for="group in groups" :key="group.groupName">
|
|
71
|
-
<ShowTable
|
|
72
|
-
:columns="group.columns"
|
|
73
|
-
:groupName="group.groupName"
|
|
74
|
-
:resource="coreStore.resource"
|
|
75
|
-
:record="coreStore.record"
|
|
76
|
-
/>
|
|
77
|
-
</template>
|
|
78
|
-
<template v-if="otherColumns.length > 0">
|
|
79
|
-
<ShowTable
|
|
80
|
-
:columns="otherColumns"
|
|
81
|
-
groupName="Other Fields"
|
|
82
|
-
:resource="coreStore.resource"
|
|
83
|
-
:record="coreStore.record"
|
|
84
|
-
/>
|
|
85
|
-
</template>
|
|
86
|
-
</template>
|
|
87
|
-
</div>
|
|
88
|
-
|
|
89
|
-
<div v-else class="text-center text-gray-500 dark:text-gray-400 mt-10">
|
|
90
|
-
{{ $t('Ooops. Record not found') }}
|
|
91
|
-
</div>
|
|
92
|
-
|
|
93
|
-
<component
|
|
94
|
-
v-if="!loading"
|
|
95
|
-
v-for="c in coreStore?.resourceOptions?.pageInjections?.show?.bottom || []"
|
|
96
|
-
:is="getCustomComponent(c)"
|
|
97
|
-
:meta="c.meta"
|
|
98
|
-
:column="column"
|
|
99
|
-
:record="coreStore.record"
|
|
100
|
-
:resource="coreStore.resource"
|
|
101
|
-
:adminUser="coreStore.adminUser"
|
|
102
|
-
/>
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
</div>
|
|
106
|
-
</template>
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
<script setup lang="ts">
|
|
110
|
-
|
|
111
|
-
import BreadcrumbsWithButtons from '@/components/BreadcrumbsWithButtons.vue';
|
|
112
|
-
|
|
113
|
-
import { useCoreStore } from '@/stores/core';
|
|
114
|
-
import { getCustomComponent, checkAcessByAllowedActions, initThreeDotsDropdown } from '@/utils';
|
|
115
|
-
import { IconPenSolid, IconTrashBinSolid, IconPlusOutline } from '@iconify-prerendered/vue-flowbite';
|
|
116
|
-
import { onMounted, ref, computed } from 'vue';
|
|
117
|
-
import { useRoute,useRouter } from 'vue-router';
|
|
118
|
-
import {callAdminForthApi} from '@/utils';
|
|
119
|
-
import { showSuccesTost, showErrorTost } from '@/composables/useFrontendApi';
|
|
120
|
-
import ThreeDotsMenu from '@/components/ThreeDotsMenu.vue';
|
|
121
|
-
import ShowTable from '@/components/ShowTable.vue';
|
|
122
|
-
import adminforth from "@/adminforth";
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
const route = useRoute();
|
|
126
|
-
const router = useRouter();
|
|
127
|
-
const loading = ref(true);
|
|
128
|
-
|
|
129
|
-
const coreStore = useCoreStore();
|
|
130
|
-
|
|
131
|
-
onMounted(async () => {
|
|
132
|
-
loading.value = true;
|
|
133
|
-
await coreStore.fetchResourceFull({
|
|
134
|
-
resourceId: route.params.resourceId
|
|
135
|
-
});
|
|
136
|
-
initThreeDotsDropdown();
|
|
137
|
-
await coreStore.fetchRecord({
|
|
138
|
-
resourceId: route.params.resourceId,
|
|
139
|
-
primaryKey: route.params.primaryKey,
|
|
140
|
-
source: 'show',
|
|
141
|
-
});
|
|
142
|
-
checkAcessByAllowedActions(coreStore.resourceOptions.allowedActions,'show');
|
|
143
|
-
loading.value = false;
|
|
144
|
-
});
|
|
145
|
-
|
|
146
|
-
const groups = computed(() => {
|
|
147
|
-
let fieldGroupType;
|
|
148
|
-
if (coreStore.resource.options?.showFieldGroups) {
|
|
149
|
-
fieldGroupType = coreStore.resource.options.showFieldGroups;
|
|
150
|
-
} else if (coreStore.resource.options?.showFieldGroups === null) {
|
|
151
|
-
fieldGroupType = [];
|
|
152
|
-
} else {
|
|
153
|
-
fieldGroupType = coreStore.resource.options?.fieldGroups;
|
|
154
|
-
}
|
|
155
|
-
|
|
156
|
-
const activeGroups = fieldGroupType ?? [];
|
|
157
|
-
|
|
158
|
-
return activeGroups.map(group => ({
|
|
159
|
-
...group,
|
|
160
|
-
columns: coreStore.resource.columns.filter(
|
|
161
|
-
col => group.columns.includes(col.name) && col.showIn.includes('show')
|
|
162
|
-
),
|
|
163
|
-
}));
|
|
164
|
-
});
|
|
165
|
-
|
|
166
|
-
const allColumns = computed(() => {
|
|
167
|
-
return coreStore.resource.columns.filter(col => col.showIn.includes('show'));
|
|
168
|
-
});
|
|
169
|
-
|
|
170
|
-
const otherColumns = computed(() => {
|
|
171
|
-
const groupedColumnNames = new Set(
|
|
172
|
-
groups.value.flatMap(group => group.columns.map(col => col.name))
|
|
173
|
-
);
|
|
174
|
-
|
|
175
|
-
return coreStore.resource.columns.filter(
|
|
176
|
-
col => !groupedColumnNames.has(col.name) && col.showIn.includes('show')
|
|
177
|
-
);
|
|
178
|
-
});
|
|
179
|
-
|
|
180
|
-
async function deleteRecord(row) {
|
|
181
|
-
const data = await adminforth.confirm({
|
|
182
|
-
message: 'Are you sure you want to delete this item?',
|
|
183
|
-
yes: 'Delete',
|
|
184
|
-
no: 'Cancel',
|
|
185
|
-
});
|
|
186
|
-
if (data) {
|
|
187
|
-
try {
|
|
188
|
-
const res = await callAdminForthApi({
|
|
189
|
-
path: '/delete_record',
|
|
190
|
-
method: 'POST',
|
|
191
|
-
body: {
|
|
192
|
-
resourceId: route.params.resourceId,
|
|
193
|
-
primaryKey: route.params.primaryKey,
|
|
194
|
-
}});
|
|
195
|
-
if (!res.error){
|
|
196
|
-
router.push({ name: 'resource-list', params: { resourceId: route.params.resourceId } });
|
|
197
|
-
showSuccesTost('Record deleted successfully')
|
|
198
|
-
} else {
|
|
199
|
-
showErrorTost(res.error)
|
|
200
|
-
}
|
|
201
|
-
|
|
202
|
-
} catch (e) {
|
|
203
|
-
console.error(e);
|
|
204
|
-
};
|
|
205
|
-
}
|
|
206
|
-
|
|
207
|
-
}
|
|
208
|
-
|
|
209
|
-
</script>
|
|
@@ -1,129 +0,0 @@
|
|
|
1
|
-
|
|
2
|
-
const subscriptions: { [topic: string]: ((data: any) => void)[] } = {};
|
|
3
|
-
const state: {
|
|
4
|
-
status: 'connecting' | 'connected' | 'disconnected';
|
|
5
|
-
ws: WebSocket | null;
|
|
6
|
-
} = {
|
|
7
|
-
status: 'connecting',
|
|
8
|
-
ws: null
|
|
9
|
-
};
|
|
10
|
-
|
|
11
|
-
function doPhysicalSubscribe(topic: string) {
|
|
12
|
-
state.ws!.send(JSON.stringify({ type: 'subscribe', topic }));
|
|
13
|
-
}
|
|
14
|
-
|
|
15
|
-
function doPhysicalUnsubscribe(topic: string) {
|
|
16
|
-
state.ws!.send(JSON.stringify({ type: 'unsubscribe', topic }));
|
|
17
|
-
}
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
async function connect () {
|
|
21
|
-
// if socket is not supported return
|
|
22
|
-
if (!window.WebSocket) {
|
|
23
|
-
console.error('Websocket not supported by this browser');
|
|
24
|
-
return;
|
|
25
|
-
}
|
|
26
|
-
if (state.ws?.connected) {
|
|
27
|
-
console.error('🔌 AFWS already connected');
|
|
28
|
-
return;
|
|
29
|
-
}
|
|
30
|
-
|
|
31
|
-
let base = import.meta.env.VITE_ADMINFORTH_PUBLIC_PATH || '';
|
|
32
|
-
if (base.endsWith('/')) {
|
|
33
|
-
base = base.slice(0, -1);
|
|
34
|
-
}
|
|
35
|
-
|
|
36
|
-
state.ws = new WebSocket(`${
|
|
37
|
-
window.location.protocol === 'http:' ? 'ws' : 'wss'
|
|
38
|
-
}://${window.location.host}${base}/afws`);
|
|
39
|
-
state.status = 'connecting';
|
|
40
|
-
state.ws.addEventListener('open', () => {
|
|
41
|
-
console.log('🔌 AFWS connected');
|
|
42
|
-
state.status = 'connected';
|
|
43
|
-
|
|
44
|
-
});
|
|
45
|
-
state.ws.addEventListener('message', (event) => {
|
|
46
|
-
const data = event.data.toString();
|
|
47
|
-
if (data === 'pong') {
|
|
48
|
-
return;
|
|
49
|
-
}
|
|
50
|
-
console.log('🔌 AFWS message', data);
|
|
51
|
-
|
|
52
|
-
const message = JSON.parse(data);
|
|
53
|
-
if (message.type === 'ready') {
|
|
54
|
-
Object.keys(subscriptions).forEach((topic) => {
|
|
55
|
-
doPhysicalSubscribe(topic);
|
|
56
|
-
});
|
|
57
|
-
return
|
|
58
|
-
}
|
|
59
|
-
if (message.type === 'message') {
|
|
60
|
-
const topic = message.topic;
|
|
61
|
-
const data = message.data;
|
|
62
|
-
if (subscriptions[topic]) {
|
|
63
|
-
for (const callback of subscriptions[topic]) {
|
|
64
|
-
callback(data);
|
|
65
|
-
}
|
|
66
|
-
}
|
|
67
|
-
}
|
|
68
|
-
});
|
|
69
|
-
state.ws.addEventListener('close', () => {
|
|
70
|
-
console.log('🔌 AFWS disconnected');
|
|
71
|
-
setTimeout(() => {
|
|
72
|
-
console.log('🔌 AFWS reconnecting after close');
|
|
73
|
-
connect();
|
|
74
|
-
// if it is first time, reconnect instantly
|
|
75
|
-
}, state.status === 'connected' ? 0 : 2_000);
|
|
76
|
-
state.status = 'disconnected';
|
|
77
|
-
});
|
|
78
|
-
}
|
|
79
|
-
|
|
80
|
-
try {
|
|
81
|
-
connect();
|
|
82
|
-
} catch (e) {
|
|
83
|
-
console.error('🔌 AFWS failed to connect', e);
|
|
84
|
-
}
|
|
85
|
-
|
|
86
|
-
export function reconnect() {
|
|
87
|
-
console.log('🔌 AFWS reconnect initiated');
|
|
88
|
-
// disconnect if already connected
|
|
89
|
-
if (state.status === 'connected') {
|
|
90
|
-
state.ws!.close();
|
|
91
|
-
}
|
|
92
|
-
|
|
93
|
-
}
|
|
94
|
-
|
|
95
|
-
setInterval(() => {
|
|
96
|
-
if (state.status === 'connected') {
|
|
97
|
-
state.ws!.send('ping');
|
|
98
|
-
}
|
|
99
|
-
}, 10_000);
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
export default {
|
|
103
|
-
subscribe(topic: string, callback: (data: any) => void): void {
|
|
104
|
-
if (!subscriptions[topic]) {
|
|
105
|
-
subscriptions[topic] = [];
|
|
106
|
-
}
|
|
107
|
-
subscriptions[topic].push(callback);
|
|
108
|
-
if (state.status === 'connected') {
|
|
109
|
-
doPhysicalSubscribe(topic);
|
|
110
|
-
}
|
|
111
|
-
},
|
|
112
|
-
|
|
113
|
-
unsubscribe(topic: string): void {
|
|
114
|
-
delete subscriptions[topic];
|
|
115
|
-
if (state.status === 'connected') {
|
|
116
|
-
doPhysicalUnsubscribe(topic);
|
|
117
|
-
}
|
|
118
|
-
},
|
|
119
|
-
|
|
120
|
-
unsubscribeAll(): void {
|
|
121
|
-
Object.keys(subscriptions).forEach((topic) => {
|
|
122
|
-
delete subscriptions[topic];
|
|
123
|
-
if (state.status === 'connected') {
|
|
124
|
-
doPhysicalUnsubscribe(topic);
|
|
125
|
-
}
|
|
126
|
-
});
|
|
127
|
-
}
|
|
128
|
-
|
|
129
|
-
}
|
|
@@ -1,19 +0,0 @@
|
|
|
1
|
-
/** @type {import('tailwindcss').Config} */
|
|
2
|
-
import flowbitePlugin from 'flowbite/plugin';
|
|
3
|
-
|
|
4
|
-
export default {
|
|
5
|
-
content: ["./src/**/*.{vue, js, ts, tsx}","./src/*.{vue, js, ts, tsx}", "./index.html", "./node_modules/flowbite/**/*.js"],
|
|
6
|
-
theme: {
|
|
7
|
-
extend: {
|
|
8
|
-
/* IMPORTANT:ADMINFORTH TAILWIND STYLES */
|
|
9
|
-
}
|
|
10
|
-
},
|
|
11
|
-
|
|
12
|
-
darkMode: 'class',
|
|
13
|
-
plugins: [
|
|
14
|
-
flowbitePlugin({
|
|
15
|
-
charts: true,
|
|
16
|
-
}),
|
|
17
|
-
],
|
|
18
|
-
}
|
|
19
|
-
|
|
@@ -1,14 +0,0 @@
|
|
|
1
|
-
{
|
|
2
|
-
"extends": "@vue/tsconfig/tsconfig.dom.json",
|
|
3
|
-
"include": ["env.d.ts", "src/**/*", "src/**/*.vue"],
|
|
4
|
-
"exclude": ["src/**/__tests__/*"],
|
|
5
|
-
"compilerOptions": {
|
|
6
|
-
"composite": true,
|
|
7
|
-
"tsBuildInfoFile": "./node_modules/.tmp/tsconfig.app.tsbuildinfo",
|
|
8
|
-
|
|
9
|
-
"baseUrl": ".",
|
|
10
|
-
"paths": {
|
|
11
|
-
"@/*": ["./src/*"]
|
|
12
|
-
}
|
|
13
|
-
}
|
|
14
|
-
}
|
package/dist/spa/tsconfig.json
DELETED
|
@@ -1,19 +0,0 @@
|
|
|
1
|
-
{
|
|
2
|
-
"extends": "@tsconfig/node20/tsconfig.json",
|
|
3
|
-
"include": [
|
|
4
|
-
"vite.config.*",
|
|
5
|
-
"vitest.config.*",
|
|
6
|
-
"cypress.config.*",
|
|
7
|
-
"nightwatch.conf.*",
|
|
8
|
-
"playwright.config.*"
|
|
9
|
-
],
|
|
10
|
-
"compilerOptions": {
|
|
11
|
-
"composite": true,
|
|
12
|
-
"noEmit": true,
|
|
13
|
-
"tsBuildInfoFile": "./node_modules/.tmp/tsconfig.node.tsbuildinfo",
|
|
14
|
-
|
|
15
|
-
"module": "ESNext",
|
|
16
|
-
"moduleResolution": "Bundler",
|
|
17
|
-
"types": ["node"]
|
|
18
|
-
}
|
|
19
|
-
}
|
package/dist/spa/vite.config.ts
DELETED
|
@@ -1,52 +0,0 @@
|
|
|
1
|
-
import { fileURLToPath, URL } from 'node:url'
|
|
2
|
-
|
|
3
|
-
import { defineConfig } from 'vite'
|
|
4
|
-
import vue from '@vitejs/plugin-vue'
|
|
5
|
-
import portfinder from 'portfinder';
|
|
6
|
-
|
|
7
|
-
/**
|
|
8
|
-
* Find the next available port after a specified port.
|
|
9
|
-
* @param {number} startPort - The starting port to check.
|
|
10
|
-
* @returns {Promise<number>} - A promise that resolves with the next available port.
|
|
11
|
-
*/
|
|
12
|
-
async function getNextAvailablePort(startPort) {
|
|
13
|
-
return await portfinder.getPortPromise({ port: startPort });
|
|
14
|
-
};
|
|
15
|
-
|
|
16
|
-
const appPort = await getNextAvailablePort(5173);
|
|
17
|
-
const hmrPort = await getNextAvailablePort(5273);
|
|
18
|
-
console.log(`SPA port: ${appPort}. HMR port: ${hmrPort}`);
|
|
19
|
-
// https://vitejs.dev/config/
|
|
20
|
-
export default defineConfig({
|
|
21
|
-
base: process.env.VITE_ADMINFORTH_PUBLIC_PATH || '/',
|
|
22
|
-
server: {
|
|
23
|
-
port: appPort,
|
|
24
|
-
hmr: {
|
|
25
|
-
path: '/adminforth-dev-server-ws', // Set your custom WebSocket path here
|
|
26
|
-
port: hmrPort,
|
|
27
|
-
},
|
|
28
|
-
},
|
|
29
|
-
plugins: [
|
|
30
|
-
vue(),
|
|
31
|
-
],
|
|
32
|
-
resolve: {
|
|
33
|
-
alias: {
|
|
34
|
-
'@': fileURLToPath(new URL('./src', import.meta.url)),
|
|
35
|
-
'@@': fileURLToPath(new URL('./src/custom', import.meta.url)),
|
|
36
|
-
}
|
|
37
|
-
},
|
|
38
|
-
build: {
|
|
39
|
-
rollupOptions: {
|
|
40
|
-
output: {
|
|
41
|
-
manualChunks(id) {
|
|
42
|
-
// reduce the size of the vendor chunk
|
|
43
|
-
// to only include the package name
|
|
44
|
-
// helps to reduce consumption of memory
|
|
45
|
-
if (id.includes('node_modules')) {
|
|
46
|
-
return id.toString().split('node_modules/')[1].split('/')[0].toString();
|
|
47
|
-
}
|
|
48
|
-
},
|
|
49
|
-
},
|
|
50
|
-
},
|
|
51
|
-
},
|
|
52
|
-
})
|