1
1
<template >
2
- <div >
3
- <div v-if =" !typeName" >
4
- <p class =" text-red-700" >Could not create view for unknown <b >type</b > {{ typeName }}</p >
5
- </div >
6
- <div v-else-if =" formStyle=='card'" :class =" panelClass" >
7
- <div :class =" formClass" >
8
- <div >
9
- <div v-if =" $slots['heading']" ><slot name =" heading" ></slot ></div >
10
- <h3 v-else :class =" headingClass" >{{ title }}</h3 >
11
-
12
- <div v-if =" $slots['subheading']" ><slot name =" subheading" ></slot ></div >
13
- <p v-else-if =" subHeading" :class =" subHeadingClass" >{{ subHeading }}</p >
14
- <p v-else-if =" metaType?.notes" :class =" ['notes',subHeadingClass]" v-html =" metaType?.notes" ></p >
15
- </div >
16
- <MarkupModel :value =" model" />
2
+ <div >
3
+ <div v-if =" !typeName" >
4
+ <p class =" text-red-700" >Could not create view for unknown <b >type</b > {{ typeName }}</p >
5
+ </div >
6
+ <div v-else-if =" formStyle=='card'" :class =" panelClass" >
7
+ <div :class =" formClass" >
8
+ <div >
9
+ <div v-if =" $slots['heading']" ><slot name =" heading" ></slot ></div >
10
+ <h3 v-else :class =" headingClass" >{{ title }}</h3 >
11
+
12
+ <div v-if =" $slots['subheading']" ><slot name =" subheading" ></slot ></div >
13
+ <p v-else-if =" subHeading" :class =" subHeadingClass" >{{ subHeading }}</p >
14
+ <p v-else-if =" metaType?.notes" :class =" ['notes',subHeadingClass]" v-html =" metaType?.notes" ></p >
17
15
</div >
16
+ <MarkupModel :value =" model" />
18
17
</div >
19
- <div v-else class =" relative z-10" aria-labelledby =" slide-over-title" role =" dialog" aria-modal =" true" >
20
- <div class =" fixed inset-0" ></div >
21
- <div class =" fixed inset-0 overflow-hidden" >
22
- <div @mousedown =" close" class =" absolute inset-0 overflow-hidden" >
23
- <div @mousedown.stop =" " class =" pointer-events-none fixed inset-y-0 right-0 flex pl-10" >
24
- <div :class =" ['pointer-events-auto w-screen xl:max-w-3xl md:max-w-xl max-w-lg',transition1]" >
25
- <div :class =" formClass" >
26
- <div class =" flex min-h-0 flex-1 flex-col overflow-auto" >
27
- <div class =" flex-1" >
28
- <!-- Header -->
29
- <div class =" bg-gray-50 dark:bg-gray-900 px-4 py-6 sm:px-6" >
30
- <div class =" flex items-start justify-between space-x-3" >
31
- <div class =" space-y-1" >
32
- <div v-if =" $slots['heading']" ><slot name =" heading" ></slot ></div >
33
- <h3 v-else :class =" headingClass" >{{ title }}</h3 >
34
-
35
- <div v-if =" $slots['subheading']" ><slot name =" subheading" ></slot ></div >
36
- <p v-else-if =" subHeading" :class =" subHeadingClass" >{{ subHeading }}</p >
37
- <p v-else-if =" metaType?.notes" :class =" ['notes',subHeadingClass]" v-html =" metaType?.notes" ></p >
38
- </div >
39
- <div class =" flex h-7 items-center" >
40
- <CloseButton button-class =" bg-gray-50 dark:bg-gray-900" @close =" close" />
41
- </div >
18
+ </div >
19
+ <div v-else class =" relative z-10" aria-labelledby =" slide-over-title" role =" dialog" aria-modal =" true" >
20
+ <div class =" fixed inset-0" ></div >
21
+ <div class =" fixed inset-0 overflow-hidden" >
22
+ <div @mousedown =" close" class =" absolute inset-0 overflow-hidden" >
23
+ <div @mousedown.stop =" " class =" pointer-events-none fixed inset-y-0 right-0 flex pl-10" >
24
+ <div :class =" ['pointer-events-auto w-screen xl:max-w-3xl md:max-w-xl max-w-lg',transition1]" >
25
+ <div :class =" formClass" >
26
+ <div class =" flex min-h-0 flex-1 flex-col overflow-auto" >
27
+ <div class =" flex-1" >
28
+ <!-- Header -->
29
+ <div class =" bg-gray-50 dark:bg-gray-900 px-4 py-6 sm:px-6" >
30
+ <div class =" flex items-start justify-between space-x-3" >
31
+ <div class =" space-y-1" >
32
+ <div v-if =" $slots['heading']" ><slot name =" heading" ></slot ></div >
33
+ <h3 v-else :class =" headingClass" >{{ title }}</h3 >
34
+
35
+ <div v-if =" $slots['subheading']" ><slot name =" subheading" ></slot ></div >
36
+ <p v-else-if =" subHeading" :class =" subHeadingClass" >{{ subHeading }}</p >
37
+ <p v-else-if =" metaType?.notes" :class =" ['notes',subHeadingClass]" v-html =" metaType?.notes" ></p >
42
38
</div >
43
- </div >
44
- <MarkupModel :value =" model" />
45
- </div >
39
+ <div class =" flex h-7 items-center" >
40
+ <CloseButton button-class =" bg-gray-50 dark:bg-gray-900" @close =" close" />
41
+ </div >
42
+ </div >
43
+ </div >
44
+ <MarkupModel :value =" model" />
46
45
</div >
47
46
</div >
47
+ <div :class =" form.buttonsClass" >
48
+ <div >
49
+ <ConfirmDelete v-if =" deleteType" @delete =" onDelete" />
50
+ </div >
51
+ <div >
52
+ <FormLoading v-if =" showLoading && loading" />
53
+ </div >
54
+ <div class =" flex justify-end" ></div >
55
+ </div >
48
56
</div >
49
57
</div >
50
58
</div >
51
59
</div >
52
60
</div >
53
61
</div >
54
- </template >
55
-
56
- <script setup lang="ts">
57
- import { useMetadata , Apis } from ' @/use/metadata'
58
- import { form } from ' ./css'
59
- import { computed , onMounted , onUnmounted , ref , watch } from ' vue'
60
- import { transition } from ' @/use/utils'
61
- import { Sole } from ' @/use/config'
62
- import { humanize } from ' @servicestack/client'
63
-
64
- const props = withDefaults (defineProps <{
65
- model: any
66
- apis? : Apis ,
67
- typeName? : string ,
68
- done? : Function ,
69
- formStyle? : " slideOver" | " card"
70
- panelClass? : string
71
- formClass? : string
72
- headingClass? : string
73
- subHeadingClass? : string
74
- heading? : string
75
- subHeading? : string
76
- }>(), {
77
- formStyle: " slideOver" ,
78
- })
79
-
80
- const emit = defineEmits <{
81
- (e : ' done' ): void
82
- }>()
83
-
84
- const { typeOf } = useMetadata ()
85
-
86
- const typeName = computed (() => props .typeName ?? props .apis ! .dataModel ! .name )
87
- const metaType = computed (() => typeOf (typeName .value ))
88
- const panelClass = computed (() => props .panelClass || form .panelClass (props .formStyle ))
89
- const formClass = computed (() => props .formClass || form .formClass (props .formStyle ))
90
- const headingClass = computed (() => props .headingClass || form .headingClass (props .formStyle ))
91
- const subHeadingClass = computed (() => props .subHeadingClass || form .subHeadingClass (props .formStyle ))
92
-
93
- const title = computed (() => props .heading || typeOf (typeName .value )?.description ||
94
- (props .model ?.id ? ` ${humanize (typeName .value )} ${props .model .id } ` : ' View ' + humanize (typeName .value )))
95
-
96
- if (Sole .interceptors .has (' AutoViewForm.new' )) Sole .interceptors .invoke (' AutoViewForm.new' , { props })
97
-
98
- function done() {
99
- if (props .done ) {
100
- props .done ()
101
- }
62
+ </div >
63
+ </template >
64
+
65
+ <script setup lang="ts">
66
+ import type { ApiResponse , ResponseStatus } from ' @/types'
67
+ import { useMetadata , toFormValues , Apis } from ' @/use/metadata'
68
+ import { form } from ' ./css'
69
+ import { computed , onMounted , onUnmounted , ref , watch } from ' vue'
70
+ import { transition } from ' @/use/utils'
71
+ import { Sole } from ' @/use/config'
72
+ import { useClient } from ' @/use/client'
73
+ import { ApiResult , humanize , map , mapGet } from ' @servicestack/client'
74
+
75
+ const props = withDefaults (defineProps <{
76
+ model: any
77
+ apis? : Apis ,
78
+ typeName? : string ,
79
+ done? : Function ,
80
+ formStyle? : " slideOver" | " card"
81
+ panelClass? : string
82
+ formClass? : string
83
+ headingClass? : string
84
+ subHeadingClass? : string
85
+ heading? : string
86
+ subHeading? : string
87
+ showLoading? : boolean
88
+ deleteType? : string | InstanceType <any >| Function
89
+ }>(), {
90
+ formStyle: " slideOver" ,
91
+ })
92
+
93
+ const emit = defineEmits <{
94
+ (e : ' done' ): void
95
+ (e : ' save' , response : any ): () => void
96
+ (e : ' delete' , response : any ): () => void
97
+ (e : ' error' , status : ResponseStatus ): void
98
+ }>()
99
+
100
+ const { typeOf, getPrimaryKey, Crud, createDto } = useMetadata ()
101
+
102
+ const typeName = computed (() => props .typeName ?? props .apis ! .dataModel ! .name )
103
+ const metaType = computed (() => typeOf (typeName .value ))
104
+ const panelClass = computed (() => props .panelClass || form .panelClass (props .formStyle ))
105
+ const formClass = computed (() => props .formClass || form .formClass (props .formStyle ))
106
+ const headingClass = computed (() => props .headingClass || form .headingClass (props .formStyle ))
107
+ const subHeadingClass = computed (() => props .subHeadingClass || form .subHeadingClass (props .formStyle ))
108
+
109
+ const title = computed (() => props .heading || typeOf (typeName .value )?.description ||
110
+ (props .model ?.id ? ` ${humanize (typeName .value )} ${props .model .id } ` : ' View ' + humanize (typeName .value )))
111
+
112
+ const api = ref <ApiResponse >(new ApiResult <any >())
113
+ let origModel = Object .assign ({}, toFormValues (props .model ))
114
+ if (Sole .interceptors .has (' AutoViewForm.new' )) Sole .interceptors .invoke (' AutoViewForm.new' , { props })
115
+
116
+ let client = useClient ()
117
+ let loading = computed (() => client .loading .value )
118
+ const getPk = () => map (metaType .value , dataModel => getPrimaryKey (dataModel ))
119
+ const dataModel = computed (() => metaType .value )
120
+
121
+ async function onDelete(e : Event ) {
122
+ let pk = getPk ()
123
+ const id = pk ? mapGet (props .model , pk .name ) : null
124
+ if (! id ) {
125
+ console .error (` Could not find Primary Key for Type ${typeName .value } (${dataModel .value }) ` )
126
+ return
102
127
}
103
-
104
- /* SlideOver */
105
- const show = ref (false )
106
- const transition1 = ref (' ' )
107
- const rule1 = {
108
- entering: { cls: ' transform transition ease-in-out duration-500 sm:duration-700' , from: ' translate-x-full' , to: ' translate-x-0' },
109
- leaving: { cls: ' transform transition ease-in-out duration-500 sm:duration-700' , from: ' translate-x-0' , to: ' translate-x-full' }
128
+ const args = { [pk ! .name ]: id }
129
+ const request = typeof props .deleteType == ' string'
130
+ ? createDto (props .deleteType , args )
131
+ : (props .deleteType ? new props .deleteType (args ) : null )
132
+
133
+ let returnsVoid = map (request [' createResponse' ], fn => typeof fn == ' function' ? fn () : null ) == null
134
+ if (! returnsVoid ) {
135
+ api .value = await client .api (request )
136
+ } else {
137
+ api .value = await client .apiVoid (request )
110
138
}
111
- watch (show , () => {
112
- transition (rule1 , transition1 , show .value )
113
- if (! show .value ) setTimeout (done , 700 )
114
- })
115
- show .value = true
116
- function close() {
117
- if (props .formStyle == ' slideOver' ) {
118
- show .value = false
119
- } else {
120
- done ()
121
- }
139
+
140
+ if (api .value .succeeded ) {
141
+ emit (' delete' , api .value .response )
142
+ } else {
143
+ emit (' error' , api .value .error ! )
122
144
}
145
+ }
123
146
124
- const globalKeyHandler = (e : KeyboardEvent ) => { if (e .key === ' Escape' ) close () }
125
- onMounted (() => window .addEventListener (' keydown' , globalKeyHandler ))
126
- onUnmounted (() => window .removeEventListener (' keydown' , globalKeyHandler ))
127
- </script >
147
+ function done() {
148
+ if (props .done ) {
149
+ props .done ()
150
+ }
151
+ }
152
+
153
+ /* SlideOver */
154
+ const show = ref (false )
155
+ const transition1 = ref (' ' )
156
+ const rule1 = {
157
+ entering: { cls: ' transform transition ease-in-out duration-500 sm:duration-700' , from: ' translate-x-full' , to: ' translate-x-0' },
158
+ leaving: { cls: ' transform transition ease-in-out duration-500 sm:duration-700' , from: ' translate-x-0' , to: ' translate-x-full' }
159
+ }
160
+ watch (show , () => {
161
+ transition (rule1 , transition1 , show .value )
162
+ if (! show .value ) setTimeout (done , 700 )
163
+ })
164
+ show .value = true
165
+ function close() {
166
+ if (props .formStyle == ' slideOver' ) {
167
+ show .value = false
168
+ } else {
169
+ done ()
170
+ }
171
+ }
172
+
173
+ const globalKeyHandler = (e : KeyboardEvent ) => { if (e .key === ' Escape' ) close () }
174
+ onMounted (() => window .addEventListener (' keydown' , globalKeyHandler ))
175
+ onUnmounted (() => window .removeEventListener (' keydown' , globalKeyHandler ))
176
+ </script >
0 commit comments