<commit_before><template>
  <AposModalToolbar class-name="apos-manager-toolbar">
    <template #leftControls>
      <AposButton
        v-if="!options.hideSelectAll"
        label="apostrophe:select" :icon-only="true"
        :icon="checkboxIcon" type="outline"
        @click="$emit('select-click')"
      />
      <!-- TODO: Return this delete button when batch updates are added.
        When we do that though, we should do it like we handle the other
        batch operation events, not with extra event plumbing
        percolating everywhere. We can still achieve a custom button
        without that. -->
      <!-- <AposButton
        label="apostrophe:delete" @click="$emit('archive-click')"
        :icon-only="true" icon="delete-icon"
        type="outline"
      /> -->
      <AposContextMenu
        v-if="more.menu.length"
        :button="more.button"
        :menu="more.menu"
        @item-clicked="batchAction"
      />
    </template>
    <template #rightControls>
      <AposPager
        v-if="!options.noPager && totalPages !== 0"
        @click="registerPageChange" @change="registerPageChange"
        :total-pages="totalPages" :current-page="currentPage"
      />
      <AposFilterMenu
        v-if="filters.length > 0"
        :filters="filters"
        :choices="filterChoices"
        :values="filterValues"
        @input="filter"
      />
      <AposInputString
        v-if="!options.noSearch"
        @input="search" @return="search($event, true)"
        :field="searchField.field"
        :status="searchField.status" :value="searchField.value"
        :modifiers="['small']"
      />
    </template>
  </AposModalToolbar>
</template>

<script>

export default {
  props: {
    selectedState: {
      type: String,
      required: true
    },
    applyTags: {
      type: Array,
      default () {
        return [];
      }
    },
    filters: {
      type: Array,
      default () {
        return [];
      }
    },
    filterChoices: {
      type: Object,
      default () {
        return {};
      }
    },
    filterValues: {
      type: Object,
      default () {
        return {};
      }
    },
    totalPages: {
      type: Number,
      default: 1
    },
    currentPage: {
      type: Number,
      default: 1
    },
    labels: {
      type: Object,
      default () {
        return {};
      }
    },
    options: {
      type: Object,
      default () {
        return {};
      }
    }
  },
  emits: [
    'select-click',
    'filter',
    'search',
    'page-change',
    'batch'
  ],
  data() {
    return {
      searchField: {
        field: {
          name: 'search',
          placeholder: {
            key: 'apostrophe:searchDocType',
            type: this.$t(this.labels.plural)
          },
          icon: 'magnify-icon',
          enterSubmittable: true
        },
        status: {},
        value: { data: '' }
      }
    };
  },
  computed: {
    checkboxIcon() {
      if (this.selectedState === 'checked') {
        return 'checkbox-marked-icon';
      } else if (this.selectedState === 'indeterminate') {
        return 'minus-box-icon';
      } else {
        return 'checkbox-blank-icon';
      }
    },
    more () {
      const config = {
        button: {
          label: 'apostrophe:moreOperations',
          iconOnly: true,
          icon: 'dots-vertical-icon',
          type: 'outline'
        },
        menu: Array.isArray(this.options.moreActions) ? this.options.moreActions : []
      };

      return config;
    }
  },
  methods: {
    filter(filter, value) {
      this.$emit('filter', filter, value.data);
    },
    search(value, force) {
      if ((force && !value) || value.data === '') {
        value = {
          data: '',
          error: false
        };
      } else if (!value || value.error || (!force && value.data.length < 3)) {
        return;
      }

      this.$emit('search', value.data);
    },
    batchAction(action) {
      this.$emit('batch', action);
    },
    registerPageChange(pageNum) {
      this.$emit('page-change', pageNum);
    }
  }
};
</script>

<style lang="scss" scoped>
  .apos-manager-toolbar ::v-deep .apos-field--search {
    width: 250px;
  }
