-
Notifications
You must be signed in to change notification settings - Fork 0
Feat/update chars #29
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
Changes from all commits
9406327
d9f269c
0738318
1f81e2f
0132ce3
d4f55a9
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| @@ -0,0 +1,206 @@ | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| <script lang="ts"> | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| import { goto } from '$app/navigation'; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| import { page } from '$app/state'; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| import pb from '$lib/pocketbase'; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| import { onMount } from 'svelte'; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| let charTags = $state<string[]>([]); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| let charTagsCurrentInput = $state(''); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| let charErrorText = $state(''); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| let record = $state<any>(); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| function newCharAddTag(e: KeyboardEvent) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| if (e.key === 'Enter' && charTagsCurrentInput.trim()) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| e.preventDefault(); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| if (charTags.length >= 10) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| charErrorText = 'Maximum of ten tags'; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| return; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| // 如果标签不存在则添加 | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| if (!charTags.includes(charTagsCurrentInput.trim())) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| charTags.push(charTagsCurrentInput.trim()); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| charTagsCurrentInput = ''; // 清空输入 | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| let charName = $state(''); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| let charDescription = $state(''); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| let charOrigin = $state(''); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| let charPictures: FileList | undefined = $state(); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| const updateCharacter = async () => { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| const formData = new FormData(); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| charErrorText = ''; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| if (charPictures && charPictures.length !== 0) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| for (let file of charPictures) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| formData.append('images', file); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| formData.append('name', charName) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| formData.append('description', charDescription) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| formData.append('origin', charOrigin) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| charTags.forEach((tag) => { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| formData.append('tag_names', tag); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| }); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
Comment on lines
+37
to
+48
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🧩 Analysis chain🏁 Script executed: # First, let's locate and inspect the file
find . -name "+page.svelte" -path "*/edit/characters/*" -type fRepository: pdnode-team/cp Length of output: 112 🏁 Script executed: # Get the context around lines 37-50 of the file
cat -n "website/src/routes/edit/characters/[id]/+page.svelte" | sed -n '30,55p'Repository: pdnode-team/cp Length of output: 966 🏁 Script executed: # Check if there's any PocketBase version info in the project
find . -name "package.json" -o -name "package-lock.json" -o -name "pocketbase.json" | head -5Repository: pdnode-team/cp Length of output: 80 🏁 Script executed: # Let's check the package.json for dependencies and PocketBase info
cat "package.json" 2>/dev/null || cat "website/package.json" 2>/dev/null || echo "No package.json found in root"Repository: pdnode-team/cp Length of output: 1320 🌐 Web query:
💡 Result: No specific changes or fixes related to multi-value (multiple relation) fields and empty array relations were made in PocketBase v0.26.x series, including any potential v0.26.8 release. The v0.26.x releases (v0.26.0 through v0.26.6 confirmed) focus on dependency updates, minor bug fixes like error serialization and OIDC support, AWS SDK replacement, and timeout adjustments, but nothing mentions relation fields or empty arrays. Multi-value relation fields in PocketBase are stored as JSON arrays of record IDs. Empty relations are represented as empty arrays []. Known past issues with multi-relations (e.g., API rules :length operator not recognizing empty strings as empty arrays, fixed in v0.16.10; multipart form binding fixed in v0.16.6) predate v0.26.x. Official docs confirm standard handling: set to [] for empty, use field+/field- modifiers for append/remove. No evidence of bugs or changes in v0.26.8 specifically addressing "empty array relations". If experiencing issues, check field defaults (toggle single/multiple to normalize), API rules, or client-side sending (e.g., empty array vs empty string). Citations:
🌐 Web query:
💡 Result: In PocketBase, record updates via the API (PATCH /api/collections/{collection}/records/{id}) are partial updates: only fields explicitly included in the request body are processed and potentially changed. Fields omitted from the FormData or JSON body retain their existing database values unchanged. To intentionally clear or unset a field during an update (set it to null/empty/zero-value), explicitly include it in the request body with the desired clearing value: - For most scalar fields (text, number, etc.): use empty string "" or null (if the field supports null and is not required). - For file fields: use empty string "" or [] (empty array) when using FormData to clear all files. Examples from official docs: formData.append('documents', '') or { 'documents': [] }. - For JSON fields: send null, empty object {}, or empty array [] as appropriate. - For relations and arrays: use [] for empty, or field- modifier (e.g., 'tags-': ['id1']) to remove specific items. This behavior is confirmed in the RecordUpsert form source code, where only submitted fields (via Load(data)) call record.SetIfFieldExists(k, v), leaving omitted fields untouched. Official file handling docs explicitly state setting file fields to empty string/[] in FormData clears them. JS SDK examples and API reference show update(body) processes only provided fields. Example clearing a text field with FormData: const formData = new FormData; formData.append('title', ''); // clears title formData.append('otherField', 'keep this'); await pb.collection('example').update('RECORD_ID', formData); Omitting 'title' entirely would leave it unchanged. Citations:
🏁 Script executed: # Check if there's any local documentation or examples in the repo about PocketBase usage
find . -name "*.md" -o -name "*.txt" | xargs grep -l "pocketbase\|PocketBase" 2>/dev/null | head -5Repository: pdnode-team/cp Length of output: 40 🏁 Script executed: # Look for any other places where FormData is used with PocketBase update calls to see patterns
rg "formData\.(append|delete)" -A 2 -B 2 --type svelteRepository: pdnode-team/cp Length of output: 88 🏁 Script executed: # Look for any backend/schema files that might define field types
find . -name "*.go" -o -name "*.pb" -o -name "schema*" -o -name "*.sql" | head -10Repository: pdnode-team/cp Length of output: 421 🏁 Script executed: # Search for any references to 'tag_names' or 'images' fields to understand their types
rg "tag_names|images" -t svelte -B 3 -A 3 | head -50Repository: pdnode-team/cp Length of output: 88 🏁 Script executed: # Check if there's any documentation about the character collection schema
find . -name "*.md" | xargs grep -l "tag_names\|character.*schema" 2>/dev/null | head -5Repository: pdnode-team/cp Length of output: 40 🏁 Script executed: # Look for any API route handlers or backend setup that might define fields
find . -type f -name "*.ts" -o -name "*.js" | xargs grep -l "characters\|collection" 2>/dev/null | head -10Repository: pdnode-team/cp Length of output: 40 🏁 Script executed: # Examine the character creation migration
cat -n "./migrations/1776132769_created_characters.go"Repository: pdnode-team/cp Length of output: 5073 🏁 Script executed: # Examine the latest character update migration
cat -n "./migrations/1776489282_updated_characters.go"Repository: pdnode-team/cp Length of output: 2362
Current behavior:
The ♻️ Suggested fix if (charPictures && charPictures.length !== 0) {
- formData.delete('images')
for (let file of charPictures) {
formData.append('images', file);
}
}
formData.append('name', charName);
formData.append('description', charDescription);
formData.append('origin', charOrigin);
- formData.delete('tag_names')
- charTags.forEach((tag) => {
- formData.append('tag_names', tag);
- });
+ // Always send tag_names to replace the value, even when empty.
+ if (charTags.length === 0) {
+ formData.append('tag_names', '');
+ } else {
+ charTags.forEach((tag) => formData.append('tag_names', tag));
+ }Verify with your PocketBase 0.26.8 backend whether an empty string ( 📝 Committable suggestion
Suggested change
🤖 Prompt for AI Agents |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| formData.append('owner', record.owner); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| try { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| await pb.collection('characters').update(page.params.id!, formData); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| goto(`/characters/${page.params.id}`); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } catch (err: any) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| charErrorText = err.data.data?.message ?? 'Update failed. Please try again.'; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| const firstKey = Object.keys(err.data.data)[0]; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| if (firstKey) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| const friendlyMessage = `${firstKey}: ${err.data.data[firstKey].message}`; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| console.error(friendlyMessage); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| charErrorText = friendlyMessage; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| return; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| }; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| onMount(async () => { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| if (!pb.authStore.isValid) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| window.location.pathname = '/login'; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| return; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| record = await pb.collection('characters').getOne(page.params.id!); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| let rawTags = record.tag_names; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| try { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| // 如果它是字符串,尝试解析它 | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| if (typeof rawTags === 'string') { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| // 如果 rawTags 是 '"单相思"',解析后得到 '单相思' | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| // 如果 rawTags 是 '["A", "B"]',解析后得到 ['A', 'B'] | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| const parsed = JSON.parse(rawTags); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| // 解析后判断结果:是数组直接赋值,是字符串则包装成数组 | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| if (Array.isArray(parsed)) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| charTags = parsed; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } else if (typeof parsed === 'string') { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| charTags = [parsed]; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } else if (Array.isArray(rawTags)) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| // 如果 SDK 已经自动帮你转成了数组 | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| charTags = rawTags; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } catch (e) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| // 如果解析失败(比如 rawTags 本身就是个普通字符串 "单相思" 而不是 '"单相思"') | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| charTags = rawTags ? [rawTags] : []; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
coderabbitai[bot] marked this conversation as resolved.
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| charName = record.name; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| charDescription = record.description; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| charOrigin = record.origin; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| }); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| </script> | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| <div class="flex min-h-[70vh] flex-col items-center justify-center px-4 py-12"> | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| <div class="card w-full max-w-md bg-base-100"> | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| {#if record} | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| <div class="card-body flex flex-col gap-4 p-8"> | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| <h2 class="mb-2 text-center text-3xl font-bold">Update {record?.name}</h2> | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| <p class="mb-6 text-center text-base-content/60"> | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| All fields must be filled out unless otherwise specified. | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| </p> | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| <div class="flex flex-col gap-4"> | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| <label class="form-control w-full"> | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| <div class="label"><span class="label-text font-medium">Name</span></div> | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| <input | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| type="text" | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| name="characterName" | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| placeholder="XXXX & YYYY" | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| class="input-bordered input w-full" | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| autocomplete="name" | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| bind:value={charName} | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| required | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| /> | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| </label> | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| <label class="form-control w-full"> | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| <div class="label"> | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| <span class="label-text font-medium">Description</span> | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| </div> | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| <textarea | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| name="characterDescription" | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| placeholder="description" | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| class="textarea w-full" | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| maxlength="1000" | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| bind:value={charDescription} | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| required | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| ></textarea> | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| </label> | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| <label class="form-control w-full"> | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| <div class="label"><span class="label-text font-medium">Origin</span></div> | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| <input | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| type="text" | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| name="characterOrigin" | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| placeholder="https://pdnode.com" | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| class="input-bordered input w-full" | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| autocomplete="name" | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| bind:value={charOrigin} | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| /> | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| </label> | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| <div class="form-control w-full max-w-xs"> | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| <label class="label" for="file-upload"> | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| <span class="label-text">Pictures (Option)</span> | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| </label> | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| <input | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| type="file" | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| id="file-upload" | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| class="file-input-bordered file-input w-full file-input-primary" | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| accept="image/*" | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| multiple | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| bind:files={charPictures} | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| /> | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| </div> | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| <div class="flex w-full max-w-sm flex-col"> | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| <div class="label"> | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| <span class="label-text font-medium">Tags (Option)</span> | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| </div> | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| <input | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| type="text" | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| placeholder="Enter the tags and press Enter...." | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| class="input-bordered input w-full" | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| bind:value={charTagsCurrentInput} | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| onkeydown={newCharAddTag} | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| /> | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| <div class="mt-2 flex flex-wrap gap-2"> | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| {#each charTags as tag, i} | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| <div class="badge gap-2 badge-soft p-3 badge-primary"> | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| {tag} | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| <button type="button" onclick={() => charTags.splice(i, 1)} class="text-xs" | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| >✕</button | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| > | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| </div> | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| {/each} | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| </div> | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| </div> | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| <p class="text-red-500">{charErrorText}</p> | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| <button type="submit" class="btn w-full text-lg btn-primary" onclick={updateCharacter} | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| >Update</button | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| > | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| </div> | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| </div> | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| {:else} | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| <div role="alert" class="alert alert-soft alert-error"> | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| <span>The record could not be found.</span> | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| </div> | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| {/if} | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| </div> | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| </div> | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Missing required-field validation before submit.
Unlike
createCharacter(which validatesnewCharName/newCharDescription/newCharOriginare non-empty),updateCharactersubmits directly. A user who clears the Name or Description field and clicks Update will either get a server-side validation error or successfully persist empty required values, depending on the PocketBase schema. Mirror the create-form validation here for consistent UX.🛡️ Proposed fix
const updateCharacter = async () => { const formData = new FormData(); charErrorText = ''; + + if (!charName.trim() || !charDescription.trim() || !charOrigin.trim()) { + charErrorText = 'All fields must be filled out'; + return; + }📝 Committable suggestion
🤖 Prompt for AI Agents