@appscode/design-system 1.1.0-alpha.2 → 1.1.0-alpha.20

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.
@@ -1,6 +1,7 @@
1
1
  @import "initial-variables";
2
2
  @import "derived-variables";
3
3
  @import "mixin";
4
+ @import "extended";
4
5
  @import "typography";
5
6
  @import "default";
6
7
  @import "grid";
@@ -0,0 +1,38 @@
1
+ .has-hover-style{
2
+ cursor: pointer;
3
+
4
+ &::before {
5
+ content: "";
6
+ position: absolute;
7
+ top: 0;
8
+ right: 0;
9
+ bottom: 0;
10
+ left: 0;
11
+ border-top: solid 1px;
12
+ border-bottom: solid 1px;
13
+ transition: 0.3s;
14
+ transform: scaleX(0);
15
+ border-color: #1971bd;
16
+ }
17
+
18
+ &::after {
19
+ content: "";
20
+ position: absolute;
21
+ top: 0;
22
+ right: 0;
23
+ bottom: 0;
24
+ left: 0;
25
+ border-left: solid 1px;
26
+ border-right: solid 1px;
27
+ transition: 0.3s;
28
+ transform: scaleY(0);
29
+ border-color: #1971bd;
30
+ }
31
+
32
+ &:hover {
33
+ &::before,
34
+ &::after {
35
+ transform: scale(1);
36
+ }
37
+ }
38
+ }
@@ -47,7 +47,7 @@ $swift-primary: #3f51b6;
47
47
  --ac-gray-dark: #5f5f5f;
48
48
  --ac-gray-light: #8d8d8d;
49
49
  --ac-gray-lightest: #d1d1d1;
50
- --ac-white-light: #e7e7e7;
50
+ --ac-white-light: #d2e7f9;
51
51
  --ac-white-lighter: #f2f5f8;
52
52
  --ac-white-lightest: #f8f9fb;
53
53
 
@@ -13,7 +13,7 @@
13
13
  justify-content: flex-start;
14
14
  position: relative;
15
15
  z-index: 1;
16
- min-width: 280px;
16
+ justify-content: flex-start;
17
17
 
18
18
  p {
19
19
  color: $ac-primary;
@@ -55,7 +55,6 @@
55
55
  }
56
56
  }
57
57
 
58
-
59
58
  .toast {
60
59
  box-shadow: $ac-shadow-sm;
61
60
  border: 1px solid $ac-white-light;
@@ -3,6 +3,7 @@
3
3
  @import "buttons";
4
4
  @import "breadcumb";
5
5
  @import "ac-card";
6
+ @import "basic-card";
6
7
  @import "ac-multi-select";
7
8
  @import "ac-code-highlight";
8
9
  @import "navbar";
@@ -0,0 +1,118 @@
1
+ .card-details {
2
+ border: 1px solid #d2e7f9;
3
+ padding: 30px 20px;
4
+ width: calc(33.3% - 8px);
5
+ min-width: 400px;
6
+ max-width: 525px;
7
+ // border-radius: 4px;
8
+ transition: 0.3s ease-in-out;
9
+ position: relative;
10
+ z-index: 1;
11
+
12
+ .c-header {
13
+ display: flex;
14
+ margin-bottom: 20px;
15
+
16
+ .c-logo {
17
+ width: 54px;
18
+ height: 54px;
19
+ background: #e8f3fc;
20
+ border-radius: 50%;
21
+ display: flex;
22
+ align-items: center;
23
+ justify-content: center;
24
+ margin-right: 24px;
25
+
26
+ img {
27
+ height: 24px;
28
+ }
29
+ }
30
+
31
+ .c-content {
32
+ width: calc(100% - 78px);
33
+ h4 {
34
+ font-size: 18px;
35
+ line-height: 130%;
36
+ color: #030d17;
37
+ }
38
+ .icon {
39
+ color: #0c365a;
40
+ cursor: pointer;
41
+ position: relative;
42
+ z-index: 1;
43
+ &:after {
44
+ position: absolute;
45
+ content: "";
46
+ border-radius: 50%;
47
+ width: 32px;
48
+ height: 32px;
49
+ background: #e8f3fc;
50
+ opacity: 0;
51
+ visibility: hidden;
52
+ transition: 0.3s ease-in-out;
53
+ z-index: -1;
54
+ }
55
+ &:hover {
56
+ &:after {
57
+ opacity: 1;
58
+ visibility: visible;
59
+ }
60
+ }
61
+ }
62
+ .tags {
63
+ margin-top: 12px;
64
+ }
65
+ }
66
+ }
67
+
68
+ .c-body {
69
+ display: flex;
70
+ flex-wrap: wrap;
71
+ gap: 20px;
72
+ justify-content: space-between;
73
+ p {
74
+ width: calc(25% - 16px);
75
+
76
+ span {
77
+ font-size: 11px;
78
+ color: #666666;
79
+ display: block;
80
+ }
81
+ strong {
82
+ color: #061b2d;
83
+ font-size: 13px;
84
+ font-weight: 400;
85
+ }
86
+ }
87
+ }
88
+ }
89
+
90
+ // ac card
91
+ .card-basic {
92
+ padding: 20px;
93
+ width: calc(25% - 8px);
94
+ max-width: 390px;
95
+ min-width: 290px;
96
+ position: relative;
97
+
98
+ .required {
99
+ position: absolute;
100
+ left: 20px;
101
+ top: -9px;
102
+ }
103
+ .c-header {
104
+ .c-title {
105
+
106
+ h4 {
107
+ font-size: 18px;
108
+ color: #061b2d;
109
+ }
110
+ }
111
+ }
112
+
113
+ .c-body {
114
+ p {
115
+ color: #0C365A;
116
+ }
117
+ }
118
+ }
@@ -17,7 +17,7 @@
17
17
  margin-bottom: 10px;
18
18
  }
19
19
 
20
- p {
20
+ p :not(.ac-notification *){
21
21
  font-size: 13px;
22
22
  margin-bottom: 10px;
23
23
  color: $ac-color-value;
@@ -237,6 +237,12 @@
237
237
  }
238
238
  }
239
239
 
240
+ .pass-strength {
241
+ position: absolute;
242
+ right: 30px;
243
+ top: 7px;
244
+ }
245
+
240
246
  // dark theme end
241
247
  /****************************************
242
248
  Responsive Classes
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@appscode/design-system",
3
- "version": "1.1.0-alpha.2",
3
+ "version": "1.1.0-alpha.20",
4
4
  "description": "A design system for Appscode websites and dashboards made using Bulma",
5
5
  "main": "main.scss",
6
6
  "scripts": {
@@ -5,6 +5,7 @@
5
5
  v-if="!hideHeader"
6
6
  :header-title="tableTitle"
7
7
  :header-sub-title="tableSubTitle"
8
+ :remove-border-bottom="removeBorderBottom"
8
9
  :class="{ 'pl-0 pr-0': removeTableHeaderPadding }"
9
10
  >
10
11
  <header-item>
@@ -22,36 +23,40 @@ export default {
22
23
  props: {
23
24
  removeTableHeaderPadding: {
24
25
  type: Boolean,
25
- default: false
26
+ default: false,
26
27
  },
27
28
  tableTitle: {
28
29
  type: String,
29
- default: "Table"
30
+ default: "Table",
30
31
  },
31
32
  tableSubTitle: {
32
33
  type: String,
33
- default: ""
34
+ default: "",
34
35
  },
35
36
  searchable: {
36
37
  type: Boolean,
37
- default: true
38
+ default: true,
38
39
  },
39
40
  hideHeader: {
40
41
  type: Boolean,
41
- default: false
42
- }
42
+ default: false,
43
+ },
44
+ removeBorderBottom: {
45
+ type: Boolean,
46
+ default: false,
47
+ },
43
48
  },
44
49
  components: {
45
50
  ContentLayout: () => import("./ContentLayout.vue"),
46
51
  ContentHeader: () => import("./ContentHeader.vue"),
47
52
  HeaderItem: () => import("../header/HeaderItem.vue"),
48
- SearchBar: () => import("../searchbars/SearchBar.vue")
53
+ SearchBar: () => import("../searchbars/SearchBar.vue"),
49
54
  },
50
55
 
51
56
  data() {
52
57
  return {
53
- searchText: ""
58
+ searchText: "",
54
59
  };
55
- }
60
+ },
56
61
  };
57
62
  </script>
@@ -32,6 +32,7 @@
32
32
  <!-- modal body start -->
33
33
  <div
34
34
  class="ac-modal-body ac-vscrollbar"
35
+ :class="modifierBodyClasses"
35
36
  data-testid="ac-modal-content-with-scroll"
36
37
  >
37
38
  <div class="ac-modal-content">
@@ -45,11 +46,7 @@
45
46
  <!-- modal footer start -->
46
47
  <div
47
48
  v-if="!hideActionFooter"
48
- class="
49
- ac-modal-footer
50
- action-footer
51
- is-flex is-align-items-center is-justify-content-space-between
52
- "
49
+ class="ac-modal-footer action-footer is-flex is-align-items-center is-justify-content-space-between"
53
50
  >
54
51
  <div>
55
52
  <slot name="modal-footer-left" />
@@ -91,6 +88,10 @@ export default {
91
88
  type: Boolean,
92
89
  default: false,
93
90
  },
91
+ modifierBodyClasses: {
92
+ type: String,
93
+ default: "",
94
+ },
94
95
  },
95
96
 
96
97
  components: {
@@ -110,6 +110,11 @@
110
110
  </tbody>
111
111
  </template>
112
112
  </table>
113
+
114
+ <!-- table footer info start -->
115
+ <slot name="table-footer-info" />
116
+ <!-- table footer info end -->
117
+
113
118
  <!-- pagination start -->
114
119
  <slot name="table-pagination" />
115
120
  <!-- pagination end -->
@@ -0,0 +1,40 @@
1
+ <template>
2
+ <!-- single card wrapper start -->
3
+ <div class="card-basic b-1">
4
+ <div class="c-header is-flex is-justify-content-space-between">
5
+ <div
6
+ v-if="isRequired"
7
+ class="tag has-background-warning has-text-secondary is-rounded required"
8
+ >
9
+ Required
10
+ </div>
11
+
12
+ <div class="c-title is-flex is-align-items-center">
13
+ <div class="icon mr-8">
14
+ <slot name="card-logo" />
15
+ </div>
16
+ <h4><slot name="card-title" /></h4>
17
+ </div>
18
+ <!-- <span class="tag has-background-dark-light has-text-dark is-rounded"
19
+ >Dark</span
20
+ > -->
21
+ <slot name="card-status" />
22
+ </div>
23
+ <div class="c-body">
24
+ <p><slot name="card-sub-title" /></p>
25
+ </div>
26
+ </div>
27
+ <!-- single card wrapper end -->
28
+ </template>
29
+ <script setup lang="ts">
30
+ withDefaults(
31
+ defineProps<{
32
+ isRequired: boolean
33
+ statusClass: string
34
+ }>(),
35
+ {
36
+ isRequired: false,
37
+ statusClass: 'has-background-primary-light has-text-primary',
38
+ }
39
+ )
40
+ </script>
@@ -0,0 +1,5 @@
1
+ <template>
2
+ <div class="is-flex is-flex-wrap-wrap" style="gap: 16px">
3
+ <slot />
4
+ </div>
5
+ </template>
@@ -0,0 +1,27 @@
1
+ <script setup lang="ts">
2
+ const { hasOptionButtons } = withDefaults(
3
+ defineProps<{ hasOptionButtons: boolean }>(),
4
+ { hasOptionButtons: false }
5
+ )
6
+ </script>
7
+ <template>
8
+ <div class="card-details">
9
+ <div class="c-header">
10
+ <div class="c-logo">
11
+ <slot name="card-logo" />
12
+ </div>
13
+ <div class="c-content">
14
+ <div class="is-flex is-justify-content-space-between">
15
+ <h4><slot name="card-title" /></h4>
16
+ <slot v-if="hasOptionButtons" name="option-buttons" />
17
+ </div>
18
+ <div class="tags">
19
+ <slot name="card-tags" />
20
+ </div>
21
+ </div>
22
+ </div>
23
+ <div class="c-body">
24
+ <slot name="card-body" />
25
+ </div>
26
+ </div>
27
+ </template>
@@ -0,0 +1,6 @@
1
+ <template>
2
+ <p>
3
+ <span><slot name="row-title" /></span>
4
+ <strong><slot name="row-value" /></strong>
5
+ </p>
6
+ </template>
@@ -0,0 +1,5 @@
1
+ <template>
2
+ <div class="is-flex is-flex-wrap-wrap" style="gap: 8px">
3
+ <slot />
4
+ </div>
5
+ </template>
@@ -5,6 +5,7 @@
5
5
  v-if="!hideHeader"
6
6
  :header-title="tableTitle"
7
7
  :header-sub-title="tableSubTitle"
8
+ :remove-border-bottom="removeBorderBottom"
8
9
  :class="{ 'pl-0 pr-0': removeTableHeaderPadding }"
9
10
  >
10
11
  <template #title-right-actions>
@@ -50,6 +51,10 @@ export default defineComponent({
50
51
  type: Boolean,
51
52
  default: false,
52
53
  },
54
+ removeBorderBottom: {
55
+ type: Boolean,
56
+ default: false,
57
+ },
53
58
  },
54
59
  components: {
55
60
  ContentLayout: defineAsyncComponent(() =>
@@ -30,6 +30,7 @@
30
30
  <!-- modal body start -->
31
31
  <div
32
32
  class="ac-modal-body ac-vscrollbar"
33
+ :class="modifierBodyClasses"
33
34
  data-testid="ac-modal-content-with-scroll"
34
35
  >
35
36
  <div class="ac-modal-content">
@@ -92,6 +93,10 @@ export default defineComponent({
92
93
  type: Boolean,
93
94
  default: false,
94
95
  },
96
+ modifierBodyClasses: {
97
+ type: String,
98
+ default: "",
99
+ },
95
100
  },
96
101
  emits: ["closemodal"],
97
102
 
@@ -110,7 +110,6 @@ import {
110
110
  Ref,
111
111
  toRefs,
112
112
  watch,
113
- watchEffect,
114
113
  } from "vue";
115
114
  import { defineAsyncComponent, ref } from "vue";
116
115
  import { Task, TaskLog } from "../../../typings/long-running-tasks.ts";
@@ -173,7 +172,7 @@ const activeStepId: Ref<string> = ref("");
173
172
  // to find active task faster
174
173
  const idToStepIndex: Ref<Record<string, number>> = ref({});
175
174
  const activeTask = computed(() => {
176
- const task = tasks.value.find((task) => task.id === activeStepId.value);
175
+ const task = tasks.value[idToStepIndex.value[activeStepId.value]];
177
176
  return task;
178
177
  });
179
178
 
@@ -207,6 +206,7 @@ function handleTaskLog(log: TaskLog) {
207
206
  task.status = log.status;
208
207
  if (log.status === "Failed") {
209
208
  task.logs.push(log.error || "");
209
+ errorCtx.value?.onError(log.error);
210
210
  } else {
211
211
  task.logs.push(log.msg || "");
212
212
  }
@@ -252,12 +252,36 @@ onBeforeUnmount(() => {
252
252
  subscription && subscription.unsubscribe();
253
253
  });
254
254
 
255
+ const longRunningTaskStatus = computed(() => {
256
+ let successTaskCount = 0;
257
+ let failedTaskCount = 0;
258
+
259
+ // get count of success and failed task
260
+ tasks.value.forEach((task) => {
261
+ if (task?.status === "Success") successTaskCount++;
262
+ else if (task?.status === "Failed") failedTaskCount++;
263
+ });
264
+
265
+ if (tasks.value.length === 0) return "NotStarted";
266
+ // if all the task has been successful
267
+ else if (successTaskCount === tasks.value.length) {
268
+ return "Success";
269
+ }
270
+ // if all the task has been completed and some tasks are failed
271
+ else if (
272
+ failedTaskCount &&
273
+ successTaskCount + failedTaskCount === tasks.value.length
274
+ ) {
275
+ return "Failed";
276
+ } else return "Pending";
277
+ });
278
+
255
279
  // modal close / footer feature
256
280
  const enableModalClose = computed(() => {
257
281
  return (
258
282
  connectionError.value ||
259
- activeTask.value?.status === "Failed" ||
260
- activeTask.value?.status === "Success"
283
+ longRunningTaskStatus.value === "Failed" ||
284
+ longRunningTaskStatus.value === "Success"
261
285
  );
262
286
  });
263
287
  const enableModalFooter = computed(() => {
@@ -265,47 +289,50 @@ const enableModalFooter = computed(() => {
265
289
  });
266
290
 
267
291
  // generate report issue title with error step title
268
- const getReportIssueTitle = (): string => {
292
+ const getReportIssueInfo = (): { title: string; body: string } => {
269
293
  const stepTitlesFromErrorTasks: Array<string> = [];
294
+ const stepLogsFromErrorTasks: Array<string> = [];
270
295
  tasks.value.forEach((task) => {
271
296
  // if this taskLog is error task, push it to array
272
297
  if (task.error) {
273
- stepTitlesFromErrorTasks.push(task.step);
298
+ stepTitlesFromErrorTasks.push(task?.step);
299
+ stepLogsFromErrorTasks.push(task?.logs[task?.logs?.length - 1] || "");
274
300
  }
275
301
  });
276
- // return final string
277
- return stepTitlesFromErrorTasks.join(", ");
302
+ // return final object
303
+ return {
304
+ title: stepTitlesFromErrorTasks.join(", "),
305
+ body: stepLogsFromErrorTasks.join(", "),
306
+ };
278
307
  };
279
308
 
280
309
  // report button
281
- const showReportButton = computed(() => activeTask.value?.status === "Failed");
310
+ const showReportButton = computed(
311
+ () => longRunningTaskStatus.value === "Failed"
312
+ );
282
313
  function onReportIssueClick() {
283
- const url = `https://github.com/bytebuilders/community/issues/new?title=Chart Install: ${getReportIssueTitle()}&labels[]=bug&body=${
284
- window.location.href
285
- } %0A%0A %60%60%60 %0A ${
286
- activeTask.value?.logs[activeTask.value?.logs.length - 1 || 0]
314
+ const url = `https://github.com/bytebuilders/community/issues/new?title=Chart Install: ${
315
+ getReportIssueInfo().title
316
+ }&labels[]=bug&body=${window.location.href} %0A%0A %60%60%60 %0A ${
317
+ getReportIssueInfo().body
287
318
  } %0A %60%60%60`;
288
319
  window.open(url, "_blank");
289
320
  }
290
321
 
291
322
  // success button
292
323
  const showSuccessButton = computed(
293
- () => activeTask.value?.status === "Success" && successCtx.value?.btnTitle
324
+ () =>
325
+ longRunningTaskStatus.value === "Success" && !!successCtx.value?.btnTitle
294
326
  );
295
327
 
296
328
  // execute on success and on error functions
297
- watch(
298
- () => activeTask.value?.status,
299
- (n) => {
300
- if (n === "Success") {
301
- successCtx.value.onSuccess();
302
- } else if (n === "Failed") {
303
- errorCtx.value.onError(
304
- activeTask.value?.logs[activeTask.value?.logs.length - 1 || 0] || ""
305
- );
306
- }
329
+ watch(longRunningTaskStatus, (n) => {
330
+ if (n === "Success") {
331
+ successCtx.value.onSuccess();
332
+ } else if (n === "Failed") {
333
+ errorCtx.value?.onError("Operation Failed");
307
334
  }
308
- );
335
+ });
309
336
  </script>
310
337
 
311
338
  <style scoped lang="scss">
@@ -0,0 +1,61 @@
1
+ <template>
2
+ <!-- alert-message area start -->
3
+ <!-- plsease, use this class name ('.is-info' 'is-success', 'is-error', 'is-warning') -->
4
+ <div :class="`ac-notification is-${notificationType} mb-15`">
5
+ <p>
6
+ <i v-if="!hideIcon" :class="`fa ${iconClass} mr-5`"></i
7
+ ><span v-html="getSanitizedHtml(content)"></span>
8
+ <ac-button
9
+ v-if="actionButton?.show"
10
+ :title="actionButton?.title"
11
+ :icon-class="actionButton?.iconClass"
12
+ data-testid="notification-action-button"
13
+ @click.prevent="actionButton?.action()"
14
+ >
15
+ </ac-button>
16
+ </p>
17
+ </div>
18
+ <!-- alert-message area end -->
19
+ </template>
20
+
21
+ <script setup lang="ts">
22
+ import { toRefs, computed, defineAsyncComponent } from "vue";
23
+ import DOMPurify from "dompurify";
24
+
25
+ const AcButton = defineAsyncComponent(
26
+ () => import("@appscode/design-system/vue-components/v3/button/Button.vue")
27
+ );
28
+
29
+ const props = withDefaults(
30
+ defineProps<{
31
+ notificationType: string;
32
+ content: string;
33
+ hideIcon: boolean;
34
+ actionButton?: {
35
+ show: boolean;
36
+ title: string;
37
+ iconClass: string;
38
+ action: (...args: any) => void | undefined;
39
+ };
40
+ }>(),
41
+ {
42
+ notificationType: "",
43
+ content: "",
44
+ hideIcon: false,
45
+ actionButton: undefined,
46
+ }
47
+ );
48
+
49
+ const { notificationType, content, hideIcon, actionButton } = toRefs(props);
50
+
51
+ const iconClass = computed(() => {
52
+ if (notificationType.value === "success") return "fa-check-circle";
53
+ else if (notificationType.value === "info") return "fa-info-circle";
54
+ else if (notificationType.value === "error") return "fa-times-circle";
55
+ else return "fa-info-circle";
56
+ });
57
+
58
+ const getSanitizedHtml = (content: string) => {
59
+ return DOMPurify.sanitize(content || "");
60
+ };
61
+ </script>
@@ -109,6 +109,11 @@
109
109
  </tbody>
110
110
  </template>
111
111
  </table>
112
+
113
+ <!-- table footer info start -->
114
+ <slot name="table-footer-info" />
115
+ <!-- table footer info end -->
116
+
112
117
  <!-- pagination start -->
113
118
  <slot name="table-pagination" />
114
119
  <!-- pagination end -->