@appscode/design-system 1.0.43-alpha.99 → 1.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (101) hide show
  1. package/base/utilities/_all.scss +7 -0
  2. package/base/utilities/_customize-bulma.scss +191 -0
  3. package/base/utilities/_default.scss +58 -124
  4. package/base/utilities/_derived-variables.scss +6 -0
  5. package/base/utilities/_grid.scss +29 -0
  6. package/base/utilities/_initial-variables.scss +13 -9
  7. package/base/utilities/_typography.scss +6 -12
  8. package/base/utilities/dark-theme.scss +1 -0
  9. package/components/_ac-accordion.scss +14 -5
  10. package/components/_ac-alert-box.scss +32 -6
  11. package/components/_ac-card.scss +17 -5
  12. package/components/_ac-drag.scss +2 -0
  13. package/components/_ac-input.scss +19 -11
  14. package/components/_ac-modal.scss +1 -1
  15. package/components/_ac-multi-select.scss +60 -4
  16. package/components/_ac-report.scss +53 -0
  17. package/components/_ac-table.scss +60 -2
  18. package/components/_ac-tabs.scss +16 -2
  19. package/components/_ac-tags.scss +85 -0
  20. package/components/_ac-terminal.scss +1 -3
  21. package/components/_all.scss +28 -0
  22. package/components/_buttons.scss +14 -33
  23. package/components/_dashboard-header.scss +32 -0
  24. package/components/_left-sidebar-menu.scss +9 -9
  25. package/components/_navbar.scss +89 -4
  26. package/components/_preview-modal.scss +14 -1
  27. package/components/_transitions.scss +261 -0
  28. package/components/_wizard.scss +1 -0
  29. package/components/bbum/_all.scss +9 -0
  30. package/components/bbum/_single-post-preview.scss +1 -1
  31. package/components/ui-builder/_ui-builder.scss +58 -0
  32. package/components/ui-builder/_vue-open-api.scss +6 -0
  33. package/layouts/_all.scss +2 -0
  34. package/layouts/_code-preview.scss +5 -2
  35. package/main.scss +5 -56
  36. package/package.json +4 -2
  37. package/plugins/caching.ts +243 -0
  38. package/plugins/time-convert.js +49 -0
  39. package/plugins/vue-toaster.js +3 -0
  40. package/vue-components/v2/banner/Banner.vue +2 -2
  41. package/vue-components/v2/breadcrumbs/Breadcrumb.vue +97 -0
  42. package/vue-components/v2/button/Button.vue +5 -0
  43. package/vue-components/v2/button/DownloadBtn.vue +45 -0
  44. package/vue-components/v2/card/Card.vue +1 -0
  45. package/vue-components/v2/content/ContentTable.vue +12 -7
  46. package/vue-components/v2/editor/Editor.vue +37 -24
  47. package/vue-components/v2/editor/FilteredFileEditor.vue +189 -0
  48. package/vue-components/v2/editor/MonacoEditor.vue +125 -0
  49. package/vue-components/v2/editor/ResourceKeyValueEditor.vue +209 -0
  50. package/vue-components/v2/form-fields/Input.vue +1 -1
  51. package/vue-components/v2/loaders/ResourceLoader.vue +101 -0
  52. package/vue-components/v2/loaders/SidebarLoader.vue +43 -0
  53. package/vue-components/v2/modal/Modal.vue +30 -5
  54. package/vue-components/v2/modals/DeleteConfirmationModal.vue +79 -0
  55. package/vue-components/v2/modals/JsonShowModal.vue +12 -2
  56. package/vue-components/v2/navbar/User.vue +229 -17
  57. package/vue-components/v2/notification/Notification.vue +101 -0
  58. package/vue-components/v2/notification/NotificationItem.vue +44 -0
  59. package/vue-components/v2/pagination/Pagination.vue +16 -3
  60. package/vue-components/v2/preloader/Preloader.vue +1 -1
  61. package/vue-components/v2/sidebar/SidebarItemWithDropDown.vue +19 -20
  62. package/vue-components/v2/tab/TabItem.vue +1 -1
  63. package/vue-components/v2/table/Table.vue +49 -8
  64. package/vue-components/v2/table/TableRow.vue +12 -2
  65. package/vue-components/v2/table/table-cell/CellValue.vue +29 -9
  66. package/vue-components/v2/table/table-cell/GenericCell.vue +56 -0
  67. package/vue-components/v2/table/table-cell/ObjectCell.vue +4 -1
  68. package/vue-components/v3/button/Button.vue +6 -1
  69. package/vue-components/v3/content/ContentHeader.vue +2 -1
  70. package/vue-components/v3/content/ContentTable.vue +20 -2
  71. package/vue-components/v3/editor/Editor.vue +36 -33
  72. package/vue-components/v3/editor/FilteredFileEditor.vue +186 -0
  73. package/vue-components/v3/editor/MonacoEditor.vue +131 -0
  74. package/vue-components/v3/editor/ResourceKeyValueEditor.vue +125 -0
  75. package/vue-components/v3/form/Form.vue +63 -0
  76. package/vue-components/v3/form-fields/Input.vue +11 -10
  77. package/vue-components/v3/header/HeaderItem.vue +5 -0
  78. package/vue-components/v3/header/HeaderItems.vue +5 -0
  79. package/vue-components/v3/loaders/ResourceLoader.vue +83 -0
  80. package/vue-components/v3/loaders/SidebarLoader.vue +34 -0
  81. package/vue-components/v3/long-running-tasks/LongRunningTaskItem.vue +92 -0
  82. package/vue-components/v3/modal/Modal.vue +30 -7
  83. package/vue-components/v3/modals/DeleteConfirmationModal.vue +85 -0
  84. package/vue-components/v3/modals/JsonShowModal.vue +25 -16
  85. package/vue-components/v3/modals/LongRunningTasksModal.vue +400 -0
  86. package/vue-components/v3/navbar/ThemeMode.vue +41 -49
  87. package/vue-components/v3/navbar/User.vue +242 -18
  88. package/vue-components/v3/notification/AlertBox.vue +61 -0
  89. package/vue-components/v3/notification/Notification.vue +98 -0
  90. package/vue-components/v3/notification/NotificationItem.vue +52 -0
  91. package/vue-components/v3/pagination/Pagination.vue +16 -3
  92. package/vue-components/v3/sidebar/SidebarItemWithDropDown.vue +120 -0
  93. package/vue-components/v3/tab/TabItem.vue +1 -1
  94. package/vue-components/v3/table/MultiInfoTable.vue +143 -0
  95. package/vue-components/v3/table/Table.vue +52 -13
  96. package/vue-components/v3/table/TableContainer.vue +34 -0
  97. package/vue-components/v3/table/TableRow.vue +93 -6
  98. package/vue-components/v3/table/table-cell/CellValue.vue +23 -7
  99. package/vue-components/v3/table/table-cell/GenericCell.vue +75 -0
  100. package/vue-components/v3/table/table-cell/ObjectCell.vue +7 -2
  101. package/vue-components/v3/terminal/LongRunningTaskTerminal.vue +148 -0
