xref: /openbmc/webui-vue/src/components/Global/TableToolbar.vue (revision c5d60f52510d934d3f4007d645db6e2aab1fe7f9)
1<template>
2  <transition name="slide">
3    <div v-if="isToolbarActive" class="toolbar-container">
4      <div class="toolbar-content">
5        <p class="toolbar-selected">
6          {{ selectedItemsCount }} {{ $t('global.action.selected') }}
7        </p>
8        <div class="toolbar-actions d-flex">
9          <slot name="toolbar-buttons"></slot>
10          <b-button
11            v-for="(action, index) in actions"
12            :key="index"
13            :data-test-id="`table-button-${action.value}Selected`"
14            variant="primary"
15            class="d-block"
16            @click="$emit('batch-action', action.value)"
17          >
18            {{ action.label }}
19          </b-button>
20          <b-button
21            variant="secondary"
22            class="d-block"
23            @click="$emit('clear-selected')"
24          >
25            {{ $t('global.action.cancel') }}
26          </b-button>
27        </div>
28      </div>
29    </div>
30  </transition>
31</template>
32
33<script>
34import { useI18n } from 'vue-i18n';
35export default {
36  name: 'TableToolbar',
37  props: {
38    selectedItemsCount: {
39      type: Number,
40      required: true,
41    },
42    actions: {
43      type: Array,
44      default: () => [],
45      validator: (prop) => {
46        return prop.every((action) => {
47          return (
48            Object.prototype.hasOwnProperty.call(action, 'value') &&
49            Object.prototype.hasOwnProperty.call(action, 'label')
50          );
51        });
52      },
53    },
54  },
55  emits: ['batch-action', 'clear-selected'],
56  data() {
57    return {
58      $t: useI18n().t,
59      isToolbarActive: false,
60    };
61  },
62  watch: {
63    selectedItemsCount: function (selectedItemsCount) {
64      if (selectedItemsCount > 0) {
65        this.isToolbarActive = true;
66      } else {
67        this.isToolbarActive = false;
68      }
69    },
70  },
71};
72</script>
73
74<style lang="scss" scoped>
75$toolbar-height: 46px;
76
77.toolbar-container {
78  width: 100%;
79  position: relative;
80  z-index: $zindex-dropdown + 1;
81}
82
83.toolbar-content {
84  height: $toolbar-height;
85  background-color: theme-color('primary');
86  color: $white;
87  position: absolute;
88  left: 0;
89  right: 0;
90  top: -$toolbar-height;
91  display: flex;
92  flex-direction: row;
93  justify-content: space-between;
94}
95
96.toolbar-selected {
97  line-height: $toolbar-height;
98  margin: 0;
99  padding: 0 $spacer;
100}
101
102// Using v-deep to style export slot child-element
103// depricated and vue-js 3
104.toolbar-actions ::v-deep .btn {
105  position: relative;
106  &:after {
107    content: '';
108    position: absolute;
109    left: 0;
110    height: 1.5rem;
111    width: 1px;
112    background: rgba($white, 0.6);
113  }
114  &:last-child,
115  &:first-child {
116    &:after {
117      width: 0;
118    }
119  }
120}
121
122.slide-enter-active {
123  transition: transform $duration--moderate-02 $entrance-easing--productive;
124}
125.slide-leave-active {
126  transition: transform $duration--moderate-02 $exit-easing--productive;
127}
128.slide-enter, // Remove this vue2 based only class when switching to vue3
129.slide-enter-from, // This is vue3 based only class modified from 'slide-enter'
130.slide-leave-to {
131  transform: translateY($toolbar-height);
132}
133</style>
134