@signal24/vue-foundation 4.2.0 → 4.2.2
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/src/helpers/mask.d.ts +1 -1
- package/dist/src/helpers/openapi.d.ts +8 -2
- package/dist/src/helpers/string.d.ts +1 -0
- package/dist/src/vite-plugins/vite-openapi-plugin.cli.js +4 -3
- package/dist/src/vite-plugins/vite-openapi-plugin.d.ts +4 -3
- package/dist/src/vite-plugins/vite-openapi-plugin.js +35 -12
- package/dist/vue-foundation.es.js +436 -402
- package/package.json +5 -3
- package/src/components/alert-modal.vue +1 -2
- package/src/components/ez-smart-select.vue +5 -5
- package/src/directives/datetime.ts +1 -1
- package/src/helpers/error.ts +1 -2
- package/src/helpers/mask.ts +5 -5
- package/src/helpers/openapi.ts +4 -4
- package/src/helpers/string.ts +6 -0
- package/src/vite-plugins/vite-openapi-plugin.cli.ts +4 -3
- package/src/vite-plugins/vite-openapi-plugin.ts +47 -12
- package/{vite.config.js → vite.config.ts} +1 -1
- /package/{vitest.config.js → vitest.config.ts} +0 -0
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@signal24/vue-foundation",
|
|
3
3
|
"type": "module",
|
|
4
|
-
"version": "4.2.
|
|
4
|
+
"version": "4.2.2",
|
|
5
5
|
"description": "Common components, directives, and helpers for Vue 3 apps",
|
|
6
6
|
"module": "./dist/vue-foundation.es.js",
|
|
7
7
|
"bin": {
|
|
@@ -39,15 +39,17 @@
|
|
|
39
39
|
"date-fns": "^2.30.0",
|
|
40
40
|
"lodash": "^4.17.21",
|
|
41
41
|
"type-fest": "^3.11.0",
|
|
42
|
+
"uuid": "^9.0.0",
|
|
42
43
|
"vue": "^3.3.4"
|
|
43
44
|
},
|
|
44
45
|
"devDependencies": {
|
|
45
46
|
"@nabla/vite-plugin-eslint": "^1.5.0",
|
|
46
|
-
"@rushstack/eslint-patch": "^1.
|
|
47
|
+
"@rushstack/eslint-patch": "^1.3.0",
|
|
47
48
|
"@tsconfig/node18": "^2.0.1",
|
|
48
49
|
"@types/jsdom": "^21.1.1",
|
|
49
50
|
"@types/lodash": "^4.14.194",
|
|
50
51
|
"@types/node": "^18.15.11",
|
|
52
|
+
"@types/uuid": "^9.0.1",
|
|
51
53
|
"@vitejs/plugin-vue": "^4.2.3",
|
|
52
54
|
"@vue/eslint-config-prettier": "^7.1.0",
|
|
53
55
|
"@vue/eslint-config-typescript": "^11.0.3",
|
|
@@ -58,7 +60,7 @@
|
|
|
58
60
|
"eslint-plugin-cypress": "^2.13.3",
|
|
59
61
|
"eslint-plugin-simple-import-sort": "^10.0.0",
|
|
60
62
|
"eslint-plugin-unused-imports": "^2.0.0",
|
|
61
|
-
"eslint-plugin-vue": "^9.
|
|
63
|
+
"eslint-plugin-vue": "^9.14.0",
|
|
62
64
|
"jsdom": "^22.0.0",
|
|
63
65
|
"openapi-typescript-codegen": "^0.24.0",
|
|
64
66
|
"prettier": "^2.8.8",
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
<template>
|
|
2
|
-
<VfSmartSelect v-model="selectedItem" :options="
|
|
2
|
+
<VfSmartSelect v-model="selectedItem" :options="computedOpts" :formatter="ezFormatter" :null-title="nullTitle" />
|
|
3
3
|
</template>
|
|
4
4
|
|
|
5
5
|
<script lang="ts" setup>
|
|
@@ -18,7 +18,7 @@ const props = defineProps<{
|
|
|
18
18
|
formatter?: (value: any) => string;
|
|
19
19
|
}>();
|
|
20
20
|
|
|
21
|
-
const
|
|
21
|
+
const computedOpts = computed(() => {
|
|
22
22
|
return Array.isArray(props.options)
|
|
23
23
|
? props.options.map(o => ({ value: o, label: o }))
|
|
24
24
|
: Object.entries(props.options).map(([value, label]) => ({
|
|
@@ -38,14 +38,14 @@ const emit = defineEmits<{
|
|
|
38
38
|
(e: 'update:modelValue', value: string | null): void;
|
|
39
39
|
}>();
|
|
40
40
|
|
|
41
|
-
const selectedItem = ref<GenericObject | null>(
|
|
41
|
+
const selectedItem = ref<GenericObject | null>(computedOpts.value.find(o => o.value === props.modelValue) ?? null);
|
|
42
42
|
watch(
|
|
43
43
|
() => props.modelValue,
|
|
44
44
|
value => {
|
|
45
|
-
selectedItem.value =
|
|
45
|
+
selectedItem.value = computedOpts.value.find(o => o.value === value) ?? null;
|
|
46
46
|
}
|
|
47
47
|
);
|
|
48
48
|
watch(selectedItem, value => {
|
|
49
|
-
emit('update:modelValue', value ?
|
|
49
|
+
emit('update:modelValue', value ? computedOpts.value.find(o => isEqual(o, value))?.value ?? null : null);
|
|
50
50
|
});
|
|
51
51
|
</script>
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { format } from 'date-fns';
|
|
2
2
|
import type { DirectiveBinding, ObjectDirective } from 'vue';
|
|
3
3
|
|
|
4
|
-
import { VfOptions } from '
|
|
4
|
+
import { VfOptions } from '../config';
|
|
5
5
|
|
|
6
6
|
export const vDatetime: ObjectDirective<HTMLElement, string> = {
|
|
7
7
|
beforeMount: applyDateTime,
|
package/src/helpers/error.ts
CHANGED
package/src/helpers/mask.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { AnyComponentPublicInstance } from '
|
|
1
|
+
import type { AnyComponentPublicInstance } from '../components/modal-container';
|
|
2
2
|
|
|
3
3
|
/*///////////////////////////////////////////////
|
|
4
4
|
Component Overlay Masking
|
|
@@ -51,7 +51,7 @@ interface IFormMaskState {
|
|
|
51
51
|
[FormMaskState]?: {
|
|
52
52
|
disabledElements: HTMLElement[];
|
|
53
53
|
waitButton: HTMLElement;
|
|
54
|
-
|
|
54
|
+
buttonHtml: string;
|
|
55
55
|
};
|
|
56
56
|
}
|
|
57
57
|
type FormMaskElement = Element & IFormMaskState;
|
|
@@ -63,7 +63,7 @@ export function maskForm(formOrCmp: Element | AnyComponentPublicInstance, button
|
|
|
63
63
|
const buttonEl = (
|
|
64
64
|
buttonSelector instanceof Element ? buttonSelector : form.querySelectorAll(buttonSelector ?? 'button:not([disabled])')[0]
|
|
65
65
|
) as HTMLElement;
|
|
66
|
-
const
|
|
66
|
+
const originalButtonHtml = buttonEl.tagName === 'INPUT' ? (buttonEl as HTMLInputElement).value : buttonEl.innerHTML;
|
|
67
67
|
buttonEl.setAttribute('disabled', 'disabled');
|
|
68
68
|
buttonEl.innerText = buttonText ?? 'Please wait...';
|
|
69
69
|
|
|
@@ -74,7 +74,7 @@ export function maskForm(formOrCmp: Element | AnyComponentPublicInstance, button
|
|
|
74
74
|
(form as FormMaskElement)[FormMaskState] = {
|
|
75
75
|
disabledElements: inputs,
|
|
76
76
|
waitButton: buttonEl,
|
|
77
|
-
|
|
77
|
+
buttonHtml: originalButtonHtml
|
|
78
78
|
};
|
|
79
79
|
|
|
80
80
|
return () => unmaskForm(form);
|
|
@@ -89,7 +89,7 @@ export function unmaskForm(formOrCmp: Element | AnyComponentPublicInstance) {
|
|
|
89
89
|
form.classList.remove('vf-masked');
|
|
90
90
|
|
|
91
91
|
state.disabledElements.forEach(el => el.removeAttribute('disabled'));
|
|
92
|
-
state.waitButton.
|
|
92
|
+
state.waitButton.innerHTML = state.buttonHtml;
|
|
93
93
|
state.waitButton.removeAttribute('disabled');
|
|
94
94
|
|
|
95
95
|
delete (form as FormMaskElement)[FormMaskState];
|
package/src/helpers/openapi.ts
CHANGED
|
@@ -18,17 +18,17 @@ interface IBaseHttpRequest {
|
|
|
18
18
|
request<T>(options: IRequestOptions): ICancelablePromise<T>;
|
|
19
19
|
}
|
|
20
20
|
|
|
21
|
-
interface IApiClient {
|
|
21
|
+
export interface IApiClient {
|
|
22
22
|
request: IBaseHttpRequest;
|
|
23
23
|
}
|
|
24
24
|
|
|
25
|
-
interface IApiError extends Error {
|
|
25
|
+
export interface IApiError extends Error {
|
|
26
26
|
status: number;
|
|
27
27
|
statusText: string;
|
|
28
28
|
body: any;
|
|
29
29
|
}
|
|
30
30
|
|
|
31
|
-
declare class ICancelablePromise<T = any> {
|
|
31
|
+
export declare class ICancelablePromise<T = any> {
|
|
32
32
|
constructor(executor: (resolve: (value: any) => void, reject: (reason: any) => void, onCancel: (cancel: () => void) => void) => void);
|
|
33
33
|
then<TResult1 = any, TResult2 = never>(
|
|
34
34
|
onfulfilled?: ((value: T) => TResult1 | PromiseLike<TResult1>) | undefined | null,
|
|
@@ -46,7 +46,7 @@ interface IWrappedApiClientOptions<P extends ICancelablePromise = ICancelablePro
|
|
|
46
46
|
CancelablePromise: new (...arguments_: Arguments) => P;
|
|
47
47
|
}
|
|
48
48
|
|
|
49
|
-
function isApiError(err: any): err is IApiError {
|
|
49
|
+
export function isApiError(err: any): err is IApiError {
|
|
50
50
|
return err instanceof Error && 'status' in err && 'body' in err;
|
|
51
51
|
}
|
|
52
52
|
|
package/src/helpers/string.ts
CHANGED
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
import { v4 as uuidv4 } from 'uuid';
|
|
2
|
+
|
|
1
3
|
// placing this here so we don't have to use the ESLint rule everywhere
|
|
2
4
|
// eslint-disable-next-line vue/prefer-import-from-vue
|
|
3
5
|
export { escapeHtml } from '@vue/shared';
|
|
@@ -25,3 +27,7 @@ export function formatUSCurrency(value: string | number) {
|
|
|
25
27
|
.replace(/\B(?=(\d{3})+(?!\d))/g, ',')
|
|
26
28
|
);
|
|
27
29
|
}
|
|
30
|
+
|
|
31
|
+
export function uuid() {
|
|
32
|
+
return uuidv4();
|
|
33
|
+
}
|
|
@@ -2,14 +2,15 @@
|
|
|
2
2
|
|
|
3
3
|
import { existsSync } from 'fs';
|
|
4
4
|
|
|
5
|
-
import { generateOpenapiClient } from './vite-openapi-plugin.js';
|
|
5
|
+
import { generateOpenapiClient, loadOpenapiOverrides } from './vite-openapi-plugin.js';
|
|
6
6
|
|
|
7
7
|
if (!process.argv[2]) {
|
|
8
|
-
throw new Error('Usage: vf-generate-openapi-client <openapi-yaml-path>');
|
|
8
|
+
throw new Error('Usage: vf-generate-openapi-client <openapi-yaml-path> [<openapi-output-path>]');
|
|
9
9
|
}
|
|
10
10
|
|
|
11
11
|
if (!existsSync(process.argv[2])) {
|
|
12
12
|
throw new Error(`OpenAPI YAML file not found: ${process.argv[2]}`);
|
|
13
13
|
}
|
|
14
14
|
|
|
15
|
-
|
|
15
|
+
loadOpenapiOverrides();
|
|
16
|
+
await generateOpenapiClient(process.argv[2], process.argv[3]);
|
|
@@ -4,9 +4,33 @@ import { rm } from 'node:fs/promises';
|
|
|
4
4
|
|
|
5
5
|
import * as OpenAPI from 'openapi-typescript-codegen';
|
|
6
6
|
|
|
7
|
+
const DEFAULT_OUT_PATH = './src/openapi-client-generated';
|
|
8
|
+
|
|
7
9
|
let generatedHash: string | null = null;
|
|
10
|
+
let overridesMap: Record<string, string> | null = null;
|
|
11
|
+
|
|
12
|
+
export function loadOpenapiOverrides() {
|
|
13
|
+
if (!existsSync('./openapi-specs.overrides.json')) {
|
|
14
|
+
return;
|
|
15
|
+
}
|
|
8
16
|
|
|
9
|
-
|
|
17
|
+
try {
|
|
18
|
+
const overridesContent = readFileSync('./openapi-specs.overrides.json', 'utf8');
|
|
19
|
+
overridesMap = JSON.parse(overridesContent);
|
|
20
|
+
} catch (e) {
|
|
21
|
+
console.error('Failed to load openapi-specs.overrides.json:', e);
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
export function openapiClientGeneratorPlugin(
|
|
26
|
+
openapiYamlPath: string,
|
|
27
|
+
outPath: string = DEFAULT_OUT_PATH
|
|
28
|
+
): {
|
|
29
|
+
name: string;
|
|
30
|
+
apply: 'serve';
|
|
31
|
+
buildStart(): void;
|
|
32
|
+
closeBundle(): void;
|
|
33
|
+
} {
|
|
10
34
|
let generator: ReturnType<typeof getGenerator> = null;
|
|
11
35
|
|
|
12
36
|
return {
|
|
@@ -14,7 +38,11 @@ export function openapiClientGeneratorPlugin(openapiYamlPath: string) {
|
|
|
14
38
|
apply: 'serve',
|
|
15
39
|
|
|
16
40
|
buildStart() {
|
|
17
|
-
|
|
41
|
+
// apply a slight delay so any output doesn't get pushed off screen
|
|
42
|
+
setTimeout(() => {
|
|
43
|
+
loadOpenapiOverrides();
|
|
44
|
+
generator = getGenerator(openapiYamlPath, outPath);
|
|
45
|
+
}, 250);
|
|
18
46
|
},
|
|
19
47
|
|
|
20
48
|
closeBundle() {
|
|
@@ -23,19 +51,21 @@ export function openapiClientGeneratorPlugin(openapiYamlPath: string) {
|
|
|
23
51
|
};
|
|
24
52
|
}
|
|
25
53
|
|
|
26
|
-
function getGenerator(openapiYamlPath: string) {
|
|
27
|
-
|
|
28
|
-
|
|
54
|
+
function getGenerator(openapiYamlPath: string, outPath: string) {
|
|
55
|
+
const resolvedPath = overridesMap?.[openapiYamlPath] ?? openapiYamlPath;
|
|
56
|
+
|
|
57
|
+
if (!existsSync(resolvedPath)) {
|
|
58
|
+
console.log(`OpenAPI YAML file not found: ${resolvedPath}`);
|
|
29
59
|
return null;
|
|
30
60
|
}
|
|
31
61
|
|
|
32
|
-
const watcher = watch(
|
|
62
|
+
const watcher = watch(resolvedPath);
|
|
33
63
|
watcher.on('change', () => {
|
|
34
64
|
// give the writes a moment to settle
|
|
35
|
-
setTimeout(() => generateOpenapiClient(
|
|
65
|
+
setTimeout(() => generateOpenapiClient(resolvedPath, outPath), 100);
|
|
36
66
|
});
|
|
37
67
|
|
|
38
|
-
generateOpenapiClient(
|
|
68
|
+
generateOpenapiClient(resolvedPath, outPath);
|
|
39
69
|
|
|
40
70
|
return {
|
|
41
71
|
close() {
|
|
@@ -44,7 +74,7 @@ function getGenerator(openapiYamlPath: string) {
|
|
|
44
74
|
};
|
|
45
75
|
}
|
|
46
76
|
|
|
47
|
-
|
|
77
|
+
async function generateOpenapiClientInternal(openapiYamlPath: string, outPath: string = DEFAULT_OUT_PATH) {
|
|
48
78
|
const yaml = readFileSync(openapiYamlPath, 'utf8');
|
|
49
79
|
const hash = createHash('sha256').update(yaml).digest('hex');
|
|
50
80
|
|
|
@@ -56,21 +86,26 @@ export async function generateOpenapiClient(openapiYamlPath: string) {
|
|
|
56
86
|
|
|
57
87
|
try {
|
|
58
88
|
try {
|
|
59
|
-
await rm(
|
|
89
|
+
await rm(outPath, { recursive: true });
|
|
60
90
|
} catch (e) {
|
|
61
91
|
// ignore
|
|
62
92
|
}
|
|
63
93
|
|
|
64
94
|
await OpenAPI.generate({
|
|
65
95
|
input: openapiYamlPath,
|
|
66
|
-
output:
|
|
96
|
+
output: outPath,
|
|
67
97
|
clientName: 'ApiClient',
|
|
68
98
|
useOptions: true,
|
|
69
99
|
useUnionTypes: true
|
|
70
100
|
});
|
|
71
101
|
|
|
72
|
-
console.log(`[${new Date().toISOString()}] Generated client from ${openapiYamlPath} to
|
|
102
|
+
console.log(`[${new Date().toISOString()}] Generated client from ${openapiYamlPath} to ${outPath}/`);
|
|
73
103
|
} catch (err) {
|
|
74
104
|
console.error(`[${new Date().toISOString()}] Error generating client from ${openapiYamlPath}:`, err);
|
|
75
105
|
}
|
|
76
106
|
}
|
|
107
|
+
|
|
108
|
+
export async function generateOpenapiClient(openapiYamlPath: string, outPath: string = DEFAULT_OUT_PATH) {
|
|
109
|
+
const resolvedPath = overridesMap?.[openapiYamlPath] ?? openapiYamlPath;
|
|
110
|
+
return generateOpenapiClientInternal(resolvedPath, outPath);
|
|
111
|
+
}
|
|
File without changes
|