@@ -9,7 +9,11 @@
9
9
  "
10
10
  >
11
11
  <label>Rows per page</label>
12
- <select v-model="selectedItemCountPerPage" name="page">
12
+ <select
13
+ v-model="selectedItemCountPerPage"
14
+ name="page"
15
+ data-testid="rows-per-page-selector"
16
+ >
13
17
  <option :value="5">5</option>
14
18
  <option :value="10" v-show="totalNoOfItems > 5">10</option>
15
19
  <option :value="15" v-show="totalNoOfItems > 10">15</option>
@@ -31,19 +35,28 @@
31
35
 
32
36
  <ul v-if="totalNoOfItems > selectedItemCountPerPage">
33
37
  <li>
34
- <a class="previous" @click.prevent="prevPage()">
38
+ <a
39
+ class="previous"
40
+ @click.prevent="prevPage()"
41
+ data-testid="pagination-previous-page-button"
42
+ >
35
43
  <i class="fa fa-angle-left" aria-hidden="true"></i>
36
44
  </a>
37
45
  </li>
38
46
  <li v-for="page in pages" :key="`page-${page}`">
39
47
  <a
40
48
  @click.prevent="changePage(page)"
49
+ data-testid="pagination-page-switch-button"
41
50
  :class="{ 'is-current': activePageNo === page }"
42
51
  >{{ page }}</a
43
52
  >
44
53
  </li>
45
54
  <li>
46
- <a class="next" @click.prevent="nextPage()">
55
+ <a
56
+ class="next"
57
+ @click.prevent="nextPage()"
58
+ data-testid="pagination-next-page-button"
59
+ >
47
60
  <i class="fa fa-angle-right" aria-hidden="true"></i>
48
61
  </a>
49
62
  </li>
@@ -0,0 +1,120 @@
1
+ <template>
2
+ <li :class="`is-${dropDownStatus}`">
3
+ <a class="ac-dropdown-button" :title="title" @click="toggleDropDownStatus">
4
+ <span>
5
+ <img :src="icon" alt="icon" />
6
+ </span>
7
+ <strong>{{ title || "-" }}</strong>
8
+ <span class="ac-arrow-down">
9
+ <i class="fa fa-angle-down" aria-hidden="true"> </i>
10
+ </span>
11
+ </a>
12
+
13
+ <ul ref="sectionItems" :style="{ maxHeight: dropDownSectionHeight }">
14
+ <slot />
15
+ </ul>
16
+ </li>
17
+ </template>
18
+
19
+ <script>
20
+ import { defineComponent } from "vue";
21
+
22
+ export default defineComponent({
23
+ props: {
24
+ isDropDownOpen: {
25
+ type: Boolean,
26
+ default: false,
27
+ },
28
+ title: {
29
+ type: String,
30
+ default: "Sidebar Item",
31
+ },
32
+ icon: {
33
+ type: String,
34
+ default: "@/assets/images/icons/basic.svg",
35
+ },
36
+ },
37
+
38
+ emits: ["dropDownItemChange"],
39
+
40
+ data() {
41
+ return {
42
+ dropDownStatus: "close",
43
+ dropDownSectionHeight: null,
44
+ isCompMounted: false,
45
+ };
46
+ },
47
+
48
+ mounted() {
49
+ this.isCompMounted = true;
50
+ setTimeout(() => {
51
+ // for expanding dropdown
52
+ if (this.isDropDownOpen) {
53
+ this.setDropdownMaxHeight("open");
54
+ } else {
55
+ this.setDropdownMaxHeight("close");
56
+ }
57
+ }, 700);
58
+ },
59
+
60
+ watch: {
61
+ title(n, o) {
62
+ if (n && this.isCompMounted) {
63
+ this.$nextTick(() => {
64
+ // for expanding dropdown
65
+ this.setDropdownMaxHeight("open");
66
+ });
67
+ }
68
+
69
+ if (o && this.isCompMounted) {
70
+ this.$nextTick(() => {
71
+ // for expanding dropdown
72
+ this.setDropdownMaxHeight("close");
73
+ });
74
+ }
75
+ },
76
+ isDropDownOpen: {
77
+ immediate: true,
78
+ handler(n) {
79
+ if (n) {
80
+ this.dropDownStatus = "open";
81
+ } else this.dropDownStatus = "close";
82
+ },
83
+ },
84
+ dropDownStatus: {
85
+ immediate: true,
86
+ handler(n) {
87
+ if (n === "open") {
88
+ // emit event to close other drop down items
89
+ this.$emit("dropDownItemChange");
90
+
91
+ this.$nextTick(() => {
92
+ const dropDownUl = this.$refs["sectionItems"];
93
+ // debugger;
94
+ if (dropDownUl)
95
+ this.dropDownSectionHeight = `${dropDownUl.scrollHeight}px`;
96
+ });
97
+ } else {
98
+ // emit event to close other drop down items
99
+ this.dropDownSectionHeight = null;
100
+ }
101
+ },
102
+ },
103
+ },
104
+
105
+ methods: {
106
+ setDropdownMaxHeight(mode) {
107
+ if (mode === "open") {
108
+ this.dropDownSectionHeight = `${this.$refs["sectionItems"].scrollHeight}px`;
109
+ } else {
110
+ this.dropDownSectionHeight = null;
111
+ }
112
+ },
113
+ toggleDropDownStatus() {
114
+ if (this.dropDownStatus === "open") {
115
+ this.dropDownStatus = "close";
116
+ } else this.dropDownStatus = "open";
117
+ },
118
+ },
119
+ });
120
+ </script>
@@ -1,5 +1,5 @@
1
1
  <template>
2
- <li :class="{ 'is-active': isActive }">
2
+ <li :class="{ 'is-active': isActive }" data-testid="tab-item">
3
3
  <slot />
4
4
  </li>
5
5
  </template>
@@ -0,0 +1,143 @@
1
+ <template>
2
+ <table-container>
3
+ <table
4
+ class="table ac-info-table is-fullwidth"
5
+ :class="{ 'pl-0 pr-0': removeContentPadding }"
6
+ >
7
+ <tbody v-if="isFullTableLoaderActive">
8
+ <table-row v-for="i in loaderCols" :key="i">
9
+ <table-cell>
10
+ <cell-value :is-loader-active="true" />
11
+ </table-cell>
12
+ <table-cell>
13
+ <cell-value :is-loader-active="true" />
14
+ </table-cell>
15
+ </table-row>
16
+ </tbody>
17
+ <tbody
18
+ v-else
19
+ :class="{
20
+ 'no-data-available has-text-centered p-10': isTableEmpty,
21
+ 'pl-0 pr-0': removeContentPadding,
22
+ }"
23
+ >
24
+ <template v-if="!isTableEmpty">
25
+ <table-row
26
+ v-for="(tableHeader, idx) in tableHeaders"
27
+ :key="headerLabels[idx]"
28
+ >
29
+ <table-cell>
30
+ <slot :name="`table-cell-icon-${idx}`" />
31
+ {{ headerLabels[idx] }}
32
+ </table-cell>
33
+ <table-cell v-if="isLoaderActive">
34
+ <cell-value :is-loader-active="true" />
35
+ </table-cell>
36
+ <slot v-else :name="`slot-${idx}`" />
37
+ </table-row>
38
+ </template>
39
+
40
+ <empty-table-info v-else />
41
+ </tbody>
42
+ </table>
43
+
44
+ <!-- pagination start -->
45
+ <slot name="table-pagination" />
46
+ <!-- pagination end -->
47
+ </table-container>
48
+ </template>
49
+
50
+ <script>
51
+ import { defineComponent, defineAsyncComponent } from "vue";
52
+
53
+ export default defineComponent({
54
+ props: {
55
+ isLoaderActive: {
56
+ type: Boolean,
57
+ default: false,
58
+ },
59
+ isTableEmpty: {
60
+ type: Boolean,
61
+ default: true,
62
+ },
63
+ tableHeaders: {
64
+ type: Array,
65
+ default: () => [],
66
+ },
67
+ removeContentPadding: {
68
+ type: Boolean,
69
+ default: false,
70
+ },
71
+ },
72
+
73
+ components: {
74
+ TableContainer: defineAsyncComponent(() =>
75
+ import("../../v2/table/TableContainer.vue").then(
76
+ (module) => module.default
77
+ )
78
+ ),
79
+ EmptyTableInfo: defineAsyncComponent(() =>
80
+ import("../../v2/table/EmptyTableInfo.vue").then(
81
+ (module) => module.default
82
+ )
83
+ ),
84
+ TableRow: defineAsyncComponent(() =>
85
+ import("./TableRow.vue").then((module) => module.default)
86
+ ),
87
+ TableCell: defineAsyncComponent(() =>
88
+ import("./TableCell.vue").then((module) => module.default)
89
+ ),
90
+ CellValue: defineAsyncComponent(() =>
91
+ import("./table-cell/CellValue.vue").then((module) => module.default)
92
+ ),
93
+ },
94
+
95
+ data() {
96
+ return {
97
+ loaderCols: 5,
98
+ headerSortables: [],
99
+ };
100
+ },
101
+
102
+ computed: {
103
+ isFullTableLoaderActive() {
104
+ return !this.tableHeaders.length;
105
+ },
106
+ headerLabels() {
107
+ return this.tableHeaders.map((th) =>
108
+ typeof th === "string" ? th : th?.name || "Label"
109
+ );
110
+ },
111
+ },
112
+
113
+ watch: {
114
+ tableHeaders: {
115
+ immediate: true,
116
+ handler(n) {
117
+ if (this.headerSortables.length === n.length) {
118
+ n.forEach((th, idx) => {
119
+ if (this.headerSortables[idx].enabled !== !!th?.sort?.enable) {
120
+ this.headerSortables[idx].enabled = !!th?.sort?.enable;
121
+ this.headerSortables[idx].mode = "";
122
+ }
123
+ });
124
+ } else {
125
+ this.headerSortables = n.map((th) => {
126
+ if (typeof th === "string") {
127
+ return {
128
+ enabled: false,
129
+ mode: "",
130
+ };
131
+ } else {
132
+ return {
133
+ enabled: !!th?.sort?.enable,
134
+ mode: "",
135
+ };
136
+ }
137
+ });
138
+ }
139
+ },
140
+ },
141
+ },
142
+ });
143
+ </script>
@@ -1,14 +1,16 @@
1
1
  <template>
2
- <table-container>
2
+ <table-container ref="ac-table-container" @scroller="handleScroller">
3
3
  <table
4
4
  ref="ac-table"
5
- class="table ac-table ac-striped"
5
+ class="table ac-table"
6
6
  :class="{
7
7
  'is-fullwidth':
8
8
  !isDynamicWidthTable ||
9
9
  isFullTableLoaderActive ||
10
10
  isTableEmpty ||
11
11
  isLoaderActive,
12
+ 'ac-striped': !columnStriped,
13
+ 'ac-label-texted': columnStriped,
12
14
  }"
13
15
  >
14
16
  <thead>
@@ -18,6 +20,7 @@
18
20
  </th>
19
21
  </table-row>
20
22
  <table-row v-else>
23
+ <th v-if="collapsible" style="width: 20px" />
21
24
  <th
22
25
  v-for="(tableHeader, idx) in tableHeaders"
23
26
  :key="idx"
@@ -25,10 +28,33 @@
25
28
  sorting: headerSortables[idx].enabled,
26
29
  'sorting-desc': headerSortables[idx].mode === 'desc',
27
30
  'sorting-asc': headerSortables[idx].mode === 'asc',
31
+ 'has-text-centered':
32
+ typeof tableHeader === 'string'
33
+ ? false
34
+ : tableHeader.textAlign === 'center',
35
+ 'has-text-left':
36
+ typeof tableHeader === 'string'
37
+ ? false
38
+ : tableHeader.textAlign === 'left',
39
+ 'has-text-right':
40
+ typeof tableHeader === 'string'
41
+ ? false
42
+ : tableHeader.textAlign === 'right',
28
43
  }"
29
44
  @click.prevent="headerSortables[idx].enabled && emitSortEvent(idx)"
30
45
  >
31
46
  {{ headerLabels[idx] }}
47
+ <span
48
+ v-if="
49
+ tableHeader.dashboard &&
50
+ tableHeader.dashboard.status &&
51
+ tableHeader.dashboard.status !== 'Success'
52
+ "
53
+ :title="tableHeader.dashboard && tableHeader.dashboard.message"
54
+ class="icon has-text-danger"
55
+ >
56
+ <i class="fa fa-exclamation-triangle" />
57
+ </span>
32
58
  </th>
33
59
  <th
34
60
  ref="action-section"
@@ -81,6 +107,11 @@
81
107
  </tbody>
82
108
  </template>
83
109
  </table>
110
+
111
+ <!-- table footer info start -->
112
+ <slot name="table-footer-info" />
113
+ <!-- table footer info end -->
114
+
84
115
  <!-- pagination start -->
85
116
  <slot name="table-pagination" />
86
117
  <!-- pagination end -->
@@ -104,6 +135,10 @@ export default defineComponent({
104
135
  type: Array,
105
136
  default: () => [],
106
137
  },
138
+ collapsible: {
139
+ type: Boolean,
140
+ default: false,
141
+ },
107
142
  actionable: {
108
143
  type: Boolean,
109
144
  default: false,
@@ -116,13 +151,15 @@ export default defineComponent({
116
151
  type: Number,
117
152
  default: 1920,
118
153
  },
154
+ columnStriped: {
155
+ type: Boolean,
156
+ default: false,
157
+ },
119
158
  },
120
- emits: ["sort"],
159
+ emits: ["sort", "scroller"],
121
160
  components: {
122
161
  TableContainer: defineAsyncComponent(() =>
123
- import("../../v2/table/TableContainer.vue").then(
124
- (module) => module.default
125
- )
162
+ import("./TableContainer.vue").then((module) => module.default)
126
163
  ),
127
164
  TableRow: defineAsyncComponent(() =>
128
165
  import("./TableRow.vue").then((module) => module.default)
@@ -165,7 +202,7 @@ export default defineComponent({
165
202
  },
166
203
  headerLabels() {
167
204
  return this.tableHeaders.map((th) =>
168
- typeof th === "string" ? th : th?.label || "Label"
205
+ typeof th === "string" ? th : th?.name || "Label"
169
206
  );
170
207
  },
171
208
  },
@@ -176,8 +213,8 @@ export default defineComponent({
176
213
  handler(n) {
177
214
  if (this.headerSortables.length === n.length) {
178
215
  n.forEach((th, idx) => {
179
- if (this.headerSortables[idx].enabled !== !!th?.sortable) {
180
- this.headerSortables[idx].enabled = !!th?.sortable;
216
+ if (this.headerSortables[idx].enabled !== !!th?.sort?.enable) {
217
+ this.headerSortables[idx].enabled = !!th?.sort?.enable;
181
218
  this.headerSortables[idx].mode = "";
182
219
  }
183
220
  });
@@ -190,7 +227,7 @@ export default defineComponent({
190
227
  };
191
228
  } else {
192
229
  return {
193
- enabled: !!th?.sortable,
230
+ enabled: !!th?.sort?.enable,
194
231
  mode: "",
195
232
  };
196
233
  }
@@ -199,7 +236,6 @@ export default defineComponent({
199
236
  },
200
237
  },
201
238
  },
202
-
203
239
  updated() {
204
240
  this.$nextTick(() => {
205
241
  this.onWindowResize();
@@ -207,9 +243,12 @@ export default defineComponent({
207
243
  },
208
244
 
209
245
  methods: {
246
+ handleScroller(value) {
247
+ this.$emit("scroller", value);
248
+ },
210
249
  onWindowResize() {
211
250
  if (this.$refs["ac-table"] && this.isDynamicWidthTable) {
212
- const tableWidth = this.$refs["ac-table"].clientWidth;
251
+ const tableWidth = this.$refs["ac-table"]?.clientWidth;
213
252
  const d = this.fullWidth - tableWidth;
214
253
  this.fakeCellWidth = d;
215
254
  }
@@ -217,7 +256,7 @@ export default defineComponent({
217
256
  emitSortEvent(index) {
218
257
  const emitValue = {
219
258
  index,
220
- label: this.tableHeaders[index].label,
259
+ label: this.tableHeaders[index].name,
221
260
  mode: "",
222
261
  };
223
262
 
@@ -0,0 +1,34 @@
1
+ <template>
2
+ <div class="ac-table-container table-container" ref="tableContainer">
3
+ <slot />
4
+ </div>
5
+ </template>
6
+
7
+ <script lang="ts">
8
+ import { emit } from 'process'
9
+ import { defineComponent, ref, onMounted, nextTick } from 'vue'
10
+
11
+ export default defineComponent({
12
+ emits: ['scroller'],
13
+
14
+ setup(props, { emit }) {
15
+ const tableContainer = ref(null)
16
+
17
+ function isScrollerShowing() {
18
+ return tableContainer.value?.scrollWidth > tableContainer.value?.clientWidth
19
+ }
20
+
21
+ onMounted(() => {
22
+ setTimeout(() => {
23
+ nextTick(() => {
24
+ emit('scroller', isScrollerShowing())
25
+ })
26
+ }, 50)
27
+ })
28
+
29
+ return {
30
+ tableContainer,
31
+ }
32
+ },
33
+ })
34
+ </script>
@@ -1,12 +1,24 @@
1
1
  <template>
2
2
  <router-link
3
3
  v-if="link"
4
+ v-slot="{ navigate }"
4
5
  event="click"
5
6
  :to="link"
6
7
  custom
7
- v-slot="{ navigate }"
8
8
  >
9
- <tr class="is-link" @click="navigate" v-bind="$attrs">
9
+ <tr
10
+ class="is-link"
11
+ v-bind="$attrs"
12
+ data-testid="ac-table-row"
13
+ @click="navigate"
14
+ >
15
+ <table-cell v-if="collapsible">
16
+ <collapsible-button
17
+ modifier-classes="is-square is-light height-20 width-20 is-rounded is-size-7"
18
+ :icon-class="isCollapsed ? 'chevron-right' : 'chevron-down'"
19
+ @click.stop="toggleCollapse"
20
+ />
21
+ </table-cell>
10
22
  <slot />
11
23
  <fake-table-cell
12
24
  v-if="fakeCellWidth > 0"
@@ -16,15 +28,37 @@
16
28
  </router-link>
17
29
  <tr
18
30
  v-else
19
- :class="{ 'is-selected': isSelected, 'is-hoverless': !isSelected }"
31
+ v-bind="$attrs"
32
+ :class="{
33
+ 'is-selected': isSelected,
34
+ 'is-hoverless': !isSelected,
35
+ 'is-disabled': isDisabled,
36
+ }"
37
+ data-testid="ac-table-row"
20
38
  @click.prevent="$emit('rowselect', true)"
21
39
  >
40
+ <table-cell v-if="collapsible">
41
+ <collapsible-button
42
+ modifier-classes="is-square is-light height-20 width-20 is-rounded is-size-7"
43
+ :icon-class="isCollapsed ? 'chevron-right' : 'chevron-down'"
44
+ @click.stop="toggleCollapse"
45
+ />
46
+ </table-cell>
22
47
  <slot />
23
48
  <fake-table-cell
24
49
  v-if="fakeCellWidth > 0"
25
50
  :fake-cell-width="fakeCellWidth"
26
51
  />
27
52
  </tr>
53
+ <transition name="slide-down" mode="out-in" appear>
54
+ <tr v-if="collapsible && !isCollapsed" v-bind="$attrs">
55
+ <table-cell colspan="1000" class="table-inner-shadow">
56
+ <div ref="collapsibleRow" class="collapsible-row">
57
+ <slot name="collapsible-content" />
58
+ </div>
59
+ </table-cell>
60
+ </tr>
61
+ </transition>
28
62
  </template>
29
63
 
30
64
  <script>
@@ -40,21 +74,74 @@ export default defineComponent({
40
74
  type: Boolean,
41
75
  default: false,
42
76
  },
77
+ isDisabled: {
78
+ type: Boolean,
79
+ default: false,
80
+ },
43
81
  fakeCellWidth: {
44
82
  type: Number,
45
83
  default: 0,
46
84
  },
85
+ collapsible: {
86
+ type: Boolean,
87
+ default: false,
88
+ },
47
89
  },
48
90
 
49
- emits: ["rowselect"],
91
+ emits: ["rowselect", "rowexpand", "rowcollapse"],
50
92
 
51
93
  components: {
52
94
  TableCell: defineAsyncComponent(() =>
53
- import("./TableCell.vue").then((module) => module.default)
95
+ import(
96
+ "@appscode/design-system/vue-components/v3/table/TableCell.vue"
97
+ ).then((module) => module.default)
54
98
  ),
55
99
  FakeTableCell: defineAsyncComponent(() =>
56
- import("./FakeTableCell.vue").then((module) => module.default)
100
+ import(
101
+ "@appscode/design-system/vue-components/v3/table/FakeTableCell.vue"
102
+ ).then((module) => module.default)
103
+ ),
104
+ CollapsibleButton: defineAsyncComponent(() =>
105
+ import("@appscode/design-system/vue-components/v3/button/Button.vue")
57
106
  ),
58
107
  },
108
+
109
+ data() {
110
+ return {
111
+ isCollapsed: true,
112
+ };
113
+ },
114
+
115
+ methods: {
116
+ toggleCollapse() {
117
+ const newVal = !this.isCollapsed;
118
+ if (!newVal) {
119
+ this.isCollapsed = newVal;
120
+ // show expand animation
121
+ this.$nextTick(() => {
122
+ setTimeout(() => {
123
+ if (this.$refs.collapsibleRow) {
124
+ this.$refs.collapsibleRow.classList.remove("is-closed");
125
+ this.$refs.collapsibleRow.classList.add("is-active");
126
+ }
127
+ this.$emit("rowexpand", this.collapseRow);
128
+ }, 0);
129
+ });
130
+ } else {
131
+ if (this.$refs.collapsibleRow) {
132
+ this.$refs.collapsibleRow.classList.remove("is-active");
133
+ this.$refs.collapsibleRow.classList.add("is-closed");
134
+ }
135
+ setTimeout(() => {
136
+ // remove row after animation finish
137
+ this.isCollapsed = newVal;
138
+ this.$emit("rowcollapse");
139
+ }, 100);
140
+ }
141
+ },
142
+ collapseRow() {
143
+ this.isCollapsed = true;
144
+ },
145
+ },
59
146
  });
60
147
  </script>