frappe-ui 0.1.99 → 0.1.101
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 +1 -1
- package/src/components/FormControl.vue +5 -1
- package/src/components/TextInput.vue +2 -0
- package/src/data-fetching/useCall/useCall.test.ts +1 -1
- package/src/data-fetching/useCall/useCall.ts +12 -6
- package/src/data-fetching/useDoc/useDoc.ts +1 -1
- package/src/data-fetching/useList/types.ts +7 -8
- package/src/data-fetching/useList/useList.test.ts +1 -1
- package/src/data-fetching/useList/useList.ts +32 -24
- package/src/data-fetching/useNewDoc/useNewDoc.ts +17 -1
- package/src/mocks/handlers.ts +1 -4
package/package.json
CHANGED
|
@@ -29,7 +29,11 @@
|
|
|
29
29
|
:id="id"
|
|
30
30
|
v-bind="{ ...controlAttrs, size }"
|
|
31
31
|
/>
|
|
32
|
-
<TextInput
|
|
32
|
+
<TextInput
|
|
33
|
+
v-else
|
|
34
|
+
:id="id"
|
|
35
|
+
v-bind="{ ...controlAttrs, type, size, required }"
|
|
36
|
+
>
|
|
33
37
|
<template #prefix v-if="$slots.prefix">
|
|
34
38
|
<slot name="prefix" />
|
|
35
39
|
</template>
|
|
@@ -22,6 +22,7 @@
|
|
|
22
22
|
:disabled="disabled"
|
|
23
23
|
:id="id"
|
|
24
24
|
:value="modelValue"
|
|
25
|
+
:required="required"
|
|
25
26
|
@input="handleChange"
|
|
26
27
|
@change="handleChange"
|
|
27
28
|
v-bind="attrsWithoutClassStyle"
|
|
@@ -53,6 +54,7 @@ interface TextInputProps {
|
|
|
53
54
|
id?: string
|
|
54
55
|
modelValue?: string | number
|
|
55
56
|
debounce?: number
|
|
57
|
+
required?: boolean
|
|
56
58
|
}
|
|
57
59
|
|
|
58
60
|
defineOptions({
|
|
@@ -88,11 +88,15 @@ export function useCall<TResponse, TParams extends BasicParams = undefined>(
|
|
|
88
88
|
canAbort,
|
|
89
89
|
aborted,
|
|
90
90
|
abort,
|
|
91
|
-
execute,
|
|
91
|
+
execute: _execute,
|
|
92
92
|
onFetchResponse,
|
|
93
93
|
onFetchError,
|
|
94
94
|
} = result
|
|
95
95
|
|
|
96
|
+
function execute(): Promise<TResponse | null> {
|
|
97
|
+
return _execute().then((r) => data.value)
|
|
98
|
+
}
|
|
99
|
+
|
|
96
100
|
onFetchResponse(() => {
|
|
97
101
|
resolve()
|
|
98
102
|
promise.value = makePromise()
|
|
@@ -107,7 +111,9 @@ export function useCall<TResponse, TParams extends BasicParams = undefined>(
|
|
|
107
111
|
if (beforeSubmit) {
|
|
108
112
|
beforeSubmit(params)
|
|
109
113
|
}
|
|
110
|
-
|
|
114
|
+
if (params != null) {
|
|
115
|
+
submitParams.value = params
|
|
116
|
+
}
|
|
111
117
|
if (!refetch) {
|
|
112
118
|
return execute()
|
|
113
119
|
}
|
|
@@ -122,14 +128,14 @@ export function useCall<TResponse, TParams extends BasicParams = undefined>(
|
|
|
122
128
|
|
|
123
129
|
const _data = computed(() => {
|
|
124
130
|
if (normalizedCacheKey && (out.loading || !out.isFinished)) {
|
|
125
|
-
let
|
|
131
|
+
let cachedData = cachedResponse.value as TResponse
|
|
126
132
|
if (transform) {
|
|
127
|
-
let returnValue = transform(
|
|
133
|
+
let returnValue = transform(cachedData)
|
|
128
134
|
if (returnValue !== undefined) {
|
|
129
|
-
|
|
135
|
+
cachedData = returnValue
|
|
130
136
|
}
|
|
131
137
|
}
|
|
132
|
-
return
|
|
138
|
+
return cachedData
|
|
133
139
|
}
|
|
134
140
|
return data.value
|
|
135
141
|
})
|
|
@@ -1,7 +1,9 @@
|
|
|
1
|
-
import { Reactive, Ref } from 'vue'
|
|
1
|
+
import { MaybeRefOrGetter, Reactive, Ref } from 'vue'
|
|
2
2
|
import { CacheKey } from '../useCall/types'
|
|
3
3
|
|
|
4
4
|
export type Field = string
|
|
5
|
+
export type LinkField = `${Field}.${Field}` | `${Field}.${Field} as ${string}`
|
|
6
|
+
export type FieldWithAlias = `${Field} as ${string}`
|
|
5
7
|
|
|
6
8
|
export type ChildTableField = {
|
|
7
9
|
[key: string]: Field[]
|
|
@@ -25,9 +27,9 @@ export type OrderBy =
|
|
|
25
27
|
|
|
26
28
|
export interface UseListOptions<T> {
|
|
27
29
|
doctype: string
|
|
28
|
-
fields?: Array<keyof T | ChildTableField>
|
|
29
|
-
filters?:
|
|
30
|
-
orderBy?: OrderBy
|
|
30
|
+
fields?: Array<keyof T | ChildTableField | LinkField | FieldWithAlias | '*'>
|
|
31
|
+
filters?: MaybeRefOrGetter<Filters>
|
|
32
|
+
orderBy?: MaybeRefOrGetter<OrderBy>
|
|
31
33
|
start?: number
|
|
32
34
|
limit?: number
|
|
33
35
|
groupBy?: Field
|
|
@@ -44,7 +46,4 @@ export interface UseListOptions<T> {
|
|
|
44
46
|
onError?: (error: Error) => void
|
|
45
47
|
}
|
|
46
48
|
|
|
47
|
-
export
|
|
48
|
-
result: T[]
|
|
49
|
-
has_next_page: boolean
|
|
50
|
-
}
|
|
49
|
+
export type UseListResponse<T> = T[]
|
|
@@ -27,7 +27,7 @@ describe('useList', () => {
|
|
|
27
27
|
// Verify initial state
|
|
28
28
|
expect(users.data).toBe(null)
|
|
29
29
|
expect(users.error).toBe(null)
|
|
30
|
-
expect(users.hasNextPage).toBe(
|
|
30
|
+
expect(users.hasNextPage).toBe(true)
|
|
31
31
|
expect(typeof users.fetch).toBe('function')
|
|
32
32
|
|
|
33
33
|
// fetch
|
|
@@ -46,11 +46,12 @@ export function useList<T extends { name: string }>(
|
|
|
46
46
|
const _limit = ref(limit || 20)
|
|
47
47
|
|
|
48
48
|
const _url = computed(() => {
|
|
49
|
-
const parsedFilters = parseFilters(filters
|
|
49
|
+
const parsedFilters = parseFilters(filters ? toValue(filters) : {})
|
|
50
|
+
const _fields = fields ? toValue(fields) : []
|
|
50
51
|
const params = makeGetParams({
|
|
51
|
-
fields:
|
|
52
|
+
fields: _fields.length ? JSON.stringify(_fields) : null,
|
|
52
53
|
filters: parsedFilters ? JSON.stringify(parsedFilters) : null,
|
|
53
|
-
order_by: orderBy,
|
|
54
|
+
order_by: toValue(orderBy),
|
|
54
55
|
start: _start.value,
|
|
55
56
|
limit: _limit.value,
|
|
56
57
|
group_by: groupBy,
|
|
@@ -64,14 +65,20 @@ export function useList<T extends { name: string }>(
|
|
|
64
65
|
})
|
|
65
66
|
|
|
66
67
|
const allData: Ref<T[] | null> = ref(null)
|
|
68
|
+
const hasNextPage = ref(true)
|
|
69
|
+
const hasPreviousPage = computed(() => _start.value > 0)
|
|
67
70
|
|
|
68
71
|
const fetchOptions: UseFetchOptions = {
|
|
69
72
|
immediate,
|
|
70
73
|
refetch,
|
|
71
|
-
initialData: initialData
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
74
|
+
initialData: initialData || null,
|
|
75
|
+
afterFetch: handleAfterFetch<T>({
|
|
76
|
+
...options,
|
|
77
|
+
allData,
|
|
78
|
+
_start,
|
|
79
|
+
_limit,
|
|
80
|
+
hasNextPage,
|
|
81
|
+
}),
|
|
75
82
|
onFetchError: handleFetchError<T>(options),
|
|
76
83
|
}
|
|
77
84
|
|
|
@@ -94,24 +101,16 @@ export function useList<T extends { name: string }>(
|
|
|
94
101
|
let data = cachedResponse.value
|
|
95
102
|
if (data) {
|
|
96
103
|
if (transform) {
|
|
97
|
-
let returnValue = transform(data
|
|
104
|
+
let returnValue = transform(data as T[])
|
|
98
105
|
if (returnValue !== undefined) {
|
|
99
106
|
return returnValue
|
|
100
107
|
}
|
|
101
108
|
}
|
|
102
|
-
return data
|
|
109
|
+
return data
|
|
103
110
|
}
|
|
104
111
|
}
|
|
105
112
|
return allData.value
|
|
106
113
|
})
|
|
107
|
-
const hasNextPage = computed(() => {
|
|
108
|
-
if (normalizedCacheKey && (out.loading || !out.isFinished)) {
|
|
109
|
-
let data = cachedResponse.value
|
|
110
|
-
return data?.has_next_page ?? false
|
|
111
|
-
}
|
|
112
|
-
return data.value?.has_next_page ?? false
|
|
113
|
-
})
|
|
114
|
-
const hasPreviousPage = computed(() => _start.value > 0)
|
|
115
114
|
|
|
116
115
|
if (normalizedCacheKey) {
|
|
117
116
|
idbStore.get(normalizedCacheKey).then((data) => {
|
|
@@ -247,7 +246,7 @@ export function useList<T extends { name: string }>(
|
|
|
247
246
|
|
|
248
247
|
let out = reactive({
|
|
249
248
|
data: result,
|
|
250
|
-
hasNextPage,
|
|
249
|
+
hasNextPage: readonly(hasNextPage),
|
|
251
250
|
hasPreviousPage,
|
|
252
251
|
start: readonly(_start),
|
|
253
252
|
limit: readonly(_limit),
|
|
@@ -283,15 +282,24 @@ function handleAfterFetch<T extends { name: string }>({
|
|
|
283
282
|
cacheKey,
|
|
284
283
|
allData,
|
|
285
284
|
_start,
|
|
285
|
+
_limit,
|
|
286
|
+
hasNextPage,
|
|
286
287
|
}: UseListOptions<T> & {
|
|
287
288
|
allData: Ref<T[] | null>
|
|
288
289
|
_start: Ref<number>
|
|
290
|
+
_limit: Ref<number>
|
|
291
|
+
hasNextPage: Ref<boolean>
|
|
289
292
|
}) {
|
|
290
293
|
return function (ctx: AfterFetchContext) {
|
|
291
|
-
let resultData =
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
294
|
+
let resultData = ctx.data
|
|
295
|
+
if (resultData[0]?.name) {
|
|
296
|
+
resultData = resultData.map((item) => ({
|
|
297
|
+
...item,
|
|
298
|
+
name: String(item.name),
|
|
299
|
+
}))
|
|
300
|
+
}
|
|
301
|
+
hasNextPage.value = resultData.length < _limit.value ? false : true
|
|
302
|
+
|
|
295
303
|
if (transform) {
|
|
296
304
|
const returnValue = transform(resultData)
|
|
297
305
|
if (Array.isArray(returnValue)) {
|
|
@@ -300,11 +308,11 @@ function handleAfterFetch<T extends { name: string }>({
|
|
|
300
308
|
}
|
|
301
309
|
|
|
302
310
|
if (_start.value === 0) {
|
|
303
|
-
allData.value = resultData
|
|
311
|
+
allData.value = resultData as T[]
|
|
304
312
|
} else {
|
|
305
313
|
allData.value = [...(allData.value || []), ...resultData]
|
|
306
314
|
}
|
|
307
|
-
ctx.data
|
|
315
|
+
ctx.data = allData.value
|
|
308
316
|
|
|
309
317
|
let normalizedCacheKey = normalizeCacheKey(cacheKey, 'useList')
|
|
310
318
|
if (normalizedCacheKey) {
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { reactive, unref } from 'vue'
|
|
2
2
|
import { useCall } from '../useCall/useCall'
|
|
3
3
|
import { UseCallOptions } from '../useCall/types'
|
|
4
|
+
import { docStore } from '../docStore'
|
|
4
5
|
|
|
5
6
|
type UseNewDocOptions = Omit<
|
|
6
7
|
UseCallOptions,
|
|
@@ -18,7 +19,11 @@ export function useNewDoc<T extends object>(
|
|
|
18
19
|
) {
|
|
19
20
|
let doc = reactive<NewDoc<T>>(initialValues)
|
|
20
21
|
|
|
21
|
-
|
|
22
|
+
type DocResponse = T & {
|
|
23
|
+
name: string
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
const out = useCall<DocResponse>({
|
|
22
27
|
url: `/api/v2/document/${doctype}`,
|
|
23
28
|
method: 'POST',
|
|
24
29
|
params() {
|
|
@@ -34,8 +39,19 @@ export function useNewDoc<T extends object>(
|
|
|
34
39
|
...options,
|
|
35
40
|
})
|
|
36
41
|
|
|
42
|
+
function submit() {
|
|
43
|
+
return out
|
|
44
|
+
.submit()
|
|
45
|
+
.then((doc) =>
|
|
46
|
+
docStore
|
|
47
|
+
.setDoc({ doctype, ...(doc as DocResponse) })
|
|
48
|
+
.then(() => docStore.getDoc(doctype, doc.name.toString()).value as T),
|
|
49
|
+
)
|
|
50
|
+
}
|
|
51
|
+
|
|
37
52
|
return reactive({
|
|
38
53
|
...out,
|
|
54
|
+
submit,
|
|
39
55
|
doc,
|
|
40
56
|
})
|
|
41
57
|
}
|