</style><commit_msg>wip dynamic batch operations rendering<commit_after><template>
  <AposModalToolbar class-name="apos-manager-toolbar">
    <template #leftControls>
      <AposButton
        v-if="!options.hideSelectAll"
        label="apostrophe:select" :icon-only="true"
        :icon="checkboxIcon" type="outline"
        @click="$emit('select-click')"
      />
      <!-- TODO: Return this delete button when batch updates are added.
        When we do that though, we should do it like we handle the other
        batch operation events, not with extra event plumbing
        percolating everywhere. We can still achieve a custom button
        without that. -->
      <!-- <AposButton
        label="apostrophe:delete" @click="$emit('archive-click')"
        :icon-only="true" icon="delete-icon"
        type="outline"
      /> -->
      <div
        v-for="{action, label, icon, operations, unlessFilter} in operations"
        :key="action"
      >
        <AposButton
          v-if="!operations"
          label="label"
          :icon-only="true"
          :icon="icon"
          type="outline"
          @click="$emit('select-click')"
        />
        <AposContextMenu
          v-else
          :button="{
            label,
            icon,
            iconOnly: true,
            type: 'outline'
          }"
          :menu="formatOperations(operations)"
          @item-clicked="batchAction"
        />
      </div>
    </template>
    <template #rightControls>
      <AposPager
        v-if="!options.noPager && totalPages !== 0"
        @click="registerPageChange" @change="registerPageChange"
        :total-pages="totalPages" :current-page="currentPage"
      />
      <AposFilterMenu
        v-if="filters.length"
        :filters="filters"
        :choices="filterChoices"
        :values="filterValues"
        @input="filter"
      />
      <AposInputString
        v-if="!options.noSearch"
        @input="search" @return="search($event, true)"
        :field="searchField.field"
        :status="searchField.status" :value="searchField.value"
        :modifiers="['small']"
      />
    </template>
  </AposModalToolbar>
</template>

<script>

export default {
  props: {
    selectedState: {
      type: String,
      required: true
    },
    applyTags: {
      type: Array,
      default () {
        return [];
      }
    },
    filters: {
      type: Array,
      default () {
        return [];
      }
    },
    filterChoices: {
      type: Object,
      default () {
        return {};
      }
    },
    filterValues: {
      type: Object,
      default () {
        return {};
      }
    },
    totalPages: {
      type: Number,
      default: 1
    },
    currentPage: {
      type: Number,
      default: 1
    },
    labels: {
      type: Object,
      default () {
        return {};
      }
    },
    options: {
      type: Object,
      default () {
        return {};
      }
    },
    batchOperations: {
      type: Array,
      default: () => []
    }
  },
  emits: [
    'select-click',
    'filter',
    'search',
    'page-change',
    'batch'
  ],
  data() {
    return {
      searchField: {
        field: {
          name: 'search',
          placeholder: {
            key: 'apostrophe:searchDocType',
            type: this.$t(this.labels.plural)
          },
          icon: 'magnify-icon',
          enterSubmittable: true
        },
        status: {},
        value: { data: '' }
      }
    };
  },
  computed: {
    checkboxIcon() {
      if (this.selectedState === 'checked') {
        return 'checkbox-marked-icon';
      } else if (this.selectedState === 'indeterminate') {
        return 'minus-box-icon';
      } else {
        return 'checkbox-blank-icon';
      }
    },
    operations () {
      // const ope = this.batchOperations
    }
    // more () {
    //   const config = {
    //     button: {
    //       label: 'apostrophe:moreOperations',
    //       iconOnly: true,
    //       icon: 'dots-vertical-icon',
    //       type: 'outline'
    //     },
    //     menu: Array.isArray(this.options.moreActions) ? this.options.moreActions : []
    //   };

    //   return config;
    // }
  },
  methods: {
    filter(filter, value) {
      this.$emit('filter', filter, value.data);
    },
    search(value, force) {
      if ((force && !value) || value.data === '') {
        value = {
          data: '',
          error: false
        };
      } else if (!value || value.error || (!force && value.data.length < 3)) {
        return;
      }

      this.$emit('search', value.data);
    },
    batchAction(action) {
      this.$emit('batch', action);
    },
    registerPageChange(pageNum) {
      this.$emit('page-change', pageNum);
    },
    formatOperations (operations) {
      return Object.entries(operations).map(([ key, props ]) => ({
        action: key,
        ...props
      }));
    }
  }
};
</script>

<style lang="scss" scoped>
  .apos-manager-toolbar ::v-deep .apos-field--search {
    width: 250px;
  }
</style>
{'fraction_non_alphanumeric': 0.15194000652103032, 'fraction_numerical': 0.0016302575806977503, 'mean_word_length': 1.7600479904019197, 'pattern_counts': {'":': 0, '<': 48, '<?xml version=': 0, '>': 49, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '1118204', 'n_tokens_mistral': 2805, 'n_tokens_neox': 2781, 'n_words': 530}