-
Notifications
You must be signed in to change notification settings - Fork 13
feat: submission list pages #59
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
Merged
Changes from all commits
Commits
Show all changes
12 commits
Select commit
Hold shift + click to select a range
0730f1d
feat: add submissions page and update sidebar navigation
harshtandiya c932994
feat: submissions page v1
harshtandiya d2d583a
feat: add Drawer component for UI enhancement
harshtandiya d689f2d
feat: extend Drawer component with additional size options
harshtandiya 1afd0d9
feat: add submission details view and field value component
harshtandiya 3e53eb3
feat: enhance SubmissionFieldValue component with dynamic class handling
harshtandiya f03d3c0
fix: validate doctype against linked_doctype in get_submission_response
harshtandiya aa45875
fix: throw when form not found in get_all_submissions
harshtandiya 1cb0507
fix: show dash placeholder for null textarea value in SubmissionField…
harshtandiya 8d33f0a
fix: remove unused isLoading ref in SubmissionList
harshtandiya 017f4fb
fix: show loading state in drawer when formData not yet available
harshtandiya 3a06e3c
fix: add aria-labelledby to Drawer dialog element
harshtandiya File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
94 changes: 94 additions & 0 deletions
94
frontend/src/components/form/submissions/SubmissionDetails.vue
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,94 @@ | ||
| <script setup lang="ts"> | ||
| import { createResource } from "frappe-ui"; | ||
| import { useManageForm } from "@/stores/form/manageForm"; | ||
| import { computed, watch } from "vue"; | ||
| import { toast } from "vue-sonner"; | ||
| import { formatDateTime } from "@/utils/date"; | ||
| import SubmissionFieldValue from "@/components/form/submissions/SubmissionFieldValue.vue"; | ||
|
|
||
| const props = defineProps<{ | ||
| submissionId: string; | ||
| doctype: string; | ||
| }>(); | ||
|
|
||
| const manageFormStore = useManageForm(); | ||
|
|
||
| const submissionResource = createResource({ | ||
| url: "forms_pro.api.submission.get_submission_response", | ||
| makeParams() { | ||
| return { | ||
| submission_id: props.submissionId, | ||
| doctype: props.doctype, | ||
| }; | ||
| }, | ||
| onError(error: Error) { | ||
| toast.error("Failed to fetch submission details", { | ||
| description: error.message, | ||
| }); | ||
| }, | ||
| }); | ||
|
|
||
| const submissionData = computed(() => submissionResource.data ?? null); | ||
|
|
||
| watch( | ||
| () => props.submissionId, | ||
| (newId) => { | ||
| if (newId) { | ||
| submissionResource.fetch(); | ||
| } | ||
| }, | ||
| { immediate: true } | ||
| ); | ||
|
|
||
| const gridItems = computed(() => [ | ||
| { | ||
| label: "Submission ID", | ||
| key: "name", | ||
| value: submissionData.value?.name, | ||
| class: "font-mono", | ||
| }, | ||
| { | ||
| label: "Submitted On", | ||
| key: "creation", | ||
| value: formatDateTime(submissionData.value?.creation), | ||
| }, | ||
| { | ||
| label: "Last Modified", | ||
| key: "modified", | ||
| value: formatDateTime(submissionData.value?.modified), | ||
| }, | ||
| { | ||
| label: "Submitted By", | ||
| key: "owner", | ||
| value: submissionData.value?.owner, | ||
| }, | ||
| ]); | ||
| </script> | ||
|
|
||
| <template> | ||
| <div v-if="submissionResource.loading" class="text-sm text-ink-gray-5">Loading...</div> | ||
| <div v-else-if="submissionData" class="flex flex-col gap-4"> | ||
| <div class="p-2 flex flex-col gap-4"> | ||
| <div class="grid grid-cols-3 gap-4"> | ||
| <template v-for="item in gridItems" :key="item.key"> | ||
| <span class="text-sm text-ink-gray-5">{{ item.label }}</span> | ||
| <span class="text-sm text-ink-gray-7 col-span-2" :class="item.class">{{ | ||
| item.value | ||
| }}</span> | ||
| </template> | ||
| </div> | ||
| <hr /> | ||
| <div class="flex flex-col gap-6 my-4"> | ||
| <SubmissionFieldValue | ||
| v-for="field in manageFormStore.formFields" | ||
| :key="field.name" | ||
| :fieldname="field.fieldname" | ||
| :label="field.label" | ||
| :description="field.description" | ||
| :fieldtype="field.fieldtype" | ||
| :value="submissionData[field.fieldname]" | ||
| /> | ||
| </div> | ||
| </div> | ||
| </div> | ||
| </template> |
111 changes: 111 additions & 0 deletions
111
frontend/src/components/form/submissions/SubmissionFieldValue.vue
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,111 @@ | ||
| <script setup lang="ts"> | ||
| import { Checkbox, Switch, Rating, TextEditor } from "frappe-ui"; | ||
| import { FormFieldTypes } from "@/types/formfield"; | ||
| import { formatDate, formatDateTime, formatTime } from "@/utils/date"; | ||
| import { computed } from "vue"; | ||
|
|
||
| const props = defineProps<{ | ||
| fieldname: string; | ||
| label: string; | ||
| description?: string; | ||
| fieldtype: FormFieldTypes; | ||
| value: any; | ||
| }>(); | ||
|
|
||
| const formattedDateValue = computed(() => { | ||
| if (!props.value) return ""; | ||
| switch (props.fieldtype) { | ||
| case FormFieldTypes.Date: | ||
| return formatDate(props.value); | ||
| case FormFieldTypes.DateTime: | ||
| return formatDateTime(props.value); | ||
| case FormFieldTypes.TimePicker: | ||
| return formatTime(props.value); | ||
| case FormFieldTypes.DateRange: | ||
| try { | ||
| const dates = JSON.parse(props.value); | ||
| if (Array.isArray(dates) && dates.length === 2) { | ||
| return `${formatDate(dates[0])} – ${formatDate(dates[1])}`; | ||
| } | ||
| } catch { | ||
| /* value might already be a readable string */ | ||
| } | ||
| return String(props.value); | ||
| default: | ||
| return String(props.value); | ||
| } | ||
| }); | ||
|
|
||
| const isDateField = computed(() => | ||
| [ | ||
| FormFieldTypes.Date, | ||
| FormFieldTypes.DateTime, | ||
| FormFieldTypes.DateRange, | ||
| FormFieldTypes.TimePicker, | ||
| ].includes(props.fieldtype) | ||
| ); | ||
|
|
||
| const classNames = computed<string>(() => { | ||
| if ([FormFieldTypes.Switch, FormFieldTypes.Checkbox].includes(props.fieldtype)) { | ||
| return "flex gap-1 flex-row-reverse items-start justify-end"; | ||
| } | ||
| return "flex flex-col gap-1"; | ||
| }); | ||
| </script> | ||
|
|
||
| <template> | ||
| <div :class="classNames"> | ||
| <div> | ||
| <span class="text-sm text-ink-gray-5">{{ label }}</span> | ||
| <p v-if="description" class="text-xs text-ink-gray-4">{{ description }}</p> | ||
| </div> | ||
|
|
||
| <Checkbox | ||
| v-if="fieldtype === FormFieldTypes.Checkbox" | ||
| class="mt-1" | ||
| :modelValue="Boolean(value)" | ||
| disabled | ||
| /> | ||
|
|
||
| <Switch | ||
| v-else-if="fieldtype === FormFieldTypes.Switch" | ||
| :modelValue="Boolean(value)" | ||
| disabled | ||
| /> | ||
|
|
||
| <TextEditor | ||
| v-else-if="fieldtype === FormFieldTypes.TextEditor" | ||
| :content="value" | ||
| :editable="false" | ||
| :bubbleMenu="false" | ||
| :fixedMenu="false" | ||
| editorClass="prose-sm !border-none !p-0 !shadow-none" | ||
| /> | ||
|
|
||
| <Rating v-else-if="fieldtype === FormFieldTypes.Rating" :modelValue="value" readonly /> | ||
|
|
||
| <a | ||
| v-else-if="fieldtype === FormFieldTypes.Attach && value" | ||
| :href="value" | ||
| target="_blank" | ||
| class="text-sm text-blue-600 hover:text-blue-700 underline truncate" | ||
| > | ||
| {{ value }} | ||
| </a> | ||
|
|
||
| <span | ||
| v-else-if="fieldtype === FormFieldTypes.Textarea" | ||
| class="text-sm text-ink-gray-7 whitespace-pre-wrap" | ||
| > | ||
| {{ value ?? "–" }} | ||
| </span> | ||
|
coderabbitai[bot] marked this conversation as resolved.
|
||
|
|
||
| <span v-else-if="isDateField" class="text-sm text-ink-gray-7"> | ||
| {{ formattedDateValue }} | ||
| </span> | ||
|
|
||
| <span v-else class="text-sm text-ink-gray-7"> | ||
| {{ value ?? "–" }} | ||
| </span> | ||
| </div> | ||
| </template> | ||
Oops, something went wrong.
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.