Skip to content

Commit bbb98ab

Browse files
authored
form, validation, relationships and authorization (#20)
* feat: refactor form system and setup validation * test: remove legacy tests * chore: changeset * feat: manage relationships * refactor: rename cockpit variables to admin * feat: authentication system * feat: always show logout button * fix: fix useForm type issue
1 parent b16f91e commit bbb98ab

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

82 files changed

+950
-860
lines changed

.changeset/brown-chicken-cover.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
'adonis-cockpit': patch
3+
---
4+
5+
Rename admin variables to cockpit

.changeset/cold-lions-relax.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
'adonis-cockpit': minor
3+
---
4+
5+
Frontend relationship management

.changeset/curvy-jeans-flow.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
'adonis-cockpit': minor
3+
---
4+
5+
Authentication system

.changeset/quiet-clocks-obey.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
'adonis-cockpit': minor
3+
---
4+
5+
Implementation of the validation system

.changeset/red-papayas-cross.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
'adonis-cockpit': patch
3+
---
4+
5+
Refactoring of the frontend code

package.json

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,7 @@
4949
"license": "MIT",
5050
"devDependencies": {
5151
"@adonisjs/assembler": "^7.7.0",
52+
"@adonisjs/auth": "^9.2.3",
5253
"@adonisjs/bouncer": "^3.1.3",
5354
"@adonisjs/core": "^6.12.0",
5455
"@adonisjs/eslint-config": "^2.0.0-beta.7",
@@ -128,6 +129,7 @@
128129
"tailwindcss-primeui": "^0.3.4",
129130
"ts-morph": "^23.0.0",
130131
"unplugin-vue-components": "^0.27.4",
132+
"vee-validate": "^4.13.2",
131133
"vue": "^3.5.10"
132134
}
133135
}
Lines changed: 32 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,43 +1,61 @@
11
<script setup lang="ts">
2-
import type { InferSerializable } from '../../../../src/types'
32
import type BelongsTo from '../../../../src/fields/belongs_to'
4-
import { ref } from 'vue'
3+
import { computed, ref, toValue } from 'vue'
54
import { useResourceApi } from '../../../composables/resource'
65
import Select from 'primevue/select'
6+
import { useField } from '../../../composables/field'
7+
import InputText from 'primevue/inputtext'
8+
import { useFormValues } from 'vee-validate'
9+
import { useSearchParams } from '../../../composables/route'
10+
import { ViaRelationship } from '../../../types'
711
812
defineOptions({
913
inheritAttrs: false,
1014
})
1115
12-
const props = defineProps<{
13-
error?: string[]
14-
field: InferSerializable<BelongsTo>
15-
record: any
16-
}>()
17-
1816
const filter = ref('')
19-
const model = defineModel()
17+
const params = useSearchParams<{ via?: ViaRelationship }>()
18+
const record = useFormValues()
19+
const { field, name, value, errorMessage, setValue, handleBlur } = useField<BelongsTo>()
20+
const { data, isLoading } = useResourceApi.list(field.resource.slug, { search: filter })
21+
22+
const options = computed(() => {
23+
// TODO: This might not be really performant
24+
const options = data.value ? [...data.value.data] : []
25+
if (!options.some((r) => r[field.resource.idKey] === value.value)) {
26+
options.unshift(record.value[field.relationship.relationName])
27+
}
28+
return options
29+
})
30+
31+
const isVia = params.via?.foreignKey === toValue(name)
2032
21-
const { data, isLoading } = useResourceApi.list(props.field.resource.slug, { search: filter })
33+
if (isVia) {
34+
setValue(params.via?.value)
35+
}
2236
</script>
2337

2438
<template>
2539
<div class="flex flex-col gap-2">
2640
<Select
27-
v-model="model"
28-
:options="data?.data ?? []"
41+
:id="name"
42+
:name="name"
43+
v-model="value"
44+
:options="options"
2945
:loading="isLoading"
3046
:option-label="field.resource.titleKey"
3147
:option-value="field.resource.idKey"
32-
:placeholder="`Select ${field.resource.name}`"
48+
:placeholder="`Select ${field.resource.label}`"
49+
:disabled="isVia"
3350
v-bind="field.attributes"
51+
@blur="handleBlur"
3452
>
3553
<template #header>
3654
<div class="p-2">
3755
<InputText class="w-full" v-model="filter" />
3856
</div>
3957
</template>
4058
</Select>
41-
<small class="text-red-400" v-if="error">{{ error.join('\n') }}</small>
59+
<errorMessage />
4260
</div>
4361
</template>

resources/components/fields/belongs_to/index.vue

Lines changed: 9 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -7,15 +7,16 @@ import { useResourceQuery } from '../../../composables/resource'
77
import { injectResources } from '../../../composables/resources'
88
import Popover from 'primevue/popover'
99
import Button from 'primevue/button'
10+
import { ResourceRecord } from '../../../types'
1011
1112
defineOptions({
1213
inheritAttrs: false,
1314
})
1415
1516
const props = defineProps<{
1617
field: InferSerializable<BelongsTo>
18+
record: ResourceRecord
1719
value: any
18-
record: any
1920
}>()
2021
2122
const opened = ref(false)
@@ -30,12 +31,14 @@ function toggle(event: Event) {
3031
}
3132
3233
const relation = props.record[props.field.relationship.relationName]
33-
const label = relation[props.field.resource.titleKey] ?? props.value
34+
const label = relation ? (relation[props.field.resource.titleKey] ?? props.value) : ''
3435
</script>
3536

3637
<template>
37-
<Button @click="toggle" size="small" text :label="label" severity="info" />
38-
<Popover ref="popover" class="px-2">
39-
<ResourcePeek v-if="data" :resource="resources[field.resource.name]" :data="data" />
40-
</Popover>
38+
<div v-if="value">
39+
<Button @click="toggle" size="small" text :label="label" severity="info" />
40+
<Popover ref="popover" class="px-2">
41+
<ResourcePeek v-if="data" :resource="resources[field.resource.name]" :record="data" />
42+
</Popover>
43+
</div>
4144
</template>
Lines changed: 10 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,30 +1,27 @@
11
<script setup lang="ts">
2-
import ToggleSwitch from 'primevue/toggleswitch'
32
import type Boolean from '../../../../src/fields/boolean'
4-
import type { InferSerializable } from '../../../../src/types'
3+
import ToggleSwitch from 'primevue/toggleswitch'
4+
import FormMessage from '../../form/form-message.vue'
5+
import { useField } from '../../../composables/field'
56
67
defineOptions({
78
inheritAttrs: false,
89
})
910
10-
defineProps<{
11-
error?: string[]
12-
field: InferSerializable<Boolean>
13-
record: any
14-
}>()
15-
16-
const model = defineModel<string | boolean | undefined>()
11+
const { field, name, value, errorMessage, handleBlur } = useField<Boolean>()
1712
</script>
1813

1914
<template>
2015
<div class="flex flex-col gap-2">
2116
<ToggleSwitch
22-
v-model="model"
17+
:id="name"
18+
:input-id="field.name"
2319
:true-value="field.trueValue"
2420
:false-value="field.falseValue"
25-
:input-id="field.name"
26-
:invalid="!!error?.length"
21+
:invalid="!!errorMessage"
22+
v-model="value"
23+
@blur="handleBlur"
2724
/>
28-
<small class="text-red-400" v-if="error">{{ error.join('\n') }}</small>
25+
<FormMessage />
2926
</div>
3027
</template>
Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
<script setup lang="ts">
2+
import type { ResourceRecord, InferSerializable } from '../../../types'
3+
import type HasMany from '../../../../src/fields/has_many'
4+
import ResourceTable from '../../resource-table.vue'
5+
import Heading from '../../ui/heading.vue'
6+
import ProvideResource from '../../resource/provide-resource.vue'
7+
8+
defineOptions({
9+
inheritAttrs: false,
10+
})
11+
12+
const props = defineProps<{
13+
field: InferSerializable<HasMany>
14+
record: ResourceRecord
15+
}>()
16+
17+
const resource = props.field.resource
18+
</script>
19+
20+
<template>
21+
<ProvideResource :resource="resource">
22+
<div class="flex flex-col gap-2">
23+
<ResourceTable
24+
:resource="field.resource"
25+
:additional-filters="[
26+
{ field: field.relationship.foreignKey, value: record[resource.idKey] },
27+
]"
28+
:via="{
29+
resource: resource.name,
30+
foreignKey: field.relationship.foreignKey,
31+
value: record[resource.idKey],
32+
}"
33+
>
34+
<template #title>
35+
<Heading variant="h2">{{ field.resource.labelPlural }}</Heading>
36+
</template>
37+
</ResourceTable>
38+
</div>
39+
</ProvideResource>
40+
</template>

0 commit comments

Comments
 (0)