From f40952120195e20c7d6c9de3f5d79faa1f3d1d1d Mon Sep 17 00:00:00 2001 From: Luka Pajukanta Date: Fri, 2 Oct 2026 14:47:16 +0300 Subject: [PATCH 1/7] Move annotation extraction config from universe annotations to form fields Fields now declare propagateToAnnotation / propagateDimensionOn{Create,Edit} in the form editor. UniverseAnnotation.form_fields is migrated onto the fields and removed. Part of #990. Co-Authored-By: Claude Sonnet 5.5 --- kompassi-v2-frontend/src/__generated__/gql.ts | 12 +- .../src/__generated__/graphql.ts | 13 +- .../program-annotations/actions.ts | 6 - .../[eventSlug]/program-annotations/page.tsx | 17 +-- .../edit/[language]/fields/page.tsx | 18 +++ .../src/components/forms/EditFieldModal.tsx | 8 ++ .../src/components/forms/FormEditor.tsx | 9 ++ .../components/forms/FormEditorWrapper.tsx | 7 + .../src/components/forms/editFieldForm.ts | 135 ++++++++++++++---- .../src/components/forms/models.ts | 4 + kompassi-v2-frontend/src/translations/en.tsx | 31 ++-- kompassi-v2-frontend/src/translations/fi.tsx | 32 +++-- kompassi-v2-frontend/src/translations/sv.tsx | 31 ++-- kompassi/core/pseudonymization.py | 1 - kompassi/dimensions/graphql/annotation.py | 1 + .../mutations/put_universe_annotation.py | 16 +-- .../graphql/universe_annotation_limited.py | 4 - ...opagate_annotation_form_fields_to_forms.py | 70 +++++++++ .../dimensions/models/universe_annotation.py | 4 - kompassi/forms/models/field.py | 58 ++++++++ kompassi/forms/tests.py | 24 ++++ kompassi/forms/utils/extract_annotations.py | 94 ++++++------ kompassi/program_v2/tests.py | 13 +- 23 files changed, 438 insertions(+), 170 deletions(-) create mode 100644 kompassi/dimensions/migrations/0020_propagate_annotation_form_fields_to_forms.py diff --git a/kompassi-v2-frontend/src/__generated__/gql.ts b/kompassi-v2-frontend/src/__generated__/gql.ts index a302cf2b4..535dc5ae8 100644 --- a/kompassi-v2-frontend/src/__generated__/gql.ts +++ b/kompassi-v2-frontend/src/__generated__/gql.ts @@ -87,7 +87,7 @@ type Documents = { "\n fragment ProgramAdmin on FullProgramType {\n slug\n title\n scheduleItems {\n startTime\n }\n cachedDimensions\n }\n": typeof types.ProgramAdminFragmentDoc, "\n query ProgramAdminList(\n $eventSlug: String!\n $locale: String\n $filters: [DimensionFilterInput!]\n ) {\n event(slug: $eventSlug) {\n slug\n name\n program {\n scheduleItemsExcelExportLink\n dimensions(publicOnly: false) {\n slug\n title(lang: $locale)\n isTechnical\n isMultiValue\n isKeyDimension\n isListFilter\n\n values(lang: $locale) {\n slug\n title(lang: $locale)\n color\n }\n }\n\n programs(filters: $filters, publicOnly: false) {\n ...ProgramAdmin\n }\n }\n }\n }\n": typeof types.ProgramAdminListDocument, "\n mutation PutEventAnnotation($input: PutUniverseAnnotationInput!) {\n putUniverseAnnotation(input: $input) {\n universeAnnotation {\n annotation {\n slug\n }\n }\n }\n }\n": typeof types.PutEventAnnotationDocument, - "\n fragment ProgramAdminEventAnnotation on LimitedUniverseAnnotationType {\n annotation {\n slug\n title(lang: $locale)\n description(lang: $locale)\n type\n isComputed\n isPublic\n isShownInDetail\n isInternal\n isApplicableToProgramItems\n isApplicableToScheduleItems\n }\n isActive\n formFields\n }\n": typeof types.ProgramAdminEventAnnotationFragmentDoc, + "\n fragment ProgramAdminEventAnnotation on LimitedUniverseAnnotationType {\n annotation {\n slug\n title(lang: $locale)\n description(lang: $locale)\n type\n isComputed\n isPublic\n isShownInDetail\n isInternal\n isApplicableToProgramItems\n isApplicableToScheduleItems\n }\n isActive\n }\n": typeof types.ProgramAdminEventAnnotationFragmentDoc, "\n query ProgramAdminEventAnnotations($eventSlug: String!, $locale: String) {\n event(slug: $eventSlug) {\n name\n slug\n timezone\n\n program {\n eventAnnotations {\n ...ProgramAdminEventAnnotation\n }\n }\n }\n }\n": typeof types.ProgramAdminEventAnnotationsDocument, "\n mutation PutProgramDimension($input: PutDimensionInput!) {\n putDimension(input: $input) {\n dimension {\n slug\n }\n }\n }\n": typeof types.PutProgramDimensionDocument, "\n mutation DeleteProgramDimension($input: DeleteDimensionInput!) {\n deleteDimension(input: $input) {\n slug\n }\n }\n": typeof types.DeleteProgramDimensionDocument, @@ -100,7 +100,7 @@ type Documents = { "\n mutation DeleteProgramFormLanguage($input: DeleteSurveyLanguageInput!) {\n deleteSurveyLanguage(input: $input) {\n language\n }\n }\n": typeof types.DeleteProgramFormLanguageDocument, "\n mutation UpdateFormFieldsMutation($input: UpdateFormFieldsInput!) {\n updateFormFields(input: $input) {\n survey {\n slug\n }\n }\n }\n": typeof types.UpdateFormFieldsMutationDocument, "\n mutation PromoteProgramFormFieldToDimension(\n $input: PromoteFieldToDimensionInput!\n ) {\n promoteFieldToDimension(input: $input) {\n survey {\n slug\n }\n }\n }\n": typeof types.PromoteProgramFormFieldToDimensionDocument, - "\n query EditProgramFormFieldsPage(\n $eventSlug: String!\n $surveySlug: String!\n $language: String!\n $locale: String\n ) {\n event(slug: $eventSlug) {\n name\n slug\n\n forms {\n survey(slug: $surveySlug, app: PROGRAM) {\n ...EditSurveyFieldsPage\n }\n }\n }\n }\n": typeof types.EditProgramFormFieldsPageDocument, + "\n query EditProgramFormFieldsPage(\n $eventSlug: String!\n $surveySlug: String!\n $language: String!\n $locale: String\n ) {\n event(slug: $eventSlug) {\n name\n slug\n\n program {\n eventAnnotations {\n isActive\n annotation {\n slug\n title(lang: $locale)\n isApplicableToProgramItems\n isApplicableToInvolvements\n }\n }\n }\n\n forms {\n survey(slug: $surveySlug, app: PROGRAM) {\n ...EditSurveyFieldsPage\n }\n }\n }\n }\n": typeof types.EditProgramFormFieldsPageDocument, "\n fragment EditProgramFormLanguage on FullSurveyType {\n slug\n title(lang: $locale)\n canRemove\n canGrantAccess\n purpose\n\n form(lang: $language) {\n title\n language\n description\n thankYouMessage\n fields\n canRemove\n }\n\n languages {\n language\n }\n }\n": typeof types.EditProgramFormLanguageFragmentDoc, "\n query EditProgramFormLanguagePage(\n $eventSlug: String!\n $surveySlug: String!\n $language: String!\n $locale: String\n ) {\n event(slug: $eventSlug) {\n name\n slug\n\n forms {\n survey(slug: $surveySlug, app: PROGRAM) {\n ...EditProgramFormLanguage\n }\n }\n }\n }\n": typeof types.EditProgramFormLanguagePageDocument, "\n mutation CreateProgramFormLanguage($input: CreateSurveyLanguageInput!) {\n createSurveyLanguage(input: $input) {\n form {\n language\n }\n }\n }\n": typeof types.CreateProgramFormLanguageDocument, @@ -336,7 +336,7 @@ const documents: Documents = { "\n fragment ProgramAdmin on FullProgramType {\n slug\n title\n scheduleItems {\n startTime\n }\n cachedDimensions\n }\n": types.ProgramAdminFragmentDoc, "\n query ProgramAdminList(\n $eventSlug: String!\n $locale: String\n $filters: [DimensionFilterInput!]\n ) {\n event(slug: $eventSlug) {\n slug\n name\n program {\n scheduleItemsExcelExportLink\n dimensions(publicOnly: false) {\n slug\n title(lang: $locale)\n isTechnical\n isMultiValue\n isKeyDimension\n isListFilter\n\n values(lang: $locale) {\n slug\n title(lang: $locale)\n color\n }\n }\n\n programs(filters: $filters, publicOnly: false) {\n ...ProgramAdmin\n }\n }\n }\n }\n": types.ProgramAdminListDocument, "\n mutation PutEventAnnotation($input: PutUniverseAnnotationInput!) {\n putUniverseAnnotation(input: $input) {\n universeAnnotation {\n annotation {\n slug\n }\n }\n }\n }\n": types.PutEventAnnotationDocument, - "\n fragment ProgramAdminEventAnnotation on LimitedUniverseAnnotationType {\n annotation {\n slug\n title(lang: $locale)\n description(lang: $locale)\n type\n isComputed\n isPublic\n isShownInDetail\n isInternal\n isApplicableToProgramItems\n isApplicableToScheduleItems\n }\n isActive\n formFields\n }\n": types.ProgramAdminEventAnnotationFragmentDoc, + "\n fragment ProgramAdminEventAnnotation on LimitedUniverseAnnotationType {\n annotation {\n slug\n title(lang: $locale)\n description(lang: $locale)\n type\n isComputed\n isPublic\n isShownInDetail\n isInternal\n isApplicableToProgramItems\n isApplicableToScheduleItems\n }\n isActive\n }\n": types.ProgramAdminEventAnnotationFragmentDoc, "\n query ProgramAdminEventAnnotations($eventSlug: String!, $locale: String) {\n event(slug: $eventSlug) {\n name\n slug\n timezone\n\n program {\n eventAnnotations {\n ...ProgramAdminEventAnnotation\n }\n }\n }\n }\n": types.ProgramAdminEventAnnotationsDocument, "\n mutation PutProgramDimension($input: PutDimensionInput!) {\n putDimension(input: $input) {\n dimension {\n slug\n }\n }\n }\n": types.PutProgramDimensionDocument, "\n mutation DeleteProgramDimension($input: DeleteDimensionInput!) {\n deleteDimension(input: $input) {\n slug\n }\n }\n": types.DeleteProgramDimensionDocument, @@ -349,7 +349,7 @@ const documents: Documents = { "\n mutation DeleteProgramFormLanguage($input: DeleteSurveyLanguageInput!) {\n deleteSurveyLanguage(input: $input) {\n language\n }\n }\n": types.DeleteProgramFormLanguageDocument, "\n mutation UpdateFormFieldsMutation($input: UpdateFormFieldsInput!) {\n updateFormFields(input: $input) {\n survey {\n slug\n }\n }\n }\n": types.UpdateFormFieldsMutationDocument, "\n mutation PromoteProgramFormFieldToDimension(\n $input: PromoteFieldToDimensionInput!\n ) {\n promoteFieldToDimension(input: $input) {\n survey {\n slug\n }\n }\n }\n": types.PromoteProgramFormFieldToDimensionDocument, - "\n query EditProgramFormFieldsPage(\n $eventSlug: String!\n $surveySlug: String!\n $language: String!\n $locale: String\n ) {\n event(slug: $eventSlug) {\n name\n slug\n\n forms {\n survey(slug: $surveySlug, app: PROGRAM) {\n ...EditSurveyFieldsPage\n }\n }\n }\n }\n": types.EditProgramFormFieldsPageDocument, + "\n query EditProgramFormFieldsPage(\n $eventSlug: String!\n $surveySlug: String!\n $language: String!\n $locale: String\n ) {\n event(slug: $eventSlug) {\n name\n slug\n\n program {\n eventAnnotations {\n isActive\n annotation {\n slug\n title(lang: $locale)\n isApplicableToProgramItems\n isApplicableToInvolvements\n }\n }\n }\n\n forms {\n survey(slug: $surveySlug, app: PROGRAM) {\n ...EditSurveyFieldsPage\n }\n }\n }\n }\n": types.EditProgramFormFieldsPageDocument, "\n fragment EditProgramFormLanguage on FullSurveyType {\n slug\n title(lang: $locale)\n canRemove\n canGrantAccess\n purpose\n\n form(lang: $language) {\n title\n language\n description\n thankYouMessage\n fields\n canRemove\n }\n\n languages {\n language\n }\n }\n": types.EditProgramFormLanguageFragmentDoc, "\n query EditProgramFormLanguagePage(\n $eventSlug: String!\n $surveySlug: String!\n $language: String!\n $locale: String\n ) {\n event(slug: $eventSlug) {\n name\n slug\n\n forms {\n survey(slug: $surveySlug, app: PROGRAM) {\n ...EditProgramFormLanguage\n }\n }\n }\n }\n": types.EditProgramFormLanguagePageDocument, "\n mutation CreateProgramFormLanguage($input: CreateSurveyLanguageInput!) {\n createSurveyLanguage(input: $input) {\n form {\n language\n }\n }\n }\n": types.CreateProgramFormLanguageDocument, @@ -821,7 +821,7 @@ export function graphql(source: "\n mutation PutEventAnnotation($input: PutUniv /** * The graphql function is used to parse GraphQL queries into a document that can be used by GraphQL clients. */ -export function graphql(source: "\n fragment ProgramAdminEventAnnotation on LimitedUniverseAnnotationType {\n annotation {\n slug\n title(lang: $locale)\n description(lang: $locale)\n type\n isComputed\n isPublic\n isShownInDetail\n isInternal\n isApplicableToProgramItems\n isApplicableToScheduleItems\n }\n isActive\n formFields\n }\n"): (typeof documents)["\n fragment ProgramAdminEventAnnotation on LimitedUniverseAnnotationType {\n annotation {\n slug\n title(lang: $locale)\n description(lang: $locale)\n type\n isComputed\n isPublic\n isShownInDetail\n isInternal\n isApplicableToProgramItems\n isApplicableToScheduleItems\n }\n isActive\n formFields\n }\n"]; +export function graphql(source: "\n fragment ProgramAdminEventAnnotation on LimitedUniverseAnnotationType {\n annotation {\n slug\n title(lang: $locale)\n description(lang: $locale)\n type\n isComputed\n isPublic\n isShownInDetail\n isInternal\n isApplicableToProgramItems\n isApplicableToScheduleItems\n }\n isActive\n }\n"): (typeof documents)["\n fragment ProgramAdminEventAnnotation on LimitedUniverseAnnotationType {\n annotation {\n slug\n title(lang: $locale)\n description(lang: $locale)\n type\n isComputed\n isPublic\n isShownInDetail\n isInternal\n isApplicableToProgramItems\n isApplicableToScheduleItems\n }\n isActive\n }\n"]; /** * The graphql function is used to parse GraphQL queries into a document that can be used by GraphQL clients. */ @@ -873,7 +873,7 @@ export function graphql(source: "\n mutation PromoteProgramFormFieldToDimension /** * The graphql function is used to parse GraphQL queries into a document that can be used by GraphQL clients. */ -export function graphql(source: "\n query EditProgramFormFieldsPage(\n $eventSlug: String!\n $surveySlug: String!\n $language: String!\n $locale: String\n ) {\n event(slug: $eventSlug) {\n name\n slug\n\n forms {\n survey(slug: $surveySlug, app: PROGRAM) {\n ...EditSurveyFieldsPage\n }\n }\n }\n }\n"): (typeof documents)["\n query EditProgramFormFieldsPage(\n $eventSlug: String!\n $surveySlug: String!\n $language: String!\n $locale: String\n ) {\n event(slug: $eventSlug) {\n name\n slug\n\n forms {\n survey(slug: $surveySlug, app: PROGRAM) {\n ...EditSurveyFieldsPage\n }\n }\n }\n }\n"]; +export function graphql(source: "\n query EditProgramFormFieldsPage(\n $eventSlug: String!\n $surveySlug: String!\n $language: String!\n $locale: String\n ) {\n event(slug: $eventSlug) {\n name\n slug\n\n program {\n eventAnnotations {\n isActive\n annotation {\n slug\n title(lang: $locale)\n isApplicableToProgramItems\n isApplicableToInvolvements\n }\n }\n }\n\n forms {\n survey(slug: $surveySlug, app: PROGRAM) {\n ...EditSurveyFieldsPage\n }\n }\n }\n }\n"): (typeof documents)["\n query EditProgramFormFieldsPage(\n $eventSlug: String!\n $surveySlug: String!\n $language: String!\n $locale: String\n ) {\n event(slug: $eventSlug) {\n name\n slug\n\n program {\n eventAnnotations {\n isActive\n annotation {\n slug\n title(lang: $locale)\n isApplicableToProgramItems\n isApplicableToInvolvements\n }\n }\n }\n\n forms {\n survey(slug: $surveySlug, app: PROGRAM) {\n ...EditSurveyFieldsPage\n }\n }\n }\n }\n"]; /** * The graphql function is used to parse GraphQL queries into a document that can be used by GraphQL clients. */ diff --git a/kompassi-v2-frontend/src/__generated__/graphql.ts b/kompassi-v2-frontend/src/__generated__/graphql.ts index c874bdccc..fffb9d70e 100644 --- a/kompassi-v2-frontend/src/__generated__/graphql.ts +++ b/kompassi-v2-frontend/src/__generated__/graphql.ts @@ -450,7 +450,6 @@ export enum PutUniverseAnnotationAction { export type PutUniverseAnnotationInput = { action?: PutUniverseAnnotationAction | null | undefined; annotationSlug: string; - formFields: Array; isActive: boolean; scopeSlug: string; universeSlug: string; @@ -1130,7 +1129,7 @@ export type PutEventAnnotationMutationVariables = Exact<{ export type PutEventAnnotationMutation = { putUniverseAnnotation: { universeAnnotation: { annotation: { slug: string } } | null } | null }; -export type ProgramAdminEventAnnotationFragment = { isActive: boolean, formFields: unknown, annotation: { slug: string, title: string, description: string, type: AnnotationDataType, isComputed: boolean, isPublic: boolean, isShownInDetail: boolean, isInternal: boolean, isApplicableToProgramItems: boolean, isApplicableToScheduleItems: boolean } }; +export type ProgramAdminEventAnnotationFragment = { isActive: boolean, annotation: { slug: string, title: string, description: string, type: AnnotationDataType, isComputed: boolean, isPublic: boolean, isShownInDetail: boolean, isInternal: boolean, isApplicableToProgramItems: boolean, isApplicableToScheduleItems: boolean } }; export type ProgramAdminEventAnnotationsQueryVariables = Exact<{ eventSlug: string; @@ -1138,7 +1137,7 @@ export type ProgramAdminEventAnnotationsQueryVariables = Exact<{ }>; -export type ProgramAdminEventAnnotationsQuery = { event: { name: string, slug: string, timezone: string, program: { eventAnnotations: Array<{ isActive: boolean, formFields: unknown, annotation: { slug: string, title: string, description: string, type: AnnotationDataType, isComputed: boolean, isPublic: boolean, isShownInDetail: boolean, isInternal: boolean, isApplicableToProgramItems: boolean, isApplicableToScheduleItems: boolean } }> } | null } | null }; +export type ProgramAdminEventAnnotationsQuery = { event: { name: string, slug: string, timezone: string, program: { eventAnnotations: Array<{ isActive: boolean, annotation: { slug: string, title: string, description: string, type: AnnotationDataType, isComputed: boolean, isPublic: boolean, isShownInDetail: boolean, isInternal: boolean, isApplicableToProgramItems: boolean, isApplicableToScheduleItems: boolean } }> } | null } | null }; export type PutProgramDimensionMutationVariables = Exact<{ input: PutDimensionInput; @@ -1228,7 +1227,7 @@ export type EditProgramFormFieldsPageQueryVariables = Exact<{ }>; -export type EditProgramFormFieldsPageQuery = { event: { name: string, slug: string, forms: { survey: { slug: string, title: string | null, canRemove: boolean, canGrantAccess: boolean, purpose: SurveyPurpose, dimensions: Array<{ slug: string, canRemove: boolean, canAddValues: boolean, title: string | null, isPublic: boolean, isKeyDimension: boolean, isMultiValue: boolean, isListFilter: boolean, isShownInDetail: boolean, isNegativeSelection: boolean, isTechnical: boolean, valueOrdering: DimensionsDimensionValueOrderingChoices, titleFi: string, titleEn: string, titleSv: string, values: Array<{ slug: string, color: string, isTechnical: boolean, isSubjectLocked: boolean, canRemove: boolean, title: string | null, titleFi: string, titleEn: string, titleSv: string }> }>, form: { title: string, language: FormsFormLanguageChoices, fields: unknown, canRemove: boolean } | null, languages: Array<{ language: FormsFormLanguageChoices }> } | null } | null } | null }; +export type EditProgramFormFieldsPageQuery = { event: { name: string, slug: string, program: { eventAnnotations: Array<{ isActive: boolean, annotation: { slug: string, title: string, isApplicableToProgramItems: boolean, isApplicableToInvolvements: boolean } }> } | null, forms: { survey: { slug: string, title: string | null, canRemove: boolean, canGrantAccess: boolean, purpose: SurveyPurpose, dimensions: Array<{ slug: string, canRemove: boolean, canAddValues: boolean, title: string | null, isPublic: boolean, isKeyDimension: boolean, isMultiValue: boolean, isListFilter: boolean, isShownInDetail: boolean, isNegativeSelection: boolean, isTechnical: boolean, valueOrdering: DimensionsDimensionValueOrderingChoices, titleFi: string, titleEn: string, titleSv: string, values: Array<{ slug: string, color: string, isTechnical: boolean, isSubjectLocked: boolean, canRemove: boolean, title: string | null, titleFi: string, titleEn: string, titleSv: string }> }>, form: { title: string, language: FormsFormLanguageChoices, fields: unknown, canRemove: boolean } | null, languages: Array<{ language: FormsFormLanguageChoices }> } | null } | null } | null }; export type EditProgramFormLanguageFragment = { slug: string, title: string | null, canRemove: boolean, canGrantAccess: boolean, purpose: SurveyPurpose, form: { title: string, language: FormsFormLanguageChoices, description: string, thankYouMessage: string, fields: unknown, canRemove: boolean } | null, languages: Array<{ language: FormsFormLanguageChoices }> }; @@ -2161,7 +2160,7 @@ export const ProgramAdminDetailHostFragmentDoc = {"kind":"Document","definitions export const ProgramAdminDetailInvitationFragmentDoc = {"kind":"Document","definitions":[{"kind":"FragmentDefinition","name":{"kind":"Name","value":"ProgramAdminDetailInvitation"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"LimitedInvitationType"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"email"}},{"kind":"Field","name":{"kind":"Name","value":"createdAt"}},{"kind":"Field","name":{"kind":"Name","value":"cachedDimensions"}}]}}]} as unknown as DocumentNode; export const ProgramAdminDetailScheduleItemFragmentDoc = {"kind":"Document","definitions":[{"kind":"FragmentDefinition","name":{"kind":"Name","value":"ProgramAdminDetailScheduleItem"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"LimitedScheduleItemType"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"slug"}},{"kind":"Field","name":{"kind":"Name","value":"title"}},{"kind":"Field","name":{"kind":"Name","value":"subtitle"}},{"kind":"Field","name":{"kind":"Name","value":"location"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"lang"},"value":{"kind":"Variable","name":{"kind":"Name","value":"locale"}}}]},{"kind":"Field","name":{"kind":"Name","value":"startTime"}},{"kind":"Field","name":{"kind":"Name","value":"durationMinutes"}},{"kind":"Field","name":{"kind":"Name","value":"room"}},{"kind":"Field","name":{"kind":"Name","value":"freeformLocation"}},{"kind":"Field","name":{"kind":"Name","value":"isPublic"}}]}}]} as unknown as DocumentNode; export const ProgramAdminFragmentDoc = {"kind":"Document","definitions":[{"kind":"FragmentDefinition","name":{"kind":"Name","value":"ProgramAdmin"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"FullProgramType"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"slug"}},{"kind":"Field","name":{"kind":"Name","value":"title"}},{"kind":"Field","name":{"kind":"Name","value":"scheduleItems"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"startTime"}}]}},{"kind":"Field","name":{"kind":"Name","value":"cachedDimensions"}}]}}]} as unknown as DocumentNode; -export const ProgramAdminEventAnnotationFragmentDoc = {"kind":"Document","definitions":[{"kind":"FragmentDefinition","name":{"kind":"Name","value":"ProgramAdminEventAnnotation"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"LimitedUniverseAnnotationType"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"annotation"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"slug"}},{"kind":"Field","name":{"kind":"Name","value":"title"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"lang"},"value":{"kind":"Variable","name":{"kind":"Name","value":"locale"}}}]},{"kind":"Field","name":{"kind":"Name","value":"description"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"lang"},"value":{"kind":"Variable","name":{"kind":"Name","value":"locale"}}}]},{"kind":"Field","name":{"kind":"Name","value":"type"}},{"kind":"Field","name":{"kind":"Name","value":"isComputed"}},{"kind":"Field","name":{"kind":"Name","value":"isPublic"}},{"kind":"Field","name":{"kind":"Name","value":"isShownInDetail"}},{"kind":"Field","name":{"kind":"Name","value":"isInternal"}},{"kind":"Field","name":{"kind":"Name","value":"isApplicableToProgramItems"}},{"kind":"Field","name":{"kind":"Name","value":"isApplicableToScheduleItems"}}]}},{"kind":"Field","name":{"kind":"Name","value":"isActive"}},{"kind":"Field","name":{"kind":"Name","value":"formFields"}}]}}]} as unknown as DocumentNode; +export const ProgramAdminEventAnnotationFragmentDoc = {"kind":"Document","definitions":[{"kind":"FragmentDefinition","name":{"kind":"Name","value":"ProgramAdminEventAnnotation"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"LimitedUniverseAnnotationType"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"annotation"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"slug"}},{"kind":"Field","name":{"kind":"Name","value":"title"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"lang"},"value":{"kind":"Variable","name":{"kind":"Name","value":"locale"}}}]},{"kind":"Field","name":{"kind":"Name","value":"description"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"lang"},"value":{"kind":"Variable","name":{"kind":"Name","value":"locale"}}}]},{"kind":"Field","name":{"kind":"Name","value":"type"}},{"kind":"Field","name":{"kind":"Name","value":"isComputed"}},{"kind":"Field","name":{"kind":"Name","value":"isPublic"}},{"kind":"Field","name":{"kind":"Name","value":"isShownInDetail"}},{"kind":"Field","name":{"kind":"Name","value":"isInternal"}},{"kind":"Field","name":{"kind":"Name","value":"isApplicableToProgramItems"}},{"kind":"Field","name":{"kind":"Name","value":"isApplicableToScheduleItems"}}]}},{"kind":"Field","name":{"kind":"Name","value":"isActive"}}]}}]} as unknown as DocumentNode; export const EditProgramFormLanguageFragmentDoc = {"kind":"Document","definitions":[{"kind":"FragmentDefinition","name":{"kind":"Name","value":"EditProgramFormLanguage"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"FullSurveyType"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"slug"}},{"kind":"Field","name":{"kind":"Name","value":"title"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"lang"},"value":{"kind":"Variable","name":{"kind":"Name","value":"locale"}}}]},{"kind":"Field","name":{"kind":"Name","value":"canRemove"}},{"kind":"Field","name":{"kind":"Name","value":"canGrantAccess"}},{"kind":"Field","name":{"kind":"Name","value":"purpose"}},{"kind":"Field","name":{"kind":"Name","value":"form"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"lang"},"value":{"kind":"Variable","name":{"kind":"Name","value":"language"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"title"}},{"kind":"Field","name":{"kind":"Name","value":"language"}},{"kind":"Field","name":{"kind":"Name","value":"description"}},{"kind":"Field","name":{"kind":"Name","value":"thankYouMessage"}},{"kind":"Field","name":{"kind":"Name","value":"fields"}},{"kind":"Field","name":{"kind":"Name","value":"canRemove"}}]}},{"kind":"Field","name":{"kind":"Name","value":"languages"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"language"}}]}}]}}]} as unknown as DocumentNode; export const EditProgramFormFragmentDoc = {"kind":"Document","definitions":[{"kind":"FragmentDefinition","name":{"kind":"Name","value":"EditProgramForm"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"FullSurveyType"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"slug"}},{"kind":"Field","name":{"kind":"Name","value":"title"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"lang"},"value":{"kind":"Variable","name":{"kind":"Name","value":"locale"}}}]},{"kind":"Field","name":{"kind":"Name","value":"activeFrom"}},{"kind":"Field","name":{"kind":"Name","value":"activeUntil"}},{"kind":"Field","name":{"kind":"Name","value":"canRemove"}},{"kind":"Field","name":{"kind":"Name","value":"canGrantAccess"}},{"kind":"Field","name":{"kind":"Name","value":"purpose"}},{"kind":"Field","name":{"kind":"Name","value":"languages"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"title"}},{"kind":"Field","name":{"kind":"Name","value":"language"}},{"kind":"Field","name":{"kind":"Name","value":"canRemove"}}]}}]}}]} as unknown as DocumentNode; export const ProgramFormResponseEditFragmentDoc = {"kind":"Document","definitions":[{"kind":"FragmentDefinition","name":{"kind":"Name","value":"ProgramFormResponseEdit"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"FullResponseType"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"revisionCreatedAt"}},{"kind":"Field","name":{"kind":"Name","value":"originalCreatedBy"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"fullName"}}]}},{"kind":"Field","name":{"kind":"Name","value":"values"}},{"kind":"Field","name":{"kind":"Name","value":"form"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"title"}},{"kind":"Field","name":{"kind":"Name","value":"description"}},{"kind":"Field","name":{"kind":"Name","value":"fields"}},{"kind":"Field","name":{"kind":"Name","value":"survey"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"slug"}},{"kind":"Field","name":{"kind":"Name","value":"profileFieldSelector"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"FullProfileFieldSelector"}}]}}]}}]}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"FullProfileFieldSelector"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"ProfileFieldSelectorType"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"firstName"}},{"kind":"Field","name":{"kind":"Name","value":"lastName"}},{"kind":"Field","name":{"kind":"Name","value":"nick"}},{"kind":"Field","name":{"kind":"Name","value":"email"}},{"kind":"Field","name":{"kind":"Name","value":"phoneNumber"}},{"kind":"Field","name":{"kind":"Name","value":"discordHandle"}}]}}]} as unknown as DocumentNode; @@ -2271,7 +2270,7 @@ export const ProgramAdminDetailScheduleDocument = {"kind":"Document","definition export const CreateProgramDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"mutation","name":{"kind":"Name","value":"CreateProgram"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"input"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"CreateProgramInput"}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"createProgram"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"input"},"value":{"kind":"Variable","name":{"kind":"Name","value":"input"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"program"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"slug"}}]}}]}}]}}]} as unknown as DocumentNode; export const ProgramAdminListDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"ProgramAdminList"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"eventSlug"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}}},{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"locale"}},"type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}},{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"filters"}},"type":{"kind":"ListType","type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"DimensionFilterInput"}}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"event"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"slug"},"value":{"kind":"Variable","name":{"kind":"Name","value":"eventSlug"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"slug"}},{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"program"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"scheduleItemsExcelExportLink"}},{"kind":"Field","name":{"kind":"Name","value":"dimensions"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"publicOnly"},"value":{"kind":"BooleanValue","value":false}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"slug"}},{"kind":"Field","name":{"kind":"Name","value":"title"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"lang"},"value":{"kind":"Variable","name":{"kind":"Name","value":"locale"}}}]},{"kind":"Field","name":{"kind":"Name","value":"isTechnical"}},{"kind":"Field","name":{"kind":"Name","value":"isMultiValue"}},{"kind":"Field","name":{"kind":"Name","value":"isKeyDimension"}},{"kind":"Field","name":{"kind":"Name","value":"isListFilter"}},{"kind":"Field","name":{"kind":"Name","value":"values"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"lang"},"value":{"kind":"Variable","name":{"kind":"Name","value":"locale"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"slug"}},{"kind":"Field","name":{"kind":"Name","value":"title"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"lang"},"value":{"kind":"Variable","name":{"kind":"Name","value":"locale"}}}]},{"kind":"Field","name":{"kind":"Name","value":"color"}}]}}]}},{"kind":"Field","name":{"kind":"Name","value":"programs"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"filters"},"value":{"kind":"Variable","name":{"kind":"Name","value":"filters"}}},{"kind":"Argument","name":{"kind":"Name","value":"publicOnly"},"value":{"kind":"BooleanValue","value":false}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"ProgramAdmin"}}]}}]}}]}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"ProgramAdmin"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"FullProgramType"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"slug"}},{"kind":"Field","name":{"kind":"Name","value":"title"}},{"kind":"Field","name":{"kind":"Name","value":"scheduleItems"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"startTime"}}]}},{"kind":"Field","name":{"kind":"Name","value":"cachedDimensions"}}]}}]} as unknown as DocumentNode; export const PutEventAnnotationDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"mutation","name":{"kind":"Name","value":"PutEventAnnotation"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"input"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"PutUniverseAnnotationInput"}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"putUniverseAnnotation"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"input"},"value":{"kind":"Variable","name":{"kind":"Name","value":"input"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"universeAnnotation"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"annotation"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"slug"}}]}}]}}]}}]}}]} as unknown as DocumentNode; -export const ProgramAdminEventAnnotationsDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"ProgramAdminEventAnnotations"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"eventSlug"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}}},{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"locale"}},"type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"event"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"slug"},"value":{"kind":"Variable","name":{"kind":"Name","value":"eventSlug"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"slug"}},{"kind":"Field","name":{"kind":"Name","value":"timezone"}},{"kind":"Field","name":{"kind":"Name","value":"program"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"eventAnnotations"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"ProgramAdminEventAnnotation"}}]}}]}}]}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"ProgramAdminEventAnnotation"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"LimitedUniverseAnnotationType"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"annotation"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"slug"}},{"kind":"Field","name":{"kind":"Name","value":"title"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"lang"},"value":{"kind":"Variable","name":{"kind":"Name","value":"locale"}}}]},{"kind":"Field","name":{"kind":"Name","value":"description"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"lang"},"value":{"kind":"Variable","name":{"kind":"Name","value":"locale"}}}]},{"kind":"Field","name":{"kind":"Name","value":"type"}},{"kind":"Field","name":{"kind":"Name","value":"isComputed"}},{"kind":"Field","name":{"kind":"Name","value":"isPublic"}},{"kind":"Field","name":{"kind":"Name","value":"isShownInDetail"}},{"kind":"Field","name":{"kind":"Name","value":"isInternal"}},{"kind":"Field","name":{"kind":"Name","value":"isApplicableToProgramItems"}},{"kind":"Field","name":{"kind":"Name","value":"isApplicableToScheduleItems"}}]}},{"kind":"Field","name":{"kind":"Name","value":"isActive"}},{"kind":"Field","name":{"kind":"Name","value":"formFields"}}]}}]} as unknown as DocumentNode; +export const ProgramAdminEventAnnotationsDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"ProgramAdminEventAnnotations"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"eventSlug"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}}},{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"locale"}},"type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"event"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"slug"},"value":{"kind":"Variable","name":{"kind":"Name","value":"eventSlug"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"slug"}},{"kind":"Field","name":{"kind":"Name","value":"timezone"}},{"kind":"Field","name":{"kind":"Name","value":"program"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"eventAnnotations"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"ProgramAdminEventAnnotation"}}]}}]}}]}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"ProgramAdminEventAnnotation"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"LimitedUniverseAnnotationType"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"annotation"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"slug"}},{"kind":"Field","name":{"kind":"Name","value":"title"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"lang"},"value":{"kind":"Variable","name":{"kind":"Name","value":"locale"}}}]},{"kind":"Field","name":{"kind":"Name","value":"description"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"lang"},"value":{"kind":"Variable","name":{"kind":"Name","value":"locale"}}}]},{"kind":"Field","name":{"kind":"Name","value":"type"}},{"kind":"Field","name":{"kind":"Name","value":"isComputed"}},{"kind":"Field","name":{"kind":"Name","value":"isPublic"}},{"kind":"Field","name":{"kind":"Name","value":"isShownInDetail"}},{"kind":"Field","name":{"kind":"Name","value":"isInternal"}},{"kind":"Field","name":{"kind":"Name","value":"isApplicableToProgramItems"}},{"kind":"Field","name":{"kind":"Name","value":"isApplicableToScheduleItems"}}]}},{"kind":"Field","name":{"kind":"Name","value":"isActive"}}]}}]} as unknown as DocumentNode; export const PutProgramDimensionDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"mutation","name":{"kind":"Name","value":"PutProgramDimension"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"input"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"PutDimensionInput"}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"putDimension"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"input"},"value":{"kind":"Variable","name":{"kind":"Name","value":"input"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"dimension"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"slug"}}]}}]}}]}}]} as unknown as DocumentNode; export const DeleteProgramDimensionDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"mutation","name":{"kind":"Name","value":"DeleteProgramDimension"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"input"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"DeleteDimensionInput"}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"deleteDimension"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"input"},"value":{"kind":"Variable","name":{"kind":"Name","value":"input"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"slug"}}]}}]}}]} as unknown as DocumentNode; export const PutProgramDimensionValueDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"mutation","name":{"kind":"Name","value":"PutProgramDimensionValue"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"input"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"PutDimensionValueInput"}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"putDimensionValue"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"input"},"value":{"kind":"Variable","name":{"kind":"Name","value":"input"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"value"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"slug"}}]}}]}}]}}]} as unknown as DocumentNode; @@ -2283,7 +2282,7 @@ export const UpdateProgramFormLanguageDocument = {"kind":"Document","definitions export const DeleteProgramFormLanguageDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"mutation","name":{"kind":"Name","value":"DeleteProgramFormLanguage"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"input"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"DeleteSurveyLanguageInput"}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"deleteSurveyLanguage"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"input"},"value":{"kind":"Variable","name":{"kind":"Name","value":"input"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"language"}}]}}]}}]} as unknown as DocumentNode; export const UpdateFormFieldsMutationDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"mutation","name":{"kind":"Name","value":"UpdateFormFieldsMutation"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"input"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"UpdateFormFieldsInput"}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"updateFormFields"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"input"},"value":{"kind":"Variable","name":{"kind":"Name","value":"input"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"survey"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"slug"}}]}}]}}]}}]} as unknown as DocumentNode; export const PromoteProgramFormFieldToDimensionDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"mutation","name":{"kind":"Name","value":"PromoteProgramFormFieldToDimension"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"input"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"PromoteFieldToDimensionInput"}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"promoteFieldToDimension"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"input"},"value":{"kind":"Variable","name":{"kind":"Name","value":"input"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"survey"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"slug"}}]}}]}}]}}]} as unknown as DocumentNode; -export const EditProgramFormFieldsPageDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"EditProgramFormFieldsPage"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"eventSlug"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}}},{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"surveySlug"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}}},{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"language"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}}},{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"locale"}},"type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"event"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"slug"},"value":{"kind":"Variable","name":{"kind":"Name","value":"eventSlug"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"slug"}},{"kind":"Field","name":{"kind":"Name","value":"forms"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"survey"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"slug"},"value":{"kind":"Variable","name":{"kind":"Name","value":"surveySlug"}}},{"kind":"Argument","name":{"kind":"Name","value":"app"},"value":{"kind":"EnumValue","value":"PROGRAM"}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"EditSurveyFieldsPage"}}]}}]}}]}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"DimensionEditorValue"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"DimensionValueType"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"slug"}},{"kind":"Field","name":{"kind":"Name","value":"color"}},{"kind":"Field","name":{"kind":"Name","value":"isTechnical"}},{"kind":"Field","name":{"kind":"Name","value":"isSubjectLocked"}},{"kind":"Field","name":{"kind":"Name","value":"canRemove"}},{"kind":"Field","name":{"kind":"Name","value":"title"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"lang"},"value":{"kind":"Variable","name":{"kind":"Name","value":"locale"}}}]},{"kind":"Field","name":{"kind":"Name","value":"titleFi"}},{"kind":"Field","name":{"kind":"Name","value":"titleEn"}},{"kind":"Field","name":{"kind":"Name","value":"titleSv"}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"DimensionEditor"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"FullDimensionType"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"slug"}},{"kind":"Field","name":{"kind":"Name","value":"canRemove"}},{"kind":"Field","name":{"kind":"Name","value":"canAddValues"}},{"kind":"Field","name":{"kind":"Name","value":"title"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"lang"},"value":{"kind":"Variable","name":{"kind":"Name","value":"locale"}}}]},{"kind":"Field","name":{"kind":"Name","value":"isPublic"}},{"kind":"Field","name":{"kind":"Name","value":"isKeyDimension"}},{"kind":"Field","name":{"kind":"Name","value":"isMultiValue"}},{"kind":"Field","name":{"kind":"Name","value":"isListFilter"}},{"kind":"Field","name":{"kind":"Name","value":"isShownInDetail"}},{"kind":"Field","name":{"kind":"Name","value":"isNegativeSelection"}},{"kind":"Field","name":{"kind":"Name","value":"isTechnical"}},{"kind":"Field","name":{"kind":"Name","value":"valueOrdering"}},{"kind":"Field","name":{"kind":"Name","value":"titleFi"}},{"kind":"Field","name":{"kind":"Name","value":"titleEn"}},{"kind":"Field","name":{"kind":"Name","value":"titleSv"}},{"kind":"Field","name":{"kind":"Name","value":"values"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"DimensionEditorValue"}}]}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"EditSurveyFieldsPage"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"FullSurveyType"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"slug"}},{"kind":"Field","name":{"kind":"Name","value":"title"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"lang"},"value":{"kind":"Variable","name":{"kind":"Name","value":"locale"}}}]},{"kind":"Field","name":{"kind":"Name","value":"canRemove"}},{"kind":"Field","name":{"kind":"Name","value":"canGrantAccess"}},{"kind":"Field","name":{"kind":"Name","value":"purpose"}},{"kind":"Field","name":{"kind":"Name","value":"dimensions"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"DimensionEditor"}}]}},{"kind":"Field","name":{"kind":"Name","value":"form"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"lang"},"value":{"kind":"Variable","name":{"kind":"Name","value":"language"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"title"}},{"kind":"Field","name":{"kind":"Name","value":"language"}},{"kind":"Field","name":{"kind":"Name","value":"fields"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"enrich"},"value":{"kind":"BooleanValue","value":false}}]},{"kind":"Field","name":{"kind":"Name","value":"canRemove"}}]}},{"kind":"Field","name":{"kind":"Name","value":"languages"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"language"}}]}}]}}]} as unknown as DocumentNode; +export const EditProgramFormFieldsPageDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"EditProgramFormFieldsPage"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"eventSlug"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}}},{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"surveySlug"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}}},{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"language"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}}},{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"locale"}},"type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"event"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"slug"},"value":{"kind":"Variable","name":{"kind":"Name","value":"eventSlug"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"slug"}},{"kind":"Field","name":{"kind":"Name","value":"program"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"eventAnnotations"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"isActive"}},{"kind":"Field","name":{"kind":"Name","value":"annotation"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"slug"}},{"kind":"Field","name":{"kind":"Name","value":"title"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"lang"},"value":{"kind":"Variable","name":{"kind":"Name","value":"locale"}}}]},{"kind":"Field","name":{"kind":"Name","value":"isApplicableToProgramItems"}},{"kind":"Field","name":{"kind":"Name","value":"isApplicableToInvolvements"}}]}}]}}]}},{"kind":"Field","name":{"kind":"Name","value":"forms"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"survey"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"slug"},"value":{"kind":"Variable","name":{"kind":"Name","value":"surveySlug"}}},{"kind":"Argument","name":{"kind":"Name","value":"app"},"value":{"kind":"EnumValue","value":"PROGRAM"}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"EditSurveyFieldsPage"}}]}}]}}]}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"DimensionEditorValue"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"DimensionValueType"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"slug"}},{"kind":"Field","name":{"kind":"Name","value":"color"}},{"kind":"Field","name":{"kind":"Name","value":"isTechnical"}},{"kind":"Field","name":{"kind":"Name","value":"isSubjectLocked"}},{"kind":"Field","name":{"kind":"Name","value":"canRemove"}},{"kind":"Field","name":{"kind":"Name","value":"title"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"lang"},"value":{"kind":"Variable","name":{"kind":"Name","value":"locale"}}}]},{"kind":"Field","name":{"kind":"Name","value":"titleFi"}},{"kind":"Field","name":{"kind":"Name","value":"titleEn"}},{"kind":"Field","name":{"kind":"Name","value":"titleSv"}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"DimensionEditor"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"FullDimensionType"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"slug"}},{"kind":"Field","name":{"kind":"Name","value":"canRemove"}},{"kind":"Field","name":{"kind":"Name","value":"canAddValues"}},{"kind":"Field","name":{"kind":"Name","value":"title"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"lang"},"value":{"kind":"Variable","name":{"kind":"Name","value":"locale"}}}]},{"kind":"Field","name":{"kind":"Name","value":"isPublic"}},{"kind":"Field","name":{"kind":"Name","value":"isKeyDimension"}},{"kind":"Field","name":{"kind":"Name","value":"isMultiValue"}},{"kind":"Field","name":{"kind":"Name","value":"isListFilter"}},{"kind":"Field","name":{"kind":"Name","value":"isShownInDetail"}},{"kind":"Field","name":{"kind":"Name","value":"isNegativeSelection"}},{"kind":"Field","name":{"kind":"Name","value":"isTechnical"}},{"kind":"Field","name":{"kind":"Name","value":"valueOrdering"}},{"kind":"Field","name":{"kind":"Name","value":"titleFi"}},{"kind":"Field","name":{"kind":"Name","value":"titleEn"}},{"kind":"Field","name":{"kind":"Name","value":"titleSv"}},{"kind":"Field","name":{"kind":"Name","value":"values"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"DimensionEditorValue"}}]}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"EditSurveyFieldsPage"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"FullSurveyType"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"slug"}},{"kind":"Field","name":{"kind":"Name","value":"title"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"lang"},"value":{"kind":"Variable","name":{"kind":"Name","value":"locale"}}}]},{"kind":"Field","name":{"kind":"Name","value":"canRemove"}},{"kind":"Field","name":{"kind":"Name","value":"canGrantAccess"}},{"kind":"Field","name":{"kind":"Name","value":"purpose"}},{"kind":"Field","name":{"kind":"Name","value":"dimensions"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"DimensionEditor"}}]}},{"kind":"Field","name":{"kind":"Name","value":"form"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"lang"},"value":{"kind":"Variable","name":{"kind":"Name","value":"language"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"title"}},{"kind":"Field","name":{"kind":"Name","value":"language"}},{"kind":"Field","name":{"kind":"Name","value":"fields"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"enrich"},"value":{"kind":"BooleanValue","value":false}}]},{"kind":"Field","name":{"kind":"Name","value":"canRemove"}}]}},{"kind":"Field","name":{"kind":"Name","value":"languages"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"language"}}]}}]}}]} as unknown as DocumentNode; export const EditProgramFormLanguagePageDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"EditProgramFormLanguagePage"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"eventSlug"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}}},{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"surveySlug"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}}},{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"language"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}}},{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"locale"}},"type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"event"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"slug"},"value":{"kind":"Variable","name":{"kind":"Name","value":"eventSlug"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"slug"}},{"kind":"Field","name":{"kind":"Name","value":"forms"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"survey"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"slug"},"value":{"kind":"Variable","name":{"kind":"Name","value":"surveySlug"}}},{"kind":"Argument","name":{"kind":"Name","value":"app"},"value":{"kind":"EnumValue","value":"PROGRAM"}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"EditProgramFormLanguage"}}]}}]}}]}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"EditProgramFormLanguage"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"FullSurveyType"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"slug"}},{"kind":"Field","name":{"kind":"Name","value":"title"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"lang"},"value":{"kind":"Variable","name":{"kind":"Name","value":"locale"}}}]},{"kind":"Field","name":{"kind":"Name","value":"canRemove"}},{"kind":"Field","name":{"kind":"Name","value":"canGrantAccess"}},{"kind":"Field","name":{"kind":"Name","value":"purpose"}},{"kind":"Field","name":{"kind":"Name","value":"form"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"lang"},"value":{"kind":"Variable","name":{"kind":"Name","value":"language"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"title"}},{"kind":"Field","name":{"kind":"Name","value":"language"}},{"kind":"Field","name":{"kind":"Name","value":"description"}},{"kind":"Field","name":{"kind":"Name","value":"thankYouMessage"}},{"kind":"Field","name":{"kind":"Name","value":"fields"}},{"kind":"Field","name":{"kind":"Name","value":"canRemove"}}]}},{"kind":"Field","name":{"kind":"Name","value":"languages"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"language"}}]}}]}}]} as unknown as DocumentNode; export const CreateProgramFormLanguageDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"mutation","name":{"kind":"Name","value":"CreateProgramFormLanguage"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"input"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"CreateSurveyLanguageInput"}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"createSurveyLanguage"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"input"},"value":{"kind":"Variable","name":{"kind":"Name","value":"input"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"form"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"language"}}]}}]}}]}}]} as unknown as DocumentNode; export const UpdateProgramFormMutationDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"mutation","name":{"kind":"Name","value":"UpdateProgramFormMutation"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"input"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"UpdateSurveyInput"}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"updateProgramForm"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"input"},"value":{"kind":"Variable","name":{"kind":"Name","value":"input"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"survey"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"slug"}}]}}]}}]}}]} as unknown as DocumentNode; diff --git a/kompassi-v2-frontend/src/app/[locale]/[eventSlug]/program-annotations/actions.ts b/kompassi-v2-frontend/src/app/[locale]/[eventSlug]/program-annotations/actions.ts index 38eb44eee..84dad84d2 100644 --- a/kompassi-v2-frontend/src/app/[locale]/[eventSlug]/program-annotations/actions.ts +++ b/kompassi-v2-frontend/src/app/[locale]/[eventSlug]/program-annotations/actions.ts @@ -34,17 +34,11 @@ export async function putEventAnnotation( ? true : decodeBoolean((formData.get("isActive") as string | null) || "false"); - const formFields = ((formData.get("formFields") as string | null) || "") - .split("\n") - .map((field) => field.trim()) - .filter(Boolean); - const input = { scopeSlug: eventSlug, universeSlug, annotationSlug, isActive, - formFields, action, }; diff --git a/kompassi-v2-frontend/src/app/[locale]/[eventSlug]/program-annotations/page.tsx b/kompassi-v2-frontend/src/app/[locale]/[eventSlug]/program-annotations/page.tsx index 40b142b7b..07eb5f0a3 100644 --- a/kompassi-v2-frontend/src/app/[locale]/[eventSlug]/program-annotations/page.tsx +++ b/kompassi-v2-frontend/src/app/[locale]/[eventSlug]/program-annotations/page.tsx @@ -40,7 +40,6 @@ graphql(` isApplicableToScheduleItems } isActive - formFields } `); @@ -167,7 +166,6 @@ export default async function ProgramAdminAnnotationsPage(props: Props) { className: "col-6 py-3", getCellContents: (row) => { const slug = mangleAnnotationSlug(row.annotation.slug); - const formFields = row.formFields as string[]; const fields: Field[] = [ { slug: "isActive", @@ -175,17 +173,8 @@ export default async function ProgramAdminAnnotationsPage(props: Props) { title: t.attributes.isActive.checkboxLabel(row.annotation.slug), readOnly: row.annotation.slug.startsWith("internal:"), }, - { - slug: "formFields", - type: "MultiLineText", - rows: 5, - title: t.attributes.formFields.title, - }, ]; - const values = { - ...row, - formFields: formFields.join("\n") || "", - }; + const values = row; return (
{t.attributes.isActive.title}:{" "} {t.attributes.isActive.description}

