@drax/settings-vue 0.11.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/package.json ADDED
@@ -0,0 +1,67 @@
1
+ {
2
+ "name": "@drax/settings-vue",
3
+ "publishConfig": {
4
+ "access": "public"
5
+ },
6
+ "version": "0.11.3",
7
+ "type": "module",
8
+ "main": "./src/index.ts",
9
+ "module": "./src/index.ts",
10
+ "types": "./src/index.ts",
11
+ "files": [
12
+ "src"
13
+ ],
14
+ "scripts": {
15
+ "dev": "vite",
16
+ "build": "run-p type-check \"build-only {@}\" --",
17
+ "preview": "vite preview",
18
+ "test:unit": "vitest",
19
+ "test:e2e": "start-server-and-test preview http://localhost:4173 'cypress run --e2e'",
20
+ "test:e2e:dev": "start-server-and-test 'vite dev --port 4173' http://localhost:4173 'cypress open --e2e'",
21
+ "build-only": "vite build",
22
+ "type-check": "vue-tsc --build --force",
23
+ "lint": "eslint . --ext .vue,.js,.jsx,.cjs,.mjs,.ts,.tsx,.cts,.mts --fix --ignore-path .gitignore",
24
+ "format": "prettier --write src/"
25
+ },
26
+ "dependencies": {
27
+ "@drax/common-front": "^0.11.3",
28
+ "@drax/settings-front": "^0.11.3",
29
+ "@drax/settings-share": "^0.11.3"
30
+ },
31
+ "peerDependencies": {
32
+ "pinia": "^2.2.2",
33
+ "vue": "^3.5.7",
34
+ "vue-i18n": "^9.14.0",
35
+ "vuetify": "^3.7.2"
36
+ },
37
+ "devDependencies": {
38
+ "@rushstack/eslint-patch": "^1.8.0",
39
+ "@tsconfig/node20": "^20.1.4",
40
+ "@types/jsdom": "^21.1.7",
41
+ "@types/node": "^20.12.5",
42
+ "@vitejs/plugin-vue": "^5.0.4",
43
+ "@vue/eslint-config-prettier": "^9.0.0",
44
+ "@vue/eslint-config-typescript": "^13.0.0",
45
+ "@vue/test-utils": "^2.4.5",
46
+ "@vue/tsconfig": "^0.5.1",
47
+ "cypress": "^13.7.2",
48
+ "eslint": "^8.57.0",
49
+ "eslint-plugin-cypress": "^2.15.1",
50
+ "eslint-plugin-vue": "^9.23.0",
51
+ "jsdom": "^24.0.0",
52
+ "npm-run-all2": "^6.1.2",
53
+ "pinia": "^2.1.7",
54
+ "pinia-plugin-persistedstate": "^3.2.1",
55
+ "prettier": "^3.2.5",
56
+ "start-server-and-test": "^2.0.3",
57
+ "typescript": "5.6.3",
58
+ "vite": "^5.4.11",
59
+ "vite-plugin-css-injected-by-js": "^3.5.1",
60
+ "vite-plugin-dts": "^3.9.1",
61
+ "vitest": "^1.4.0",
62
+ "vue": "^3.5.3",
63
+ "vue-tsc": "^2.1.10",
64
+ "vuetify": "^3.7.1"
65
+ },
66
+ "gitHead": "54216d94d68dac488969f9c95d3c6be780935f9d"
67
+ }
@@ -0,0 +1,78 @@
1
+ <script setup lang="ts">
2
+ import {useSetting} from "../composables/UseSetting";
3
+ import SettingField from "./SettingField.vue";
4
+ import SettingEditor from "./SettingEditor.vue";
5
+ import {onMounted, ref} from "vue";
6
+ import type {ISetting} from "@drax/settings-share";
7
+
8
+ const {fetchSettings, settingsGrouped, loading} = useSetting()
9
+
10
+ onMounted(async () => {
11
+ await fetchSettings()
12
+ })
13
+
14
+ const settingEditing = ref()
15
+ const editing = ref(false)
16
+
17
+ function edit(setting: ISetting) {
18
+ settingEditing.value = {...setting}
19
+ editing.value = true
20
+ }
21
+
22
+ function clearEdit() {
23
+ editing.value = false
24
+ settingEditing.value = null
25
+ }
26
+
27
+ </script>
28
+
29
+ <template>
30
+ <div>
31
+ <h1 class="mb-6">Settings</h1>
32
+
33
+ <setting-editor
34
+ v-if="editing"
35
+ v-model="editing"
36
+ :setting="settingEditing"
37
+ @updateValue="clearEdit"
38
+ ></setting-editor>
39
+
40
+ <v-row >
41
+ <v-col cols="12" v-for="(group,k) in settingsGrouped">
42
+ <v-card>
43
+ <v-card-title>
44
+ {{ k }}
45
+ </v-card-title>
46
+ <v-card-text>
47
+ <v-row v-for="(setting, i) in group" :key="i">
48
+ <v-col cols="9">
49
+ <setting-field
50
+
51
+ v-model="setting.value"
52
+ :setting="setting"
53
+ ></setting-field>
54
+ </v-col>
55
+ <v-col cols="3">
56
+ <v-btn
57
+ icon="mdi-pencil"
58
+ class="mr-1"
59
+ variant="text"
60
+ color="blue"
61
+ slim
62
+ @click="edit(setting)"
63
+ ></v-btn>
64
+ </v-col>
65
+ </v-row>
66
+
67
+
68
+ </v-card-text>
69
+ </v-card>
70
+ </v-col>
71
+
72
+ </v-row>
73
+ </div>
74
+ </template>
75
+
76
+ <style scoped>
77
+
78
+ </style>
@@ -0,0 +1,75 @@
1
+ <script setup lang="ts">
2
+
3
+ import SettingField from "./SettingField.vue";
4
+ import type {PropType} from "vue";
5
+ import {onMounted, ref} from "vue";
6
+ import type {ISetting} from "@drax/settings-share";
7
+ import {useSetting} from "../composables/UseSetting";
8
+
9
+
10
+ const {updateSettingValue} = useSetting()
11
+
12
+ const valueModel = defineModel<any>({type: [Boolean], default: false})
13
+
14
+ const {setting} = defineProps({
15
+ setting: {type: Object as PropType<ISetting>, required: true}
16
+ })
17
+
18
+ const value = ref()
19
+ const loading = ref(false)
20
+
21
+ onMounted(() => {
22
+ value.value = setting.value
23
+ })
24
+
25
+ const emit = defineEmits(['updateValue'])
26
+
27
+ async function updateValue() {
28
+ try {
29
+ loading.value = true
30
+ await updateSettingValue(setting.id, value.value)
31
+ emit('updateValue', value.value)
32
+ } catch (e) {
33
+ console.error(e)
34
+ } finally {
35
+ loading.value = false
36
+ }
37
+ }
38
+
39
+ </script>
40
+
41
+ <template>
42
+
43
+ <v-dialog v-model="valueModel" max-width="500px">
44
+ <v-card>
45
+ <v-toolbar>
46
+ <v-toolbar-title>
47
+ {{ setting.label }}
48
+ </v-toolbar-title>
49
+ </v-toolbar>
50
+ <v-card-text>
51
+ <v-form v-if="setting" ref="form" autocomplete="off" @submit.prevent>
52
+ <v-row>
53
+ <v-col cols="10">
54
+ <setting-field
55
+ v-model="value"
56
+ :setting="setting"
57
+ editing
58
+ />
59
+ </v-col>
60
+ </v-row>
61
+ </v-form>
62
+ </v-card-text>
63
+ <v-card-actions>
64
+ <v-spacer></v-spacer>
65
+ <v-btn @click="valueModel = false">Cancel</v-btn>
66
+ <v-btn @click="updateValue" color="primary" :loading="loading">Save</v-btn>
67
+ </v-card-actions>
68
+ </v-card>
69
+
70
+ </v-dialog>
71
+ </template>
72
+
73
+ <style scoped>
74
+
75
+ </style>
@@ -0,0 +1,225 @@
1
+ <script setup lang="ts">
2
+
3
+ import type {ISetting} from "@drax/settings-share";
4
+ import {type PropType, ref, computed} from "vue";
5
+
6
+
7
+ const valueModel = defineModel<any>({type: [String, Number, Boolean, Object, Array], default: false})
8
+
9
+
10
+ const {setting, editing} = defineProps({
11
+ setting: {type: Object as PropType<ISetting>, required: true},
12
+ editing: {type: Boolean as PropType<boolean>, default: false}
13
+ })
14
+
15
+ const visible = ref(false)
16
+
17
+ const variant = computed(() => {
18
+ return editing ? 'filled' : 'underlined'
19
+ })
20
+
21
+ const validateRegex = computed(() => {
22
+ return [(val: any) => {
23
+ if (!setting.regex) return true
24
+ let regex = new RegExp(setting.regex)
25
+ if (typeof val === 'string') {
26
+ return regex.test(val) || 'Formato Invalido.'
27
+ }
28
+ if (Array.isArray(val)) {
29
+ return val.every(v => regex.test(v)) || 'Formato Invalido.'
30
+ }
31
+ return true
32
+ }]
33
+ })
34
+
35
+ const validateNumber = computed(() => {
36
+ return [(val: any) => {
37
+ let regex = new RegExp(/\d+/)
38
+ return regex.test(val) || 'Formato Invalido. Solo se esperan números.'
39
+ }]
40
+ })
41
+
42
+ const validateNumberList = computed(() => {
43
+ return [(val: any) => {
44
+ let regex = new RegExp(/\d+/)
45
+ if (Array.isArray(val)) {
46
+ return val.every((v: any) => regex.test(v)) || 'Formato Invalido. Solo se esperan números.'
47
+ }
48
+ return true
49
+ }]
50
+ })
51
+
52
+
53
+ </script>
54
+
55
+ <template>
56
+
57
+ <!--string-->
58
+ <v-text-field v-if="setting.type === 'string'"
59
+ prepend-icon="text_snippet"
60
+ :name="setting.key"
61
+ v-model="valueModel"
62
+ :label="setting.label"
63
+ :placeholder="setting.label"
64
+ color="secondary"
65
+ :rules="validateRegex"
66
+ :prefix="setting.prefix"
67
+ :suffix="setting.suffix"
68
+ :readonly="!editing"
69
+ :variant="variant"
70
+ >
71
+ </v-text-field>
72
+
73
+ <!--longString-->
74
+ <v-textarea v-if="setting.type === 'longString'"
75
+ :rows="2"
76
+ prepend-icon="text_snippet"
77
+ :name="setting.key"
78
+ v-model="valueModel"
79
+ :label="setting.label"
80
+ :placeholder="setting.label"
81
+ color="secondary"
82
+ :rules="validateRegex"
83
+ :prefix="setting.prefix"
84
+ :suffix="setting.suffix"
85
+ :readonly="!editing"
86
+ :variant="variant"
87
+ >
88
+ </v-textarea>
89
+
90
+
91
+ <!--password-->
92
+ <v-text-field v-if=" setting.type === 'password'"
93
+ prepend-icon="text_snippet"
94
+ :name="setting.key"
95
+ v-model="valueModel"
96
+ :label="setting.label"
97
+ :placeholder="setting.label"
98
+ :append-inner-icon="visible ? 'mdi-eye' : 'mdi-eye-off'"
99
+ @click:append-inner="visible =!visible"
100
+ :type="visible ? 'text' : 'password'"
101
+ color="secondary"
102
+ :rules="validateRegex"
103
+ :prefix="setting.prefix"
104
+ :suffix="setting.suffix"
105
+ :readonly="!editing"
106
+ :variant="variant"
107
+ >
108
+ </v-text-field>
109
+
110
+ <!--number-->
111
+ <v-text-field v-if="setting.type === 'number'"
112
+ prepend-icon="text_snippet"
113
+ type="number"
114
+ :name="setting.key"
115
+ v-model.number="valueModel"
116
+ :label="setting.label"
117
+ :placeholder="setting.label"
118
+ :rules="validateNumber"
119
+ color="secondary"
120
+ :prefix="setting.prefix"
121
+ :suffix="setting.suffix"
122
+ :readonly="!editing"
123
+ :variant="variant"
124
+ >
125
+ </v-text-field>
126
+
127
+ <!--boolean-->
128
+ <v-checkbox v-if="setting.type === 'boolean'"
129
+ prepend-icon="text_snippet"
130
+ :name="setting.key"
131
+ :value="true"
132
+ v-model="valueModel"
133
+ :label="setting.label"
134
+ :placeholder="setting.label"
135
+ color="secondary"
136
+ :readonly="!editing"
137
+ :variant="variant"
138
+ >
139
+ </v-checkbox>
140
+
141
+
142
+ <!--enum-->
143
+ <v-select v-if="setting.type === 'enum'"
144
+ prepend-icon="text_snippet"
145
+ :name="setting.key"
146
+ :items="setting.options"
147
+ v-model="valueModel"
148
+ :label="setting.label"
149
+ :placeholder="setting.label"
150
+ color="secondary"
151
+ :prefix="setting.prefix"
152
+ :suffix="setting.suffix"
153
+ :readonly="!editing"
154
+ :variant="variant"
155
+ >
156
+ </v-select>
157
+
158
+
159
+ <!--stringList-->
160
+ <v-combobox v-if="setting.type === 'stringList'"
161
+ chips
162
+ multiple
163
+ prepend-icon="list"
164
+ :name="setting.key"
165
+ v-model="valueModel"
166
+ :label="setting.label"
167
+ :placeholder="setting.label"
168
+ color="secondary"
169
+ :readonly="!editing"
170
+ :variant="variant"
171
+ >
172
+ </v-combobox>
173
+
174
+ <!--numberList-->
175
+ <v-combobox v-if="setting.type === 'numberList'"
176
+ chips
177
+ multiple
178
+ prepend-icon="list"
179
+ :name="setting.key"
180
+ v-model="valueModel"
181
+ :label="setting.label"
182
+ :placeholder="setting.label"
183
+ color="secondary"
184
+ :rules="validateNumberList"
185
+ :readonly="!editing"
186
+ :variant="variant"
187
+ >
188
+ </v-combobox>
189
+
190
+ <!--enumList-->
191
+ <v-select v-if="setting.type === 'enumList'"
192
+ multiple
193
+ chips
194
+ prepend-icon="text_snippet"
195
+ :name="setting.key"
196
+ :items="setting.options"
197
+ v-model="valueModel"
198
+ :label="setting.label"
199
+ :placeholder="setting.label"
200
+ color="secondary"
201
+ :prefix="setting.prefix"
202
+ :suffix="setting.suffix"
203
+ :readonly="!editing"
204
+ :variant="variant"
205
+ >
206
+ </v-select>
207
+
208
+ <!--ref-->
209
+ <!-- <v-select v-if="setting.type === 'ref'"-->
210
+ <!-- prepend-icon="list"-->
211
+ <!-- :name="setting.key"-->
212
+ <!-- setting-text="entityText"-->
213
+ <!-- setting-value="entityValue"-->
214
+ <!-- :settings="entityOptions"-->
215
+ <!-- v-model="valueModel"-->
216
+ <!-- :label="setting.label"-->
217
+ <!-- :placeholder="setting.label"-->
218
+ <!-- color="secondary">-->
219
+ <!-- </v-select>-->
220
+
221
+ </template>
222
+
223
+ <style scoped>
224
+
225
+ </style>
@@ -0,0 +1,84 @@
1
+ import {useSettingStore} from "../stores/UseSettingStore";
2
+ import {computed} from "vue";
3
+ import {SettingProviderFactory} from "@drax/settings-front";
4
+ import type {ISetting} from "@drax/settings-share";
5
+
6
+ export function useSetting() {
7
+
8
+ const store = useSettingStore()
9
+ const provider = SettingProviderFactory.getInstance()
10
+
11
+
12
+ const loading = computed({
13
+ get() {
14
+ return store.loading
15
+ }, set(value) {
16
+ store.setLoading(value)
17
+ }
18
+ })
19
+
20
+ const settings = computed({
21
+ get() {
22
+ return store.settings
23
+ }, set(value) {
24
+ store.setSettings(value)
25
+ }
26
+ })
27
+
28
+ const settingValue = computed(()=>{
29
+ return (key:string) => store.getSettingValueByKey(key)
30
+ })
31
+
32
+ const settingsGrouped = computed(() => {
33
+ return settings.value.reduce((acc, item) => {
34
+ if (!acc[item.group]) {
35
+ acc[item.group] = [];
36
+ }
37
+ acc[item.group].push(item);
38
+ return acc;
39
+ }, {} as { [key: string]: ISetting[] });
40
+ })
41
+
42
+
43
+ async function fetchSettings(): Promise<ISetting[]> {
44
+ try {
45
+ store.setLoading(true)
46
+ const settings = await provider.fetchAll()
47
+ store.setSettings(settings)
48
+ return settings
49
+ } catch (e) {
50
+ console.error("UseSettings fetchSettings", e)
51
+ throw e
52
+ } finally {
53
+ store.setLoading(false)
54
+ }
55
+ }
56
+
57
+ async function updateSettingValue(id:string,value:string): Promise<ISetting> {
58
+ try {
59
+ store.setLoading(true)
60
+ const setting: ISetting = await provider.updateValue(id,value)
61
+ store.updateSetting(setting)
62
+ return setting
63
+ } catch (e) {
64
+ console.error("UseSettings fetchSettings", e)
65
+ throw e
66
+ } finally {
67
+ store.setLoading(false)
68
+ }
69
+ }
70
+
71
+
72
+
73
+ return {
74
+ fetchSettings,
75
+ updateSettingValue,
76
+
77
+ settings,
78
+ settingsGrouped,
79
+ settingValue,
80
+ loading,
81
+
82
+ }
83
+
84
+ }
package/src/index.ts ADDED
@@ -0,0 +1,14 @@
1
+ import {useSetting} from "./composables/UseSetting";
2
+ import {useSettingStore} from "./stores/UseSettingStore";
3
+ import SettingConfig from "./components/SettingConfig.vue";
4
+ import SettingPage from "./pages/SettingPage.vue";
5
+ import SettingRoutes from "./routes/SettingRoutes";
6
+
7
+
8
+ export{
9
+ useSetting,
10
+ useSettingStore,
11
+ SettingConfig,
12
+ SettingPage,
13
+ SettingRoutes
14
+ }
@@ -0,0 +1,14 @@
1
+ <script setup lang="ts">
2
+ import SettingConfig from "../components/SettingConfig.vue";
3
+ </script>
4
+
5
+ <template>
6
+ <v-container max-width="900">
7
+ <setting-config></setting-config>
8
+ </v-container>
9
+
10
+ </template>
11
+
12
+ <style scoped>
13
+
14
+ </style>
@@ -0,0 +1,17 @@
1
+ import SettingPage from '../pages/SettingPage.vue'
2
+
3
+ const routes = [
4
+ {
5
+ name: 'SettingPage',
6
+ path: '/settings',
7
+ component: SettingPage,
8
+ meta: {
9
+ auth: true,
10
+ permission: 'setting:manage'
11
+ }
12
+ },
13
+
14
+ ]
15
+
16
+
17
+ export default routes
@@ -0,0 +1,39 @@
1
+ import {defineStore} from "pinia";
2
+ import type {ISetting} from "@drax/settings-share";
3
+
4
+ export const useSettingStore = defineStore('SettingStore', {
5
+ state: () => (
6
+ {
7
+ loading: false as boolean,
8
+ settings: [] as ISetting[]
9
+ }
10
+ ),
11
+ getters: {
12
+ isSettingsLoading: (state): boolean => state.loading,
13
+ getSettings: (state): ISetting[] => state.settings,
14
+ getSettingByKey: (state) => (key: string): ISetting | undefined => {
15
+ return state.settings.find((setting) => setting.key === key)
16
+ },
17
+ getSettingValueByKey: (state) => (key: string): string | undefined => {
18
+ return state.settings.find((setting) => setting.key === key)?.value
19
+ }
20
+ },
21
+ actions: {
22
+ setLoading(isLoading: boolean): void {
23
+ this.loading = isLoading
24
+ },
25
+ setSettings(settings: ISetting[]): void {
26
+ this.settings = settings
27
+ },
28
+ updateSetting(setting: ISetting): void {
29
+ const index = this.settings.findIndex((s) => s.id === setting.id)
30
+ if (index > -1) {
31
+ this.settings[index] = setting
32
+ } else {
33
+ this.settings.push(setting)
34
+ }
35
+ }
36
+
37
+ }
38
+
39
+ })