Jake Vanderwerf
2026-02-06 94de71140be2d0c80bf6a2e03cb9381b37736ed5
assets/js/concise/CRUD.js
@@ -402,7 +402,7 @@
               keyPath: 'id',
               endpoint: this.endpoint??'content', //for taxonomy stores
               headers: {
                  'action_nonce': window.auth.getNonce('dash'),
                  'X-Action-Nonce': window.auth.getNonce('dash'),
               },
               indexes: [
                  {name: 'id', keyPath: 'id'},
@@ -482,16 +482,29 @@
      //    }
      // });
      if (window.jvbUploads) {
         window.jvbUploads.subscribe((event, data) => {
            if (event === 'groups_uploaded' && data.content === this.content) {
               this.handleGroupsUploaded(data);
            }
         });
      }
      this.queue.subscribe((event, data) => {
         if (['image_upload', 'video_upload', 'document_upload'].includes(data.type)
            && event === 'operation-status'
            && data.status === 'completed') {
            this.store.clearCache();
         }
         console.log('CRUD.js queue subscription');
         console.log(event, data);
         if (event === 'operation-status'
            && data.status === 'completed'
            && data.endpoint === 'uploads/groups') {
            console.log('Grouped Uploads completed');
            if (data.result && data.result.group_mappings) {
               this.handleGroupMappings(data.result.group_mappings);
            }
            console.log('Cleared local cache. Refresh to see changes');
            this.store.clearCache();
         }
@@ -508,9 +521,7 @@
            }
            // Get successfully processed post IDs
            const successfulIds = Object.keys(data.result.posts).filter(id => {
               return data.result.posts[id]?.success === true;
            });
            const successfulIds = Object.keys(data.result.posts);
            if (successfulIds.length === 0) {
               return;
@@ -752,7 +763,10 @@
      this.changes.get(itemId)[name] = value;
      this.scheduleBackup();
      this.scheduleSave();
      //Only send actual itemIds to server. If this is a recently uploaded item, just store changes for now
      if (typeof itemId === 'number' || !itemId.includes('group')) {
         this.scheduleSave();
      }
   }
   scheduleBackup() {
      window.debouncer.schedule(
@@ -1201,7 +1215,7 @@
      let operation = {
         endpoint: this.endpoint,
         headers: {
            'action_nonce': window.auth.getNonce('dash'),
            'X-Action-Nonce': window.auth.getNonce('dash'),
         },
         data: {
            posts: allChanges,
@@ -1400,6 +1414,102 @@
      });
   }
   /***************************************************************
    UPLOAD GROUP SUPPORT
    Handles:
      - immediate UI feedback once the uploaded groups are sent to server
   ***************************************************************/
   handleGroupsUploaded(data) {
      const { posts, fieldId } = data;
      let uploader = window.jvbUploads;
      let field = uploader.fields.get(fieldId);
      console.log(posts);
      console.log(field);
      let added = [];
      posts.forEach(post => {
         const placeholderPost = {
            id: post.groupId,
            title: post.fields.post_title || `New ${this.singular}`,
            status: 'draft',
            date: new Date().toISOString(),
            modified: new Date().toISOString(),
            thumbnail: null,
            icon: this.content,
            taxonomies: {},
            fields: post.fields,
            images: {},
         };
         post.images.forEach((uploadId, index) => {
            let id = uploadId['upload_id'];
            if (index === 0) {
               placeholderPost.fields['post_thumbnail'] = uploadId;
            }
            let upload = uploader.stores.uploads.get(id);
            if (upload) {
               placeholderPost.images[id] = {
                  'image-alt-text': '',
                  'image-caption': '',
                  'image-title': upload.fields.originalName,
                  medium: uploader.createPreviewUrl(uploader.formatFile(upload))
               };
            }
         });
         //
         // // Add to store (won't persist since it's a fake ID)
         // this.store.data.set(post.groupId, placeholderPost);
         //
         //
         // // Render immediately
         // let element;
         // switch (this.view) {
         //    case 'grid':
         //       element = this.renderGridItem(placeholderPost);
         //       this.ui.grid.prepend(element);
         //       break;
         //    case 'list':
         //       element = this.renderListItem(placeholderPost);
         //       this.ui.grid.prepend(element);
         //       break;
         //    case 'table':
         //       element = this.renderTableItem(placeholderPost);
         //       if (this.ui.table.body) {
         //          this.ui.table.body.prepend(element);
         //       }
         //       break;
         // }
         // element.classList.add('uploading');
         added.push(placeholderPost);
      });
      this.store.saveMany(added).then(() => this.render());
      this.a11y.announce(`${posts.length} ${posts.length === 1 ? this.singular : this.plural} created. Waiting for server confirmation...`);
   }
   handleGroupMappings(mappings) {
      console.log('[CRUD] Applying group mappings:', mappings);
      // mappings = { "group_abc123": 456, "group_def456": 789 }
      for (const [groupId, postId] of Object.entries(mappings)) {
         // Get any pending changes for this temp item
         let changes = {};
         if (this.changes.has(groupId)) {
            changes = this.changes.get(groupId);
            this.changes.delete(groupId);
         }
         let storedChanges = this.changesStore.get(groupId)??{};
         if (changes.size > 0 || storedChanges.size > 0) {
            changes = window.deepMerge(storedChanges, changes);
            this.changes.set(postId, changes);
            this.scheduleBackup();
         }
      }
   }
   /***************************************************************
    UTILITY
   ***************************************************************/
   shouldRemoveItemUI(newStatus) {