-

- {t.attributes.formFields.title}:{" "} - {t.attributes.formFields.description} -

{t.eventAnnotationsAdmin.actions.saveWithoutRefresh.title}:{" "} {t.eventAnnotationsAdmin.actions.saveWithoutRefresh.description} diff --git a/kompassi-v2-frontend/src/app/[locale]/[eventSlug]/program-forms/[surveySlug]/edit/[language]/fields/page.tsx b/kompassi-v2-frontend/src/app/[locale]/[eventSlug]/program-forms/[surveySlug]/edit/[language]/fields/page.tsx index f0b646fb9..e030c1a4a 100644 --- a/kompassi-v2-frontend/src/app/[locale]/[eventSlug]/program-forms/[surveySlug]/edit/[language]/fields/page.tsx +++ b/kompassi-v2-frontend/src/app/[locale]/[eventSlug]/program-forms/[surveySlug]/edit/[language]/fields/page.tsx @@ -22,6 +22,18 @@ const query = graphql(` name slug + program { + eventAnnotations { + isActive + annotation { + slug + title(lang: $locale) + isApplicableToProgramItems + isApplicableToInvolvements + } + } + } + forms { survey(slug: $surveySlug, app: PROGRAM) { ...EditSurveyFieldsPage @@ -107,6 +119,10 @@ export default async function EditProgramFormFieldsPage(props: Props) { validateFields(form.fields); + const annotations = (data.event.program?.eventAnnotations ?? []) + .filter(({ isActive }) => isActive) + .map(({ annotation }) => annotation); + return ( { const t = messages.FormEditor.editFieldModal; const fields = getFieldEditorFields( fieldToEdit.type, messages.FormEditor.editFieldForm, dimensions, + annotations, + formContext, ); const handleSubmit = useCallback( diff --git a/kompassi-v2-frontend/src/components/forms/FormEditor.tsx b/kompassi-v2-frontend/src/components/forms/FormEditor.tsx index 5e33975ac..6c452bcba 100644 --- a/kompassi-v2-frontend/src/components/forms/FormEditor.tsx +++ b/kompassi-v2-frontend/src/components/forms/FormEditor.tsx @@ -3,6 +3,7 @@ import React from "react"; import AddFieldDropdown from "./AddFieldDropdown"; +import type { AnnotationOption, FormEditorContext } from "./editFieldForm"; import EditFieldModal from "./EditFieldModal"; import FormEditorControls from "./FormEditorControls"; import { addField, removeField, replaceField } from "./formEditorLogic"; @@ -25,6 +26,10 @@ interface Props { SchemaForm: Translations["SchemaForm"]; }; dimensions: DimensionValueSelectFragment[]; + /// Annotations that fields may pass their values forward to. + annotations?: AnnotationOption[]; + /// Where responses end up; survey responses have nothing to pass values forward to. + formContext?: FormEditorContext; } /// The end user facing SchemaForm operates on enriched fields @@ -81,6 +86,8 @@ export default function FormEditor(props: Props) { onPromoteFieldToDimension: onPromoteFieldToDimension, messages, dimensions, + annotations = [], + formContext = "survey", } = props; const t = messages.FormEditor; @@ -196,6 +203,8 @@ export default function FormEditor(props: Props) { }} onClose={() => setEditFieldModalOpen(false)} dimensions={dimensions} + annotations={annotations} + formContext={formContext} messages={messages} /> )} diff --git a/kompassi-v2-frontend/src/components/forms/FormEditorWrapper.tsx b/kompassi-v2-frontend/src/components/forms/FormEditorWrapper.tsx index e7ce4f398..4fba404bc 100644 --- a/kompassi-v2-frontend/src/components/forms/FormEditorWrapper.tsx +++ b/kompassi-v2-frontend/src/components/forms/FormEditorWrapper.tsx @@ -2,6 +2,7 @@ import { useCallback, useState } from "react"; import FormEditor from "./FormEditor"; +import type { AnnotationOption, FormEditorContext } from "./editFieldForm"; import { Field } from "./models"; import { DimensionValueSelectFragment } from "@/__generated__/graphql"; import type { Translations } from "@/translations/en"; @@ -9,6 +10,8 @@ import type { Translations } from "@/translations/en"; interface Props { initialFields: Field[]; dimensions: DimensionValueSelectFragment[]; + annotations?: AnnotationOption[]; + formContext?: FormEditorContext; messages: { FormEditor: Translations["FormEditor"]; SchemaForm: Translations["SchemaForm"]; @@ -25,6 +28,8 @@ export default function FormEditorWrapper({ onChange, onPromoteFieldToDimension: onPromoteFieldToDimension, dimensions, + annotations, + formContext, }: Props) { const [fields, setFields] = useState(initialFields); @@ -40,6 +45,8 @@ export default function FormEditorWrapper({ return ( + formContext === "involvement" + ? annotation.isApplicableToInvolvements + : annotation.isApplicableToProgramItems, + ); + propagationFields.push( + { + type: "SingleSelect", + slug: "propagateToAnnotation", + required: false, + presentation: "dropdown", + choices: [ + { slug: "", title: t.propagateToAnnotation.none }, + ...applicable.map(({ slug, title }) => ({ slug, title })), + ], + title: t.propagateToAnnotation.title, + helpText: t.propagateToAnnotation.helpText, + }, + { + type: "SingleCheckbox", + slug: "propagateToAnnotationOnEdit", + required: false, + ...t.propagateToAnnotationOnEdit, + }, + ); + } + } + const choicesField: Field = { type: "MultiLineText", slug: "choices", @@ -89,33 +165,38 @@ export function getFieldEditorFields( // ...t.encryptTo, // }; - switch (fieldType) { - case "SingleSelect": - case "MultiSelect": - return editableFieldFields.concat([choicesField]); // , encryptTo]); - case "DimensionSingleSelect": - case "DimensionMultiSelect": - case "DimensionSingleCheckbox": - return editableFieldFields.concat([dimensionField]); // , encryptTo]); - case "RadioMatrix": - return editableFieldFields.concat([ - questionsField, - choicesField, - // encryptTo, - ]); - case "MultiLineText": - case "MarkdownText": - return editableFieldFields.concat([maxLengthField]); - case "Divider": - case "Spacer": - return [slugField]; - case "StaticText": - return baseFieldEditorFields; - default: - // TODO implement encryption - return editableFieldFields; - // default: - // return baseFieldEditorFields.concat([encryptTo]); + const fields = getTypeSpecificFields(); + return fields.concat(propagationFields); + + function getTypeSpecificFields(): Field[] { + switch (fieldType) { + case "SingleSelect": + case "MultiSelect": + return editableFieldFields.concat([choicesField]); // , encryptTo]); + case "DimensionSingleSelect": + case "DimensionMultiSelect": + case "DimensionSingleCheckbox": + return editableFieldFields.concat([dimensionField]); // , encryptTo]); + case "RadioMatrix": + return editableFieldFields.concat([ + questionsField, + choicesField, + // encryptTo, + ]); + case "MultiLineText": + case "MarkdownText": + return editableFieldFields.concat([maxLengthField]); + case "Divider": + case "Spacer": + return [slugField]; + case "StaticText": + return baseFieldEditorFields; + default: + // TODO implement encryption + return editableFieldFields; + // default: + // return baseFieldEditorFields.concat([encryptTo]); + } } } diff --git a/kompassi-v2-frontend/src/components/forms/models.ts b/kompassi-v2-frontend/src/components/forms/models.ts index 3a8674d32..b16806598 100644 --- a/kompassi-v2-frontend/src/components/forms/models.ts +++ b/kompassi-v2-frontend/src/components/forms/models.ts @@ -74,6 +74,10 @@ interface BaseField { isKeyField?: boolean; htmlType?: HtmlType; encryptTo?: string[]; + propagateDimensionOnCreate?: boolean; + propagateDimensionOnEdit?: boolean; + propagateToAnnotation?: string; + propagateToAnnotationOnEdit?: boolean; } export interface Divider extends BaseField { diff --git a/kompassi-v2-frontend/src/translations/en.tsx b/kompassi-v2-frontend/src/translations/en.tsx index bc0c4cdc7..82ff91ef1 100644 --- a/kompassi-v2-frontend/src/translations/en.tsx +++ b/kompassi-v2-frontend/src/translations/en.tsx @@ -257,6 +257,27 @@ const translations = { title: "Key field", helpText: "Key fields are shown in the response list.", }, + propagateDimensionOnCreate: { + title: "Pass value forward on create", + helpText: + "When the response is created, set the corresponding dimension of the target object (eg. the program item or the involvement) to this value.", + }, + propagateDimensionOnEdit: { + title: "Pass value forward on edit", + helpText: + "When the response is edited, update the corresponding dimension of the target object.", + }, + propagateToAnnotation: { + title: "Pass value forward to annotation", + helpText: + "Set this annotation of the target object (eg. the program item or the involvement) to the value of this field.", + none: "(do not pass forward)", + }, + propagateToAnnotationOnEdit: { + title: "Also pass forward on edit", + helpText: + "Update the annotation also when the response is edited, not just when it is created.", + }, choices: { title: "Choices", helpText: @@ -2501,16 +2522,6 @@ const translations = { isShownInDetail: { title: "Shown in program guide", }, - formFields: { - title: "Program form fields", - description: ( - <> - Slugs of program form fields values for this annotation will be - extracted from. One per line, in order: the first field that has a - nonempty value of an appropriate type will be used. - - ), - }, properties: { title: "Properties", }, diff --git a/kompassi-v2-frontend/src/translations/fi.tsx b/kompassi-v2-frontend/src/translations/fi.tsx index 09335735a..2292f91aa 100644 --- a/kompassi-v2-frontend/src/translations/fi.tsx +++ b/kompassi-v2-frontend/src/translations/fi.tsx @@ -263,6 +263,27 @@ const translations: Translations = { title: "Avainkenttä", helpText: "Avainkentät näytetään vastauslistassa.", }, + propagateDimensionOnCreate: { + title: "Välitä arvo eteenpäin luotaessa", + helpText: + "Kun vastaus luodaan, aseta kohdeobjektin (esim. ohjelmanumeron tai osallisuuden) vastaava ulottuvuus tähän arvoon.", + }, + propagateDimensionOnEdit: { + title: "Välitä arvo eteenpäin muokattaessa", + helpText: + "Kun vastausta muokataan, päivitä kohdeobjektin vastaava ulottuvuus.", + }, + propagateToAnnotation: { + title: "Välitä arvo lisätietoon", + helpText: + "Aseta kohdeobjektin (esim. ohjelmanumeron tai osallisuuden) tämä lisätieto tämän kentän arvoon.", + none: "(ei välitetä eteenpäin)", + }, + propagateToAnnotationOnEdit: { + title: "Välitä myös muokattaessa", + helpText: + "Päivitä lisätieto myös kun vastausta muokataan, ei vain kun se luodaan.", + }, choices: { title: "Vaihtoehdot", helpText: @@ -2439,17 +2460,6 @@ const translations: Translations = { isInternal: { title: "Sisäinen", }, - formFields: { - title: "Lähdekentät ohjelmalomakkeilla", - description: ( - <> - Niiden lomakekenttien tekniset nimet, joista tämän lisätiedon arvoja - yritetään kaivella. Yksi per rivi, järjestys merkitsee: lisätiedon - arvon määrittelee ensimmäinen näistä kentistä jolla on - oikeantyyppinen, epätyhjä arvo. - - ), - }, properties: { title: "Ominaisuudet", }, diff --git a/kompassi-v2-frontend/src/translations/sv.tsx b/kompassi-v2-frontend/src/translations/sv.tsx index 44e7905d8..003c94ff0 100644 --- a/kompassi-v2-frontend/src/translations/sv.tsx +++ b/kompassi-v2-frontend/src/translations/sv.tsx @@ -253,6 +253,27 @@ const translations: Translations = { title: "Nyckelfält", helpText: "Nyckelfält visas i svarslistan.", }, + propagateDimensionOnCreate: { + title: "Skicka värdet vidare vid skapande", + helpText: + "När svaret skapas, sätt motsvarande dimension hos målobjektet (t.ex. programpunkten eller delaktigheten) till detta värde.", + }, + propagateDimensionOnEdit: { + title: "Skicka värdet vidare vid redigering", + helpText: + "När svaret redigeras, uppdatera motsvarande dimension hos målobjektet.", + }, + propagateToAnnotation: { + title: "Skicka värdet vidare till anteckning", + helpText: + "Sätt denna anteckning hos målobjektet (t.ex. programpunkten eller delaktigheten) till fältets värde.", + none: "(skicka inte vidare)", + }, + propagateToAnnotationOnEdit: { + title: "Skicka vidare även vid redigering", + helpText: + "Uppdatera anteckningen även när svaret redigeras, inte bara när det skapas.", + }, choices: { title: "Val", helpText: @@ -2443,16 +2464,6 @@ const translations: Translations = { }, isInternal: { title: "Intern" }, isShownInDetail: { title: "Visas i programguiden" }, - formFields: { - title: "Programformulärsfält", - description: ( - <> - Tekniska namn på programformulärsfält vars värden extraheras för - denna anteckning. Ett per rad, i ordning: det första fältet med ett - icke-tomt värde av lämplig typ används. - - ), - }, properties: { title: "Egenskaper" }, actions: { title: "Funktioner" }, }, diff --git a/kompassi/core/pseudonymization.py b/kompassi/core/pseudonymization.py index edefd02e6..4aee0370f 100644 --- a/kompassi/core/pseudonymization.py +++ b/kompassi/core/pseudonymization.py @@ -315,7 +315,6 @@ def pseudonymize_responses(model: type[models.Model]) -> str: "programme.Role": "perks", "programme.SpecialReservation": "code", "programme.Tag": "v2_dimensions", - "dimensions.UniverseAnnotation": "form_fields", "involvement.InvolvementToGroupMapping": "required_dimensions", "involvement.InvolvementToBadgeMapping": "required_dimensions annotations", "badges.SurveyToBadgeMapping": "required_dimensions annotations", diff --git a/kompassi/dimensions/graphql/annotation.py b/kompassi/dimensions/graphql/annotation.py index a927180b9..08d618c65 100644 --- a/kompassi/dimensions/graphql/annotation.py +++ b/kompassi/dimensions/graphql/annotation.py @@ -28,3 +28,4 @@ class Meta: is_computed = graphene.NonNull(graphene.Boolean) is_applicable_to_program_items = graphene.NonNull(graphene.Boolean) is_applicable_to_schedule_items = graphene.NonNull(graphene.Boolean) + is_applicable_to_involvements = graphene.NonNull(graphene.Boolean) diff --git a/kompassi/dimensions/graphql/mutations/put_universe_annotation.py b/kompassi/dimensions/graphql/mutations/put_universe_annotation.py index 18ce49235..4367173c0 100644 --- a/kompassi/dimensions/graphql/mutations/put_universe_annotation.py +++ b/kompassi/dimensions/graphql/mutations/put_universe_annotation.py @@ -1,7 +1,6 @@ from enum import Enum import graphene -import pydantic from django.db import transaction from django.http import HttpRequest @@ -13,10 +12,6 @@ from ...tasks import universe_annotation_refresh_values from ..universe_annotation_limited import LimitedUniverseAnnotationType -# too strict, users will be confounded -# ListOfSlugsAdapter = pydantic.TypeAdapter(list[Slug]) -ListOfSlugsAdapter = pydantic.TypeAdapter(list[str]) - class PutUniverseAnnotationAction(Enum): SAVE_WITHOUT_REFRESH = "SAVE_WITHOUT_REFRESH" @@ -31,10 +26,6 @@ class PutUniverseAnnotationInput(graphene.InputObjectType): universe_slug = graphene.String(required=True) annotation_slug = graphene.String(required=True) is_active = graphene.Boolean(required=True) - form_fields = graphene.InputField( - graphene.List(graphene.NonNull(graphene.String)), - required=True, - ) action = graphene.InputField(PutUniverseAnnotationActionType) @@ -68,8 +59,6 @@ def mutate( if annotation.is_internal and not input.is_active: raise ValueError("Internal annotations cannot be deactivated.") - form_fields = ListOfSlugsAdapter.validate_python(input.form_fields) - if input.action: action = PutUniverseAnnotationAction(input.action) else: @@ -82,10 +71,7 @@ def mutate( ).update_or_create( universe=universe, annotation=annotation, - defaults=dict( - is_active=input.is_active, - form_fields=form_fields, - ), + defaults=dict(is_active=input.is_active), ) match action: diff --git a/kompassi/dimensions/graphql/universe_annotation_limited.py b/kompassi/dimensions/graphql/universe_annotation_limited.py index 28297371b..948ca4d6f 100644 --- a/kompassi/dimensions/graphql/universe_annotation_limited.py +++ b/kompassi/dimensions/graphql/universe_annotation_limited.py @@ -1,4 +1,3 @@ -from graphene.types.generic import GenericScalar from graphene_django import DjangoObjectType from ..models.universe_annotation import UniverseAnnotation @@ -10,7 +9,4 @@ class Meta: fields = ( "annotation", "is_active", - "form_fields", ) - - form_fields = GenericScalar() diff --git a/kompassi/dimensions/migrations/0020_propagate_annotation_form_fields_to_forms.py b/kompassi/dimensions/migrations/0020_propagate_annotation_form_fields_to_forms.py new file mode 100644 index 000000000..bc681dde6 --- /dev/null +++ b/kompassi/dimensions/migrations/0020_propagate_annotation_form_fields_to_forms.py @@ -0,0 +1,70 @@ +import logging + +from django.db import migrations + +logger = logging.getLogger(__name__) + +# keep in sync with FieldType.can_propagate_to_annotation (frozen here so the migration stays stable) +PROPAGATABLE_TYPES = { + "SingleLineText", + "MultiLineText", + "MarkdownText", + "SingleCheckbox", + "NumberField", + "DecimalField", + "DateField", + "TimeField", + "DateTimeField", +} + + +def propagate_form_fields_to_forms(apps, schema_editor): + UniverseAnnotation = apps.get_model("dimensions", "UniverseAnnotation") + Form = apps.get_model("forms", "Form") + + for universe_annotation in UniverseAnnotation.objects.exclude(form_fields=[]).select_related("annotation"): + annotation_slug = universe_annotation.annotation.slug + wanted_slugs = universe_annotation.form_fields + + for form in Form.objects.filter(survey__universe_id=universe_annotation.universe_id): + changed = False + for field_list in (form.fields, form.cached_enriched_fields): + claimed = False + # first wanted slug that exists in this form wins, as in the old extractor + for wanted_slug in wanted_slugs: + for field in field_list: + if field.get("slug") != wanted_slug: + continue + if field.get("type") not in PROPAGATABLE_TYPES: + logger.warning( + "Form %s: field %s of type %s cannot propagate to annotation %s", + form.id, + wanted_slug, + field.get("type"), + annotation_slug, + ) + continue + if claimed: + logger.warning( + "Form %s: field %s also fed annotation %s; only the first is kept", + form.id, + wanted_slug, + annotation_slug, + ) + continue + field["propagateToAnnotation"] = annotation_slug + claimed = changed = True + if changed: + form.save(update_fields=["fields", "cached_enriched_fields"]) + + +class Migration(migrations.Migration): + dependencies = [ # noqa: RUF012 + ("dimensions", "0019_rename_universe_app_name_to_app"), + ("forms", "0058_survey_retention_period"), + ] + + operations = [ # noqa: RUF012 + migrations.RunPython(propagate_form_fields_to_forms, migrations.RunPython.noop), + migrations.RemoveField(model_name="universeannotation", name="form_fields"), + ] diff --git a/kompassi/dimensions/models/universe_annotation.py b/kompassi/dimensions/models/universe_annotation.py index 2d48b5c56..ae6dd6bce 100644 --- a/kompassi/dimensions/models/universe_annotation.py +++ b/kompassi/dimensions/models/universe_annotation.py @@ -26,10 +26,6 @@ class UniverseAnnotation(models.Model): ) is_active = models.BooleanField(default=True) - form_fields = models.JSONField( - default=list, - help_text="Slugs of form fields to extract values from.", - ) class Meta: unique_together = ("universe", "annotation") diff --git a/kompassi/forms/models/field.py b/kompassi/forms/models/field.py index 4cfe1021e..d59a9592d 100644 --- a/kompassi/forms/models/field.py +++ b/kompassi/forms/models/field.py @@ -49,6 +49,24 @@ def are_attachments_allowed(self) -> bool: """ return self == FieldType.FILE_UPLOAD + @property + def can_propagate_to_annotation(self) -> bool: + """ + Returns True iff the value of this field is a scalar string, number, date or boolean + and can thus be passed forward to an annotation. + """ + return self in ( + FieldType.SINGLE_LINE_TEXT, + FieldType.MULTI_LINE_TEXT, + FieldType.MARKDOWN_TEXT, + FieldType.SINGLE_CHECKBOX, + FieldType.NUMBER_FIELD, + FieldType.DECIMAL_FIELD, + FieldType.DATE_FIELD, + FieldType.TIME_FIELD, + FieldType.DATE_TIME_FIELD, + ) + @property def is_dimension_field(self) -> bool: """ @@ -169,6 +187,46 @@ class Field(pydantic.BaseModel, populate_by_name=True): repr=False, ) + propagate_dimension_on_create: bool | None = pydantic.Field( + default=None, + validation_alias="propagateDimensionOnCreate", + serialization_alias="propagateDimensionOnCreate", + repr=False, + ) + propagate_dimension_on_edit: bool | None = pydantic.Field( + default=None, + validation_alias="propagateDimensionOnEdit", + serialization_alias="propagateDimensionOnEdit", + repr=False, + ) + propagate_to_annotation: str | None = pydantic.Field( + default=None, + validation_alias="propagateToAnnotation", + serialization_alias="propagateToAnnotation", + repr=False, + ) + propagate_to_annotation_on_edit: bool | None = pydantic.Field( + default=None, + validation_alias="propagateToAnnotationOnEdit", + serialization_alias="propagateToAnnotationOnEdit", + repr=False, + ) + + @pydantic.model_validator(mode="after") + def validate_propagation(self) -> Field: + wants_dimension = self.propagate_dimension_on_create or self.propagate_dimension_on_edit + if wants_dimension and not self.type.is_dimension_field: + raise ValueError(f"Field {self.slug}: only Dimension* fields can propagate dimension values") + + wants_annotation = self.propagate_to_annotation or self.propagate_to_annotation_on_edit + if wants_annotation and not self.type.can_propagate_to_annotation: + raise ValueError(f"Field {self.slug}: {self.type} fields cannot propagate to an annotation") + + if self.propagate_to_annotation_on_edit and not self.propagate_to_annotation: + raise ValueError(f"Field {self.slug}: propagateToAnnotationOnEdit requires propagateToAnnotation") + + return self + @classmethod def from_dimension( cls, diff --git a/kompassi/forms/tests.py b/kompassi/forms/tests.py index 01eddae6e..9eb758fbf 100644 --- a/kompassi/forms/tests.py +++ b/kompassi/forms/tests.py @@ -1,6 +1,7 @@ from datetime import datetime, timedelta from types import SimpleNamespace +import pydantic import pytest import yaml from django.contrib.auth import get_user_model @@ -2060,3 +2061,26 @@ def test_grantee_can_manage_dimensions_only_in_the_granted_surveys_universe(): assert survey_a.universe.can_dimensions_be_created_by(_cached_request(grantee.user)) assert not survey_b.universe.can_dimensions_be_created_by(_cached_request(grantee.user)) + + +def test_field_propagation_config_is_validated(): + ok = Field.model_validate( + dict( + slug="max", + type="NumberField", + propagateToAnnotation="konsti:maxAttendance", + propagateToAnnotationOnEdit=True, + ) + ) + assert ok.propagate_to_annotation == "konsti:maxAttendance" + + Field.model_validate(dict(slug="d", type="DimensionSingleSelect", dimension="d", propagateDimensionOnCreate=True)) + + with pytest.raises(pydantic.ValidationError): + Field.model_validate(dict(slug="d", type="DimensionSingleSelect", dimension="d", propagateToAnnotation="x:y")) + + with pytest.raises(pydantic.ValidationError): + Field.model_validate(dict(slug="s", type="SingleSelect", propagateDimensionOnCreate=True)) + + with pytest.raises(pydantic.ValidationError): + Field.model_validate(dict(slug="n", type="NumberField", propagateToAnnotationOnEdit=True)) diff --git a/kompassi/forms/utils/extract_annotations.py b/kompassi/forms/utils/extract_annotations.py index 7d7bbdef7..63318ccbe 100644 --- a/kompassi/forms/utils/extract_annotations.py +++ b/kompassi/forms/utils/extract_annotations.py @@ -1,7 +1,6 @@ import logging from collections.abc import Iterable -from kompassi.dimensions.models.annotation import Annotation from kompassi.dimensions.models.cached_annotations import CachedAnnotations from kompassi.dimensions.models.universe_annotation import UniverseAnnotation @@ -13,53 +12,62 @@ def extract_annotations_from_responses( responses: Iterable[Response], universe_annotations: Iterable[UniverseAnnotation], + *, + on_edit: bool = False, ) -> CachedAnnotations: - schema: list[Annotation] = [] - field_mapping: dict[str, list[str]] = {} - interesting_fields: set[str] = set() - - for ea in universe_annotations: - schema.append(ea.annotation) - field_mapping[ea.annotation.slug] = ea.form_fields - interesting_fields.update(ea.form_fields) + """ + Collects annotation values from fields that declare `propagate_to_annotation`. + Annotations not active in the given universe annotations are ignored. + When several fields target the same annotation, the first field with a usable value wins. + """ + schema = {ua.annotation.slug: ua.annotation for ua in universe_annotations} result: CachedAnnotations = {} for response in responses: fields = response.form.validated_fields - values, warnings = response.get_processed_form_data(fields=fields, field_slugs=interesting_fields) - form_fields_by_slug = {field.slug: field for field in fields} - - for annotation in schema: - for form_field_slug in field_mapping[annotation.slug]: - form_field = form_fields_by_slug.get(form_field_slug) - if form_field is None: - # this form does not have this field - continue - - value = values.get(form_field_slug) - if value is None: - # no value for this field in this response - continue - - if field_warnings := warnings.get(form_field_slug): - logger.info( - "Cowardly refusing to look for value for annotation in a field with warnings: %s", - dict( - response=response.id, - annotation_slug=annotation.slug, - form_field_slug=form_field_slug, - field_warnings=field_warnings, - ), - ) - continue - - value = annotation.type.conform_value(value) - if value is None: - # value did not conform to the data type of the annotation - continue - - result[annotation.slug] = value - break + propagating_fields = [ + field + for field in fields + if field.propagate_to_annotation in schema and (not on_edit or field.propagate_to_annotation_on_edit) + ] + if not propagating_fields: + continue + + values, warnings = response.get_processed_form_data( + fields=fields, + field_slugs={field.slug for field in propagating_fields}, + ) + + response_result: CachedAnnotations = {} + for field in propagating_fields: + annotation = schema[str(field.propagate_to_annotation)] + + if annotation.slug in response_result: + continue + + value = values.get(field.slug) + if value is None: + continue + + if field_warnings := warnings.get(field.slug): + logger.info( + "Cowardly refusing to look for value for annotation in a field with warnings: %s", + dict( + response=response.id, + annotation_slug=annotation.slug, + form_field_slug=field.slug, + field_warnings=field_warnings, + ), + ) + continue + + value = annotation.type.conform_value(value) + if value is None: + continue + + response_result[annotation.slug] = value + + result.update(response_result) return result diff --git a/kompassi/program_v2/tests.py b/kompassi/program_v2/tests.py index 3a98eb094..eb6c42105 100644 --- a/kompassi/program_v2/tests.py +++ b/kompassi/program_v2/tests.py @@ -213,6 +213,7 @@ def test_extract_annotations(): title="Max participants", type="NumberField", required=False, + propagateToAnnotation="konsti:maxAttendance", ), ], ) @@ -238,12 +239,14 @@ def test_extract_annotations(): title="Max participants", type="NumberField", required=False, + propagateToAnnotation="konsti:maxAttendance", ), dict( slug="is_revolving_door", title="Is revolving door", type="SingleCheckbox", required=False, + propagateToAnnotation="ropecon:isRevolvingDoor", ), ], ) @@ -269,11 +272,6 @@ def test_extract_annotations(): annotation=Annotation.objects.get(slug="konsti:maxAttendance"), defaults=dict( is_active=True, - form_fields=[ - "this_field_does_not_exist", - "max_participants", - "also_this_field_does_not_exist", - ], ), ) assert not created @@ -283,11 +281,6 @@ def test_extract_annotations(): annotation=Annotation.objects.get(slug="ropecon:isRevolvingDoor"), defaults=dict( is_active=True, - form_fields=[ - "this_field_does_not_exist", - "is_revolving_door", - "also_this_field_does_not_exist", - ], ), ) assert not created From ed2af9171bafd57555836aa61466bf6dc8e383d4 Mon Sep 17 00:00:00 2001 From: Luka Pajukanta Date: Fri, 2 Oct 2026 16:32:11 +0300 Subject: [PATCH 2/7] Address review: normalize on-edit flag, honor is_active and on_edit in extraction Co-Authored-By: Claude Sonnet 5.5 --- .../src/components/forms/editFieldForm.ts | 8 ++++++++ kompassi/forms/utils/extract_annotations.py | 2 +- kompassi/program_v2/workflows/program_host_invitation.py | 1 + 3 files changed, 10 insertions(+), 1 deletion(-) diff --git a/kompassi-v2-frontend/src/components/forms/editFieldForm.ts b/kompassi-v2-frontend/src/components/forms/editFieldForm.ts index 7bdbc12b9..34d426ae3 100644 --- a/kompassi-v2-frontend/src/components/forms/editFieldForm.ts +++ b/kompassi-v2-frontend/src/components/forms/editFieldForm.ts @@ -247,6 +247,14 @@ export function formDataToField( encryptTo: ((formData.get("encryptTo") as string) || "").split("\n"), }; + // the backend rejects "on edit" without an annotation to pass forward to + if ( + "propagateToAnnotationOnEdit" in values && + !values.propagateToAnnotation + ) { + values.propagateToAnnotationOnEdit = false; + } + switch (initialValues.type) { case "SingleSelect": case "MultiSelect": diff --git a/kompassi/forms/utils/extract_annotations.py b/kompassi/forms/utils/extract_annotations.py index 63318ccbe..2829a9c8d 100644 --- a/kompassi/forms/utils/extract_annotations.py +++ b/kompassi/forms/utils/extract_annotations.py @@ -20,7 +20,7 @@ def extract_annotations_from_responses( Annotations not active in the given universe annotations are ignored. When several fields target the same annotation, the first field with a usable value wins. """ - schema = {ua.annotation.slug: ua.annotation for ua in universe_annotations} + schema = {ua.annotation.slug: ua.annotation for ua in universe_annotations if ua.is_active} result: CachedAnnotations = {} diff --git a/kompassi/program_v2/workflows/program_host_invitation.py b/kompassi/program_v2/workflows/program_host_invitation.py index 19869000f..27562820c 100644 --- a/kompassi/program_v2/workflows/program_host_invitation.py +++ b/kompassi/program_v2/workflows/program_host_invitation.py @@ -68,6 +68,7 @@ def handle_new_response_phase2( extract_annotations_from_responses( program.responses.all(), program.universe.active_universe_annotations.all(), + on_edit=old_version is not None, ) ) program.refresh_dependents() From d1c4e88696ad4fe61d2a77161a5676cc11198738 Mon Sep 17 00:00:00 2001 From: Luka Pajukanta Date: Fri, 2 Oct 2026 16:58:55 +0300 Subject: [PATCH 3/7] Address review: keep edit propagation in migration, filter annotations by universe Co-Authored-By: Claude Sonnet 5.5 --- ...opagate_annotation_form_fields_to_forms.py | 2 + kompassi/forms/tests.py | 39 +++++++++++++++++++ kompassi/forms/utils/extract_annotations.py | 26 ++++++++++++- 3 files changed, 65 insertions(+), 2 deletions(-) diff --git a/kompassi/dimensions/migrations/0020_propagate_annotation_form_fields_to_forms.py b/kompassi/dimensions/migrations/0020_propagate_annotation_form_fields_to_forms.py index bc681dde6..e6d4ab368 100644 --- a/kompassi/dimensions/migrations/0020_propagate_annotation_form_fields_to_forms.py +++ b/kompassi/dimensions/migrations/0020_propagate_annotation_form_fields_to_forms.py @@ -53,6 +53,8 @@ def propagate_form_fields_to_forms(apps, schema_editor): ) continue field["propagateToAnnotation"] = annotation_slug + # the old extractor also ran after edits + field["propagateToAnnotationOnEdit"] = True claimed = changed = True if changed: form.save(update_fields=["fields", "cached_enriched_fields"]) diff --git a/kompassi/forms/tests.py b/kompassi/forms/tests.py index 9eb758fbf..cafb2e840 100644 --- a/kompassi/forms/tests.py +++ b/kompassi/forms/tests.py @@ -2084,3 +2084,42 @@ def test_field_propagation_config_is_validated(): with pytest.raises(pydantic.ValidationError): Field.model_validate(dict(slug="n", type="NumberField", propagateToAnnotationOnEdit=True)) + + +@pytest.mark.django_db +def test_extract_annotations_ignores_annotations_not_applicable_to_the_universe(): + from kompassi.dimensions.models.annotation import Annotation + from kompassi.dimensions.models.enums import AnnotationAppliesTo, AnnotationDataType + from kompassi.dimensions.models.universe_annotation import UniverseAnnotation + from kompassi.program_v2.models.meta import ProgramV2EventMeta + + from .utils.extract_annotations import extract_annotations_from_responses + + meta, _ = ProgramV2EventMeta.get_or_create_dummy() + event = meta.event + + survey = Survey(event=event, slug="offer", app=DimensionApp.PROGRAM, purpose=SurveyPurpose.DEFAULT) + survey.with_mandatory_fields().save() + form = Form.objects.create( + event=event, + survey=survey, + language="en", + fields=[ + dict(slug="a", type="SingleLineText", propagateToAnnotation="test:programNote"), + dict(slug="b", type="SingleLineText", propagateToAnnotation="test:hostNote"), + ], + ) + response = Response.objects.create(form=form, form_data={"a": "x", "b": "y"}) + + universe_annotations = [ + UniverseAnnotation.objects.create( + universe=meta.universe, + annotation=Annotation.objects.create(slug=slug, type=AnnotationDataType.STRING, applies_to=applies_to), + ) + for slug, applies_to in ( + ("test:programNote", AnnotationAppliesTo.PROGRAM_ITEM), + ("test:hostNote", AnnotationAppliesTo.INVOLVEMENT), + ) + ] + + assert extract_annotations_from_responses([response], universe_annotations) == {"test:programNote": "x"} diff --git a/kompassi/forms/utils/extract_annotations.py b/kompassi/forms/utils/extract_annotations.py index 2829a9c8d..881fe6206 100644 --- a/kompassi/forms/utils/extract_annotations.py +++ b/kompassi/forms/utils/extract_annotations.py @@ -1,7 +1,10 @@ import logging from collections.abc import Iterable +from kompassi.dimensions.models.annotation import Annotation from kompassi.dimensions.models.cached_annotations import CachedAnnotations +from kompassi.dimensions.models.enums import DimensionApp +from kompassi.dimensions.models.universe import Universe from kompassi.dimensions.models.universe_annotation import UniverseAnnotation from ..models.response import Response @@ -17,10 +20,19 @@ def extract_annotations_from_responses( ) -> CachedAnnotations: """ Collects annotation values from fields that declare `propagate_to_annotation`. - Annotations not active in the given universe annotations are ignored. + Annotations not active in the given universe annotations are ignored, as are annotations + that do not apply to the kind of object the universe holds (every annotation is + activated in every universe, so eg. an involvement-only annotation could otherwise + end up on a program item). When several fields target the same annotation, the first field with a usable value wins. """ - schema = {ua.annotation.slug: ua.annotation for ua in universe_annotations if ua.is_active} + active = [ua for ua in universe_annotations if ua.is_active] + universe_apps = dict(Universe.objects.filter(id__in={ua.universe_id for ua in active}).values_list("id", "app")) + schema = { + ua.annotation.slug: ua.annotation + for ua in active + if _is_applicable_in_universe(ua.annotation, universe_apps[ua.universe_id]) + } result: CachedAnnotations = {} @@ -71,3 +83,13 @@ def extract_annotations_from_responses( result.update(response_result) return result + + +def _is_applicable_in_universe(annotation: Annotation, app: DimensionApp) -> bool: + match app: + case DimensionApp.PROGRAM: + return annotation.is_applicable_to_program_items + case DimensionApp.INVOLVEMENT: + return annotation.is_applicable_to_involvements + case _: + return True From 19fcaeacedcf7209392284a28b73d830bb0fbeff Mon Sep 17 00:00:00 2001 From: Luka Pajukanta Date: Fri, 2 Oct 2026 17:18:15 +0300 Subject: [PATCH 4/7] Address review: legacy-compatible annotation context for INVITE forms Co-Authored-By: Claude Sonnet 5.5 --- .../[surveySlug]/edit/[language]/fields/page.tsx | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/kompassi-v2-frontend/src/app/[locale]/[eventSlug]/program-forms/[surveySlug]/edit/[language]/fields/page.tsx b/kompassi-v2-frontend/src/app/[locale]/[eventSlug]/program-forms/[surveySlug]/edit/[language]/fields/page.tsx index e030c1a4a..ad22e1a3f 100644 --- a/kompassi-v2-frontend/src/app/[locale]/[eventSlug]/program-forms/[surveySlug]/edit/[language]/fields/page.tsx +++ b/kompassi-v2-frontend/src/app/[locale]/[eventSlug]/program-forms/[surveySlug]/edit/[language]/fields/page.tsx @@ -134,7 +134,11 @@ export default async function EditProgramFormFieldsPage(props: Props) { initialFields={form.fields} dimensions={dimensions} annotations={annotations} - formContext={survey.purpose === "DEFAULT" ? "program" : "involvement"} + formContext={ + survey.purpose === "DEFAULT" || survey.purpose === "INVITE" + ? "program" + : "involvement" + } messages={{ FormEditor: translations.FormEditor, SchemaForm: translations.SchemaForm, From c1b22db95caec11036a80bc06262e9219d76d671 Mon Sep 17 00:00:00 2001 From: Luka Pajukanta Date: Fri, 2 Oct 2026 20:49:55 +0300 Subject: [PATCH 5/7] Use dimensio for dimension in Finnish translations Co-Authored-By: Claude Sonnet 5.5 --- kompassi-v2-frontend/src/translations/fi.tsx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/kompassi-v2-frontend/src/translations/fi.tsx b/kompassi-v2-frontend/src/translations/fi.tsx index 2292f91aa..08af7e8dc 100644 --- a/kompassi-v2-frontend/src/translations/fi.tsx +++ b/kompassi-v2-frontend/src/translations/fi.tsx @@ -266,12 +266,12 @@ const translations: Translations = { propagateDimensionOnCreate: { title: "Välitä arvo eteenpäin luotaessa", helpText: - "Kun vastaus luodaan, aseta kohdeobjektin (esim. ohjelmanumeron tai osallisuuden) vastaava ulottuvuus tähän arvoon.", + "Kun vastaus luodaan, aseta kohdeobjektin (esim. ohjelmanumeron tai osallisuuden) vastaava dimensio tähän arvoon.", }, propagateDimensionOnEdit: { title: "Välitä arvo eteenpäin muokattaessa", helpText: - "Kun vastausta muokataan, päivitä kohdeobjektin vastaava ulottuvuus.", + "Kun vastausta muokataan, päivitä kohdeobjektin vastaava dimensio.", }, propagateToAnnotation: { title: "Välitä arvo lisätietoon", From a5b6b0961df899f23a7dfcbf544f12cb92fe972b Mon Sep 17 00:00:00 2001 From: Luka Pajukanta Date: Fri, 2 Oct 2026 20:54:31 +0300 Subject: [PATCH 6/7] Specialize propagation help texts by form context Co-Authored-By: Claude Sonnet 5.5 --- .../src/components/forms/editFieldForm.ts | 8 ++++--- kompassi-v2-frontend/src/translations/en.tsx | 24 ++++++++++++++----- kompassi-v2-frontend/src/translations/fi.tsx | 22 ++++++++++++----- kompassi-v2-frontend/src/translations/sv.tsx | 23 +++++++++++++----- 4 files changed, 56 insertions(+), 21 deletions(-) diff --git a/kompassi-v2-frontend/src/components/forms/editFieldForm.ts b/kompassi-v2-frontend/src/components/forms/editFieldForm.ts index 34d426ae3..bf00c1978 100644 --- a/kompassi-v2-frontend/src/components/forms/editFieldForm.ts +++ b/kompassi-v2-frontend/src/components/forms/editFieldForm.ts @@ -86,13 +86,15 @@ export function getFieldEditorFields( type: "SingleCheckbox", slug: "propagateDimensionOnCreate", required: false, - ...t.propagateDimensionOnCreate, + title: t.propagateDimensionOnCreate.title, + helpText: t.propagateDimensionOnCreate.helpText[formContext], }, { type: "SingleCheckbox", slug: "propagateDimensionOnEdit", required: false, - ...t.propagateDimensionOnEdit, + title: t.propagateDimensionOnEdit.title, + helpText: t.propagateDimensionOnEdit.helpText[formContext], }, ); } else if (annotationPropagatingTypes.includes(fieldType)) { @@ -112,7 +114,7 @@ export function getFieldEditorFields( ...applicable.map(({ slug, title }) => ({ slug, title })), ], title: t.propagateToAnnotation.title, - helpText: t.propagateToAnnotation.helpText, + helpText: t.propagateToAnnotation.helpText[formContext], }, { type: "SingleCheckbox", diff --git a/kompassi-v2-frontend/src/translations/en.tsx b/kompassi-v2-frontend/src/translations/en.tsx index 82ff91ef1..68ef95872 100644 --- a/kompassi-v2-frontend/src/translations/en.tsx +++ b/kompassi-v2-frontend/src/translations/en.tsx @@ -259,18 +259,30 @@ const translations = { }, propagateDimensionOnCreate: { title: "Pass value forward on create", - helpText: - "When the response is created, set the corresponding dimension of the target object (eg. the program item or the involvement) to this value.", + helpText: { + program: + "When the response is created, set the corresponding dimension of the program item to this value.", + involvement: + "When the response is created, set the corresponding dimension of the involvement to this value.", + }, }, propagateDimensionOnEdit: { title: "Pass value forward on edit", - helpText: - "When the response is edited, update the corresponding dimension of the target object.", + helpText: { + program: + "When the response is edited, update the corresponding dimension of the program item.", + involvement: + "When the response is edited, update the corresponding dimension of the involvement.", + }, }, propagateToAnnotation: { title: "Pass value forward to annotation", - helpText: - "Set this annotation of the target object (eg. the program item or the involvement) to the value of this field.", + helpText: { + program: + "Set this annotation of the program item to the value of this field.", + involvement: + "Set this annotation of the involvement to the value of this field.", + }, none: "(do not pass forward)", }, propagateToAnnotationOnEdit: { diff --git a/kompassi-v2-frontend/src/translations/fi.tsx b/kompassi-v2-frontend/src/translations/fi.tsx index 08af7e8dc..89afb0f50 100644 --- a/kompassi-v2-frontend/src/translations/fi.tsx +++ b/kompassi-v2-frontend/src/translations/fi.tsx @@ -265,18 +265,28 @@ const translations: Translations = { }, propagateDimensionOnCreate: { title: "Välitä arvo eteenpäin luotaessa", - helpText: - "Kun vastaus luodaan, aseta kohdeobjektin (esim. ohjelmanumeron tai osallisuuden) vastaava dimensio tähän arvoon.", + helpText: { + program: + "Kun vastaus luodaan, aseta ohjelmanumeron vastaava dimensio tähän arvoon.", + involvement: + "Kun vastaus luodaan, aseta osallisuuden vastaava dimensio tähän arvoon.", + }, }, propagateDimensionOnEdit: { title: "Välitä arvo eteenpäin muokattaessa", - helpText: - "Kun vastausta muokataan, päivitä kohdeobjektin vastaava dimensio.", + helpText: { + program: + "Kun vastausta muokataan, päivitä ohjelmanumeron vastaava dimensio.", + involvement: + "Kun vastausta muokataan, päivitä osallisuuden vastaava dimensio.", + }, }, propagateToAnnotation: { title: "Välitä arvo lisätietoon", - helpText: - "Aseta kohdeobjektin (esim. ohjelmanumeron tai osallisuuden) tämä lisätieto tämän kentän arvoon.", + helpText: { + program: "Aseta ohjelmanumeron tämä lisätieto tämän kentän arvoon.", + involvement: "Aseta osallisuuden tämä lisätieto tämän kentän arvoon.", + }, none: "(ei välitetä eteenpäin)", }, propagateToAnnotationOnEdit: { diff --git a/kompassi-v2-frontend/src/translations/sv.tsx b/kompassi-v2-frontend/src/translations/sv.tsx index 003c94ff0..4b89d620a 100644 --- a/kompassi-v2-frontend/src/translations/sv.tsx +++ b/kompassi-v2-frontend/src/translations/sv.tsx @@ -255,18 +255,29 @@ const translations: Translations = { }, propagateDimensionOnCreate: { title: "Skicka värdet vidare vid skapande", - helpText: - "När svaret skapas, sätt motsvarande dimension hos målobjektet (t.ex. programpunkten eller delaktigheten) till detta värde.", + helpText: { + program: + "När svaret skapas, sätt programpunktens motsvarande dimension till detta värde.", + involvement: + "När svaret skapas, sätt delaktighetens motsvarande dimension till detta värde.", + }, }, propagateDimensionOnEdit: { title: "Skicka värdet vidare vid redigering", - helpText: - "När svaret redigeras, uppdatera motsvarande dimension hos målobjektet.", + helpText: { + program: + "När svaret redigeras, uppdatera programpunktens motsvarande dimension.", + involvement: + "När svaret redigeras, uppdatera delaktighetens motsvarande dimension.", + }, }, propagateToAnnotation: { title: "Skicka värdet vidare till anteckning", - helpText: - "Sätt denna anteckning hos målobjektet (t.ex. programpunkten eller delaktigheten) till fältets värde.", + helpText: { + program: "Sätt programpunktens denna anteckning till fältets värde.", + involvement: + "Sätt delaktighetens denna anteckning till fältets värde.", + }, none: "(skicka inte vidare)", }, propagateToAnnotationOnEdit: { From f58c3f8669e06253456c71b6450edbaece21d1c4 Mon Sep 17 00:00:00 2001 From: Luka Pajukanta Date: Fri, 2 Oct 2026 20:57:17 +0300 Subject: [PATCH 7/7] chore: translation fix --- kompassi-v2-frontend/src/translations/fi.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/kompassi-v2-frontend/src/translations/fi.tsx b/kompassi-v2-frontend/src/translations/fi.tsx index 89afb0f50..e44d187dc 100644 --- a/kompassi-v2-frontend/src/translations/fi.tsx +++ b/kompassi-v2-frontend/src/translations/fi.tsx @@ -306,7 +306,7 @@ const translations: Translations = { }, dimension: { title: "Dimensio", - helpText: "Mistä dimensiosta tämä kenttä saa vastauksensa?", + helpText: "Mistä dimensiosta tämä kenttä saa vastausvaihtoehtonsa?", }, maxLength: { title: "Enimmäispituus",