From 24821fde6e1acf9f53842ac6cc76df769923bc99 Mon Sep 17 00:00:00 2001
From: Axel Rindle
Date: Wed, 4 Mar 2026 21:55:06 +0100
Subject: [PATCH 1/5] feat: custom field ordering
---
.../migration.sql | 2 +
apps/api/prisma/schema/CustomField.prisma | 1 +
.../customFields/customFields.router.ts | 6 +-
.../services/customFields/customFieldsList.ts | 73 +++++---
.../customFields/schema/customField.schema.ts | 26 ++-
.../customFieldsUnterveranstaltungOrder.ts | 54 ++++++
.../schema/customFieldsVeranstaltungOrder.ts | 44 +++++
.../CustomFields/CustomFieldsTable.vue | 13 ++
.../CustomFieldUnterveranstaltungOrder.vue | 168 ++++++++++++++++++
.../UnterveranstaltungDetail.vue | 11 ++
.../src/views/Unterveranstaltung/routes.ts | 13 ++
.../CustomFieldVeranstaltungOrder.vue | 126 +++++++++++++
.../Veranstaltungen/VeranstaltungDetail.vue | 26 ++-
.../Verwaltung/Veranstaltungen/routes.ts | 13 ++
14 files changed, 536 insertions(+), 40 deletions(-)
create mode 100644 apps/api/prisma/migrations/20260304182124_custom_field_order/migration.sql
create mode 100644 apps/api/src/services/customFields/schema/customFieldsUnterveranstaltungOrder.ts
create mode 100644 apps/api/src/services/customFields/schema/customFieldsVeranstaltungOrder.ts
create mode 100644 apps/frontend/src/views/Unterveranstaltung/CustomFields/CustomFieldUnterveranstaltungOrder.vue
create mode 100644 apps/frontend/src/views/Verwaltung/Veranstaltungen/CustomFields/CustomFieldVeranstaltungOrder.vue
diff --git a/apps/api/prisma/migrations/20260304182124_custom_field_order/migration.sql b/apps/api/prisma/migrations/20260304182124_custom_field_order/migration.sql
new file mode 100644
index 00000000..79c1d2b8
--- /dev/null
+++ b/apps/api/prisma/migrations/20260304182124_custom_field_order/migration.sql
@@ -0,0 +1,2 @@
+-- AlterTable
+ALTER TABLE "CustomField" ADD COLUMN "order" INTEGER;
diff --git a/apps/api/prisma/schema/CustomField.prisma b/apps/api/prisma/schema/CustomField.prisma
index 0a1415df..ac05f0a7 100644
--- a/apps/api/prisma/schema/CustomField.prisma
+++ b/apps/api/prisma/schema/CustomField.prisma
@@ -19,6 +19,7 @@ model CustomField {
id String @id @default(uuid(7))
name String
description String?
+ order Int?
type CustomFieldType
required Boolean @default(false)
options String[]
diff --git a/apps/api/src/services/customFields/customFields.router.ts b/apps/api/src/services/customFields/customFields.router.ts
index 3e38d8cc..5f861fa8 100644
--- a/apps/api/src/services/customFields/customFields.router.ts
+++ b/apps/api/src/services/customFields/customFields.router.ts
@@ -9,6 +9,8 @@ import { customFieldsVeranstaltungCreate } from './customFieldsVeranstaltungCrea
import { customFieldsVeranstaltungDelete, customFieldsUnterveranstaltungDelete } from './customFieldsDelete.js'
import { customFieldsUpdate } from './customFieldsUpdate.js'
import { customFieldValuesUpdate } from './customFieldValuesUpdate.js'
+import { customFieldUnterveranstaltungOrder } from './schema/customFieldsUnterveranstaltungOrder.js'
+import { customFieldVeranstaltungOrder } from './schema/customFieldsVeranstaltungOrder.js'
// Import Routes here - do not delete this line
export const customFieldsRouter = mergeRouters(
@@ -21,6 +23,8 @@ export const customFieldsRouter = mergeRouters(
customFieldsUnterveranstaltungDelete,
customFieldsUnterveranstaltungCreate,
customFieldValuesUpdate,
- customFieldsTemplates
+ customFieldsTemplates,
+ customFieldVeranstaltungOrder,
+ customFieldUnterveranstaltungOrder
// Add Routes here - do not delete this line
)
diff --git a/apps/api/src/services/customFields/customFieldsList.ts b/apps/api/src/services/customFields/customFieldsList.ts
index f7d9a09c..35fbd0f9 100644
--- a/apps/api/src/services/customFields/customFieldsList.ts
+++ b/apps/api/src/services/customFields/customFieldsList.ts
@@ -2,7 +2,7 @@ import { z } from 'zod'
import { CustomFieldPosition, CustomFieldType, Prisma } from '@prisma/client'
import prisma from '../../prisma.js'
-import { definePublicQueryProcedure } from '../../types/defineProcedure.js'
+import { defineProtectedQueryProcedure, definePublicQueryProcedure } from '../../types/defineProcedure.js'
import {
calculatePagination,
defineEmptyQueryResponse,
@@ -10,6 +10,7 @@ import {
defineTableInput,
} from '../../types/defineTableProcedure.js'
import { boolish } from '../../util/zod.js'
+import { getGliederungRequireAdmin } from '../../util/getGliederungRequireAdmin.js'
const baseFilter = z.strictObject({
entity: z.enum(['veranstaltung', 'unterveranstaltung']),
@@ -23,6 +24,7 @@ export const customFieldsTable = definePublicQueryProcedure({
async handler({ input: { entity, entityId, position } }) {
if (entity === 'veranstaltung') {
return await prisma.customField.findMany({
+ orderBy: [{ order: { sort: 'asc', nulls: 'last' } }],
where: {
veranstaltungId: entityId,
positions:
@@ -35,6 +37,14 @@ export const customFieldsTable = definePublicQueryProcedure({
})
} else if (entity === 'unterveranstaltung') {
return await prisma.customField.findMany({
+ orderBy: [
+ {
+ unterveranstaltungId: { sort: 'asc', nulls: 'first' },
+ },
+ {
+ order: { sort: 'asc', nulls: 'last' },
+ },
+ ],
where: {
positions:
position === undefined
@@ -64,8 +74,9 @@ export const customFieldsTable = definePublicQueryProcedure({
},
})
-export const customFieldsList = definePublicQueryProcedure({
+export const customFieldsList = defineProtectedQueryProcedure({
key: 'table',
+ roleIds: ['ADMIN', 'GLIEDERUNG_ADMIN'],
inputSchema: baseFilter.extend({
table: defineTableInput({
filter: {
@@ -74,10 +85,14 @@ export const customFieldsList = definePublicQueryProcedure({
required: boolish,
position: z.nativeEnum(CustomFieldPosition),
},
- orderBy: ['name'],
+ orderBy: ['name', 'order'],
}),
}),
- async handler({ input }) {
+ async handler({ ctx, input }) {
+ if (ctx.account.role === 'GLIEDERUNG_ADMIN') {
+ await getGliederungRequireAdmin(ctx.accountId)
+ }
+
const where: Prisma.CustomFieldWhereInput = {
name: {
contains: input.table?.filter?.name,
@@ -93,6 +108,25 @@ export const customFieldsList = definePublicQueryProcedure({
},
}
+ if (input.entity === 'veranstaltung') {
+ where.veranstaltungId = input.entityId
+ } else if (input.entity === 'unterveranstaltung') {
+ where.OR = [
+ {
+ unterveranstaltungId: input.entityId,
+ },
+ {
+ veranstaltung: {
+ unterveranstaltungen: {
+ some: {
+ id: input.entityId,
+ },
+ },
+ },
+ },
+ ]
+ }
+
const total = await prisma.customField.count({ where })
const { pageIndex, pageSize, pages } = calculatePagination(total, input.table?.pagination)
@@ -100,15 +134,13 @@ export const customFieldsList = definePublicQueryProcedure({
const customFields = await prisma.customField.findMany({
take: pageSize,
skip: pageSize * pageIndex,
- where: {
- ...where,
- veranstaltungId: input.entityId,
- },
+ where,
orderBy: input.table?.orderBy,
select: {
id: true,
name: true,
description: true,
+ order: true,
type: true,
positions: true,
required: true,
@@ -122,27 +154,18 @@ export const customFieldsList = definePublicQueryProcedure({
const customFields = await prisma.customField.findMany({
take: pageSize,
skip: pageSize * pageIndex,
- where: {
- ...where,
- OR: [
- {
- unterveranstaltungId: input.entityId,
- },
- {
- veranstaltung: {
- unterveranstaltungen: {
- some: {
- id: input.entityId,
- },
- },
- },
- },
- ],
- },
+ orderBy: [
+ {
+ unterveranstaltungId: { sort: 'asc', nulls: 'first' },
+ },
+ ...(input.table?.orderBy ?? []),
+ ],
+ where,
select: {
id: true,
name: true,
description: true,
+ order: true,
type: true,
positions: true,
required: true,
diff --git a/apps/api/src/services/customFields/schema/customField.schema.ts b/apps/api/src/services/customFields/schema/customField.schema.ts
index 8172e451..af4585c1 100644
--- a/apps/api/src/services/customFields/schema/customField.schema.ts
+++ b/apps/api/src/services/customFields/schema/customField.schema.ts
@@ -1,11 +1,21 @@
import { CustomFieldPosition, CustomFieldType } from '@prisma/client'
import { z } from 'zod'
-export const customFieldSchema = z.strictObject({
- name: z.string().min(1),
- description: z.string().nullable(),
- type: z.nativeEnum(CustomFieldType),
- required: z.boolean(),
- options: z.array(z.string()),
- positions: z.nativeEnum(CustomFieldPosition).array(),
-})
+export const customFieldSchema = z
+ .strictObject({
+ name: z.string().min(1),
+ description: z.string().nullable(),
+ type: z.nativeEnum(CustomFieldType),
+ required: z.boolean(),
+ options: z.array(z.string()),
+ positions: z.nativeEnum(CustomFieldPosition).array().min(1),
+ })
+ .superRefine((values, ctx) => {
+ const optionTypes = ['BASIC_DROPDOWN', 'BASIC_RADIO', 'BASIC_SWITCH'] as CustomFieldType[]
+ if (optionTypes.includes(values.type) && values.options.length === 0) {
+ ctx.addIssue({
+ code: 'custom',
+ message: 'Es muss mindestens eine Auswahlmöglichkeit angegeben werden',
+ })
+ }
+ })
diff --git a/apps/api/src/services/customFields/schema/customFieldsUnterveranstaltungOrder.ts b/apps/api/src/services/customFields/schema/customFieldsUnterveranstaltungOrder.ts
new file mode 100644
index 00000000..8f672d27
--- /dev/null
+++ b/apps/api/src/services/customFields/schema/customFieldsUnterveranstaltungOrder.ts
@@ -0,0 +1,54 @@
+import z from 'zod'
+import { defineProtectedMutateProcedure } from '../../../types/defineProcedure.js'
+import { getGliederungRequireAdmin } from '../../../util/getGliederungRequireAdmin.js'
+import { TRPCError } from '@trpc/server'
+import prisma from '../../../prisma.js'
+
+export const customFieldUnterveranstaltungOrder = defineProtectedMutateProcedure({
+ key: 'unterveranstaltungOrder',
+ roleIds: ['ADMIN', 'GLIEDERUNG_ADMIN'],
+ inputSchema: z.strictObject({
+ unterveranstaltungId: z.uuid(),
+ fields: z.array(z.uuid()),
+ }),
+ handler: async ({ ctx, input }) => {
+ if (ctx.account.role === 'GLIEDERUNG_ADMIN') {
+ const gliederung = await getGliederungRequireAdmin(ctx.accountId)
+ if (gliederung.id !== input.unterveranstaltungId) {
+ throw new TRPCError({
+ code: 'FORBIDDEN',
+ })
+ }
+ }
+
+ const fields = await prisma.customField.findMany({
+ where: {
+ unterveranstaltungId: input.unterveranstaltungId,
+ id: {
+ in: input.fields,
+ },
+ },
+ })
+
+ if (fields.length !== input.fields.length) {
+ throw new TRPCError({
+ code: 'BAD_REQUEST',
+ message: 'Some supplied fields do not belong to the given unterveranstaltung!',
+ })
+ }
+
+ await prisma.$transaction(
+ input.fields.map((field, index) =>
+ prisma.customField.update({
+ where: {
+ unterveranstaltungId: input.unterveranstaltungId,
+ id: field,
+ },
+ data: {
+ order: index + 1,
+ },
+ })
+ )
+ )
+ },
+})
diff --git a/apps/api/src/services/customFields/schema/customFieldsVeranstaltungOrder.ts b/apps/api/src/services/customFields/schema/customFieldsVeranstaltungOrder.ts
new file mode 100644
index 00000000..ac435865
--- /dev/null
+++ b/apps/api/src/services/customFields/schema/customFieldsVeranstaltungOrder.ts
@@ -0,0 +1,44 @@
+import { TRPCError } from '@trpc/server'
+import z from 'zod'
+import prisma from '../../../prisma.js'
+import { defineProtectedMutateProcedure } from '../../../types/defineProcedure.js'
+
+export const customFieldVeranstaltungOrder = defineProtectedMutateProcedure({
+ key: 'veranstaltungOrder',
+ roleIds: ['ADMIN'],
+ inputSchema: z.strictObject({
+ veranstaltungId: z.uuid(),
+ fields: z.array(z.uuid()),
+ }),
+ handler: async ({ input }) => {
+ const fields = await prisma.customField.findMany({
+ where: {
+ veranstaltungId: input.veranstaltungId,
+ id: {
+ in: input.fields,
+ },
+ },
+ })
+
+ if (fields.length !== input.fields.length) {
+ throw new TRPCError({
+ code: 'BAD_REQUEST',
+ message: 'Some supplied fields do not belong to the given veranstaltung!',
+ })
+ }
+
+ await prisma.$transaction(
+ input.fields.map((field, index) =>
+ prisma.customField.update({
+ where: {
+ veranstaltungId: input.veranstaltungId,
+ id: field,
+ },
+ data: {
+ order: index + 1,
+ },
+ })
+ )
+ )
+ },
+})
diff --git a/apps/frontend/src/components/CustomFields/CustomFieldsTable.vue b/apps/frontend/src/components/CustomFields/CustomFieldsTable.vue
index f9bcf945..2ec38a34 100644
--- a/apps/frontend/src/components/CustomFields/CustomFieldsTable.vue
+++ b/apps/frontend/src/components/CustomFields/CustomFieldsTable.vue
@@ -32,6 +32,18 @@ const router = useRouter()
const column = createColumnHelper()
const columns = [
+ column.accessor('order', {
+ header: 'Reihenfolge',
+ enableSorting: true,
+ cell({ getValue }) {
+ const order = getValue()
+ if (!order) {
+ return '-'
+ }
+
+ return order
+ },
+ }),
column.accessor('name', {
header: 'Name',
enableColumnFilter: true,
@@ -174,6 +186,7 @@ function onClick(field: CustomField) {
diff --git a/apps/frontend/src/views/Unterveranstaltung/CustomFields/CustomFieldUnterveranstaltungOrder.vue b/apps/frontend/src/views/Unterveranstaltung/CustomFields/CustomFieldUnterveranstaltungOrder.vue
new file mode 100644
index 00000000..d324a12e
--- /dev/null
+++ b/apps/frontend/src/views/Unterveranstaltung/CustomFields/CustomFieldUnterveranstaltungOrder.vue
@@ -0,0 +1,168 @@
+
+
+
+
+
+
+ Reihenfolge
+ Name
+ Typ
+ Quelle
+
+
+
+
+
+
+
+ {{ field.order || '-' }}
+ ( {{ index + 1 }} )
+
+
+
+
+
+
+
+
+
+
+ {{ field.name }}
+ {{ formatType(field) }}
+ {{ formatSource(field) }}
+
+
+
+
+
+
+ Hinweis : Die Spalte Reihenfolge gliedert sich wie folgt: Die erste Zahl zeigt die aktuelle Position in
+ der Reihenfolge wohingegen die Zahl in der Klammer die neue Position anzeigt.
+
+
+
+
+ Speichern
+
+ Abbrechen
+
+
diff --git a/apps/frontend/src/views/Unterveranstaltung/UnterveranstaltungDetail.vue b/apps/frontend/src/views/Unterveranstaltung/UnterveranstaltungDetail.vue
index 8c8f7e8a..6a8eecbf 100644
--- a/apps/frontend/src/views/Unterveranstaltung/UnterveranstaltungDetail.vue
+++ b/apps/frontend/src/views/Unterveranstaltung/UnterveranstaltungDetail.vue
@@ -371,6 +371,7 @@ const anmeldeLinkCreateModal = useTemplateRef('anmeldeLinkCreateModal')
Hier können benutzerdefinierte Felder erstellt werden, welche für alle Unterveranstaltungen gelten.
+
+ Reihenfolge ändern
+
+
import('./CustomFields/CustomFieldUnterveranstaltungOrder.vue'),
+ meta: {
+ breadcrumbs: [
+ detailCrumb,
+ {
+ text: 'Benutzerdefinierte Felder sortieren',
+ },
+ ],
+ },
+ },
{
name: 'Unterveranstaltung Custom Field bearbeiten',
path: ':unterveranstaltungId/fields/:fieldId',
diff --git a/apps/frontend/src/views/Verwaltung/Veranstaltungen/CustomFields/CustomFieldVeranstaltungOrder.vue b/apps/frontend/src/views/Verwaltung/Veranstaltungen/CustomFields/CustomFieldVeranstaltungOrder.vue
new file mode 100644
index 00000000..347fd5f3
--- /dev/null
+++ b/apps/frontend/src/views/Verwaltung/Veranstaltungen/CustomFields/CustomFieldVeranstaltungOrder.vue
@@ -0,0 +1,126 @@
+
+
+
+
+
+
+ Reihenfolge
+ Name
+ Typ
+ Quelle
+
+
+
+
+
+
+ {{ field.order || '-' }}
+ ( {{ index + 1 }} )
+
+
+
+
+
+
+
+
+
+
+ {{ field.name }}
+ {{ formatType(field) }}
+ Veranstaltung
+
+
+
+
+
+ Hinweis : Die Spalte Reihenfolge gliedert sich wie folgt: Die erste Zahl zeigt die aktuelle Position in
+ der Reihenfolge wohingegen die Zahl in der Klammer die neue Position anzeigt.
+
+
+
+
+ Speichern
+
+ Abbrechen
+
+
diff --git a/apps/frontend/src/views/Verwaltung/Veranstaltungen/VeranstaltungDetail.vue b/apps/frontend/src/views/Verwaltung/Veranstaltungen/VeranstaltungDetail.vue
index 7730e943..74d2d789 100644
--- a/apps/frontend/src/views/Verwaltung/Veranstaltungen/VeranstaltungDetail.vue
+++ b/apps/frontend/src/views/Verwaltung/Veranstaltungen/VeranstaltungDetail.vue
@@ -10,6 +10,7 @@ import {
RocketLaunchIcon,
DocumentDuplicateIcon,
LinkIcon,
+ ChevronUpDownIcon,
} from '@heroicons/vue/24/outline'
import { useAsyncState } from '@vueuse/core'
import { computed } from 'vue'
@@ -352,12 +353,25 @@ function copyProgramLink() {
Hier können benutzerdefinierte Felder erstellt werden, welche für alle Unterveranstaltungen gelten.
-
- Neues Feld
-
+
+
+
+ Neues Feld
+
+
+
+ Reihenfolge ändern
+
+
import('./CustomFields/CustomFieldVeranstaltungOrder.vue'),
+ meta: {
+ breadcrumbs: [
+ detailCrumb,
+ {
+ text: 'Benutzerdefinierte Felder sortieren',
+ },
+ ],
+ },
+ },
{
name: 'Verwaltung Custom Field bearbeiten',
path: ':veranstaltungId/fields/:fieldId',
From 82b0b30c1c640ab5ca58705f0c15b14e6387ebbe Mon Sep 17 00:00:00 2001
From: Axel Rindle
Date: Wed, 4 Mar 2026 22:50:52 +0100
Subject: [PATCH 2/5] chore: remove unused import
---
.../CustomFields/CustomFieldVeranstaltungOrder.vue | 1 -
1 file changed, 1 deletion(-)
diff --git a/apps/frontend/src/views/Verwaltung/Veranstaltungen/CustomFields/CustomFieldVeranstaltungOrder.vue b/apps/frontend/src/views/Verwaltung/Veranstaltungen/CustomFields/CustomFieldVeranstaltungOrder.vue
index 347fd5f3..0e0d5c20 100644
--- a/apps/frontend/src/views/Verwaltung/Veranstaltungen/CustomFields/CustomFieldVeranstaltungOrder.vue
+++ b/apps/frontend/src/views/Verwaltung/Veranstaltungen/CustomFields/CustomFieldVeranstaltungOrder.vue
@@ -2,7 +2,6 @@
import { apiClient } from '@/api'
import Button from '@/components/UIComponents/Button.vue'
import { useRouteTitle } from '@/composables/useRouteTitle'
-import cn from '@/helpers/cn'
import { CustomFieldTypeMapping, type CustomField } from '@codeanker/api'
import { ChevronDownIcon, ChevronUpIcon } from '@heroicons/vue/24/outline'
import { useMutation, useQuery } from '@tanstack/vue-query'
From 0ab0d2aa4679307b7ea42bd9b2820b09ba7def51 Mon Sep 17 00:00:00 2001
From: Axel Rindle
Date: Wed, 4 Mar 2026 23:00:42 +0100
Subject: [PATCH 3/5] fix: zod schema
---
.../schema/customFieldsUnterveranstaltungOrder.ts | 4 ++--
.../customFields/schema/customFieldsVeranstaltungOrder.ts | 4 ++--
2 files changed, 4 insertions(+), 4 deletions(-)
diff --git a/apps/api/src/services/customFields/schema/customFieldsUnterveranstaltungOrder.ts b/apps/api/src/services/customFields/schema/customFieldsUnterveranstaltungOrder.ts
index 8f672d27..2b0f974a 100644
--- a/apps/api/src/services/customFields/schema/customFieldsUnterveranstaltungOrder.ts
+++ b/apps/api/src/services/customFields/schema/customFieldsUnterveranstaltungOrder.ts
@@ -8,8 +8,8 @@ export const customFieldUnterveranstaltungOrder = defineProtectedMutateProcedure
key: 'unterveranstaltungOrder',
roleIds: ['ADMIN', 'GLIEDERUNG_ADMIN'],
inputSchema: z.strictObject({
- unterveranstaltungId: z.uuid(),
- fields: z.array(z.uuid()),
+ unterveranstaltungId: z.string().uuid(),
+ fields: z.array(z.string().uuid()),
}),
handler: async ({ ctx, input }) => {
if (ctx.account.role === 'GLIEDERUNG_ADMIN') {
diff --git a/apps/api/src/services/customFields/schema/customFieldsVeranstaltungOrder.ts b/apps/api/src/services/customFields/schema/customFieldsVeranstaltungOrder.ts
index ac435865..3cc63732 100644
--- a/apps/api/src/services/customFields/schema/customFieldsVeranstaltungOrder.ts
+++ b/apps/api/src/services/customFields/schema/customFieldsVeranstaltungOrder.ts
@@ -7,8 +7,8 @@ export const customFieldVeranstaltungOrder = defineProtectedMutateProcedure({
key: 'veranstaltungOrder',
roleIds: ['ADMIN'],
inputSchema: z.strictObject({
- veranstaltungId: z.uuid(),
- fields: z.array(z.uuid()),
+ veranstaltungId: z.string().uuid(),
+ fields: z.array(z.string().uuid()),
}),
handler: async ({ input }) => {
const fields = await prisma.customField.findMany({
From 21c880347e8e1745a263290542a397ab905ae410 Mon Sep 17 00:00:00 2001
From: Axel Rindle
Date: Wed, 4 Mar 2026 23:17:45 +0100
Subject: [PATCH 4/5] chore: ui updates
---
.../CustomFieldUnterveranstaltungOrder.vue | 28 ++++++++++++++++---
.../UnterveranstaltungDetail.vue | 12 +++++---
.../CustomFieldVeranstaltungOrder.vue | 25 +++++++++++++++--
3 files changed, 54 insertions(+), 11 deletions(-)
diff --git a/apps/frontend/src/views/Unterveranstaltung/CustomFields/CustomFieldUnterveranstaltungOrder.vue b/apps/frontend/src/views/Unterveranstaltung/CustomFields/CustomFieldUnterveranstaltungOrder.vue
index d324a12e..ae0387af 100644
--- a/apps/frontend/src/views/Unterveranstaltung/CustomFields/CustomFieldUnterveranstaltungOrder.vue
+++ b/apps/frontend/src/views/Unterveranstaltung/CustomFields/CustomFieldUnterveranstaltungOrder.vue
@@ -5,10 +5,11 @@ import { useRouteTitle } from '@/composables/useRouteTitle'
import cn from '@/helpers/cn'
import { CustomFieldTypeMapping, type CustomField } from '@codeanker/api'
import { groupBy } from '@codeanker/helpers'
-import { ChevronDownIcon, ChevronUpIcon } from '@heroicons/vue/24/outline'
+import { ArrowLeftIcon, ChevronDownIcon, ChevronUpIcon } from '@heroicons/vue/24/outline'
import { useMutation, useQuery } from '@tanstack/vue-query'
import { useRouteParams } from '@vueuse/router'
import { computed, ref, watch } from 'vue'
+import { RouterLink } from 'vue-router'
const { setTitle } = useRouteTitle()
setTitle('Benutzerdefinierte Felder sortieren')
@@ -93,6 +94,23 @@ const { mutate, isPending } = useMutation({
+
+
+
+ Zurück zur Ausschreibung
+
+
+
+
+
Reihenfolge ändern
+
+ Hier kann die Reihenfolge der benutzerdefinierten Felder deiner Ausschreibung verändert werden.
+
+
+
@@ -110,7 +128,7 @@ const { mutate, isPending } = useMutation({
:class="
cn({
'even:bg-slate-50 dark:even:bg-slate-800': !!field.unterveranstaltungId,
- 'text-gray-400 italic': !!field.veranstaltungId,
+ 'text-gray-400 italic cursor-not-allowed': !!field.veranstaltungId,
})
"
>
@@ -161,8 +179,10 @@ const { mutate, isPending } = useMutation({
Abbrechen
+ Abbrechen
+
diff --git a/apps/frontend/src/views/Unterveranstaltung/UnterveranstaltungDetail.vue b/apps/frontend/src/views/Unterveranstaltung/UnterveranstaltungDetail.vue
index 6a8eecbf..83b18296 100644
--- a/apps/frontend/src/views/Unterveranstaltung/UnterveranstaltungDetail.vue
+++ b/apps/frontend/src/views/Unterveranstaltung/UnterveranstaltungDetail.vue
@@ -2,12 +2,14 @@
import {
CameraIcon,
ChatBubbleLeftRightIcon,
+ ChevronUpDownIcon,
CodeBracketIcon,
DocumentDuplicateIcon,
DocumentIcon,
HandRaisedIcon,
LinkIcon,
MegaphoneIcon,
+ PlusIcon,
RocketLaunchIcon,
SquaresPlusIcon,
UserGroupIcon,
@@ -373,22 +375,24 @@ const anmeldeLinkCreateModal = useTemplateRef('anmeldeLinkCreateModal')
- Neues Feld
+
+ Neues Feld
- Reihenfolge ändern
+
+ Reihenfolge ändern
diff --git a/apps/frontend/src/views/Verwaltung/Veranstaltungen/CustomFields/CustomFieldVeranstaltungOrder.vue b/apps/frontend/src/views/Verwaltung/Veranstaltungen/CustomFields/CustomFieldVeranstaltungOrder.vue
index 0e0d5c20..df07c4a2 100644
--- a/apps/frontend/src/views/Verwaltung/Veranstaltungen/CustomFields/CustomFieldVeranstaltungOrder.vue
+++ b/apps/frontend/src/views/Verwaltung/Veranstaltungen/CustomFields/CustomFieldVeranstaltungOrder.vue
@@ -3,7 +3,7 @@ import { apiClient } from '@/api'
import Button from '@/components/UIComponents/Button.vue'
import { useRouteTitle } from '@/composables/useRouteTitle'
import { CustomFieldTypeMapping, type CustomField } from '@codeanker/api'
-import { ChevronDownIcon, ChevronUpIcon } from '@heroicons/vue/24/outline'
+import { ArrowLeftIcon, ChevronDownIcon, ChevronUpIcon } from '@heroicons/vue/24/outline'
import { useMutation, useQuery } from '@tanstack/vue-query'
import { useRouteParams } from '@vueuse/router'
import { ref, watch } from 'vue'
@@ -60,6 +60,23 @@ const { mutate, isPending } = useMutation({
+
+
+
+ Zurück zur Veranstaltung
+
+
+
+
+
Reihenfolge ändern
+
+ Hier kann die Reihenfolge benutzerdefinierter Felder der Veranstaltung verändert werden.
+
+
+
@@ -118,8 +135,10 @@ const { mutate, isPending } = useMutation({
Abbrechen
+ Abbrechen
+
From 7a0779c3932d75cd84134b7bf6e3076ea828b1a3 Mon Sep 17 00:00:00 2001
From: Axel Rindle
Date: Thu, 5 Mar 2026 09:18:21 +0100
Subject: [PATCH 5/5] feat: show notification
---
.../CustomFieldUnterveranstaltungOrder.vue | 15 +++++++++++++++
.../CustomFieldVeranstaltungOrder.vue | 15 +++++++++++++++
2 files changed, 30 insertions(+)
diff --git a/apps/frontend/src/views/Unterveranstaltung/CustomFields/CustomFieldUnterveranstaltungOrder.vue b/apps/frontend/src/views/Unterveranstaltung/CustomFields/CustomFieldUnterveranstaltungOrder.vue
index ae0387af..8cb874a9 100644
--- a/apps/frontend/src/views/Unterveranstaltung/CustomFields/CustomFieldUnterveranstaltungOrder.vue
+++ b/apps/frontend/src/views/Unterveranstaltung/CustomFields/CustomFieldUnterveranstaltungOrder.vue
@@ -1,5 +1,6 @@