@appscode/design-system 0.0.21-alpha.2 → 0.4.27

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 (165) 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 +319 -110
  4. package/base/utilities/_derived-variables.scss +8 -15
  5. package/base/utilities/_grid.scss +29 -0
  6. package/base/utilities/_initial-variables.scss +111 -72
  7. package/base/utilities/_mixin.scss +90 -10
  8. package/base/utilities/_typography.scss +29 -19
  9. package/base/utilities/dark-theme.scss +26 -0
  10. package/components/_ac-accordion.scss +15 -5
  11. package/components/_ac-alert-box.scss +109 -26
  12. package/components/_ac-card.scss +71 -24
  13. package/components/_ac-code-highlight.scss +7 -1
  14. package/components/_ac-content-layout.scss +5 -5
  15. package/components/_ac-drag.scss +8 -6
  16. package/components/_ac-input.scss +196 -38
  17. package/components/_ac-modal.scss +6 -5
  18. package/components/_ac-multi-select.scss +281 -23
  19. package/components/_ac-options.scss +31 -16
  20. package/components/_ac-report.scss +53 -0
  21. package/components/_ac-select-box.scss +15 -5
  22. package/components/_ac-table.scss +160 -39
  23. package/components/_ac-tabs.scss +86 -23
  24. package/components/_ac-tags.scss +87 -2
  25. package/components/_ac-terminal.scss +270 -0
  26. package/components/_all.scss +28 -0
  27. package/components/_app-drawer.scss +134 -0
  28. package/components/_breadcumb.scss +8 -3
  29. package/components/_buttons.scss +96 -62
  30. package/components/_card-body-wrapper.scss +3 -3
  31. package/components/_dashboard-header.scss +33 -1
  32. package/components/_direct-deploy.scss +69 -0
  33. package/components/_go-to-top.scss +1 -1
  34. package/components/_graph.scss +45 -0
  35. package/components/_image-upload.scss +6 -4
  36. package/components/_left-sidebar-menu.scss +212 -52
  37. package/components/_monaco-editor.scss +1 -1
  38. package/components/_navbar.scss +193 -31
  39. package/components/_overview-info.scss +4 -4
  40. package/components/_overview-page.scss +1 -2
  41. package/components/_pagination.scss +45 -7
  42. package/components/_payment-card.scss +28 -12
  43. package/components/_preloader.scss +1 -1
  44. package/components/_preview-modal.scss +22 -9
  45. package/components/_pricing-table.scss +1 -1
  46. package/components/_progress-bar.scss +5 -5
  47. package/components/_subscription-card.scss +15 -8
  48. package/components/_table-of-content.scss +1 -1
  49. package/components/_tfa.scss +69 -0
  50. package/components/_transitions.scss +261 -0
  51. package/components/_widget-menu.scss +9 -9
  52. package/components/_wizard.scss +33 -20
  53. package/components/ac-toaster/_ac-toasted.scss +40 -8
  54. package/components/bbum/_all.scss +9 -0
  55. package/components/bbum/_card-team.scss +18 -10
  56. package/components/bbum/_information-center.scss +19 -5
  57. package/components/bbum/_mobile-desktop.scss +6 -6
  58. package/components/bbum/_post.scss +5 -4
  59. package/components/bbum/_sign-up-notification.scss +6 -6
  60. package/components/bbum/_single-post-preview.scss +10 -10
  61. package/components/bbum/_user-profile.scss +97 -90
  62. package/components/ui-builder/_ui-builder.scss +98 -21
  63. package/components/ui-builder/_vue-open-api.scss +104 -0
  64. package/layouts/_404.scss +159 -0
  65. package/layouts/_all.scss +2 -0
  66. package/layouts/_code-preview.scss +19 -8
  67. package/main.scss +6 -53
  68. package/package.json +4 -7
  69. package/plugins/caching.ts +243 -0
  70. package/plugins/theme.js +142 -0
  71. package/plugins/time-convert.js +49 -0
  72. package/plugins/vue-toaster.js +10 -6
  73. package/vue-components/v2/banner/Banner.vue +2 -2
  74. package/vue-components/v2/breadcrumbs/Breadcrumb.vue +97 -0
  75. package/vue-components/v2/button/Button.vue +10 -1
  76. package/vue-components/v2/button/DownloadBtn.vue +45 -0
  77. package/vue-components/v2/card/Card.vue +1 -0
  78. package/vue-components/v2/card/CardContent.vue +5 -0
  79. package/vue-components/v2/card/CardHeader.vue +12 -0
  80. package/vue-components/v2/card/OverviewCard.vue +10 -0
  81. package/vue-components/v2/card/OverviewCards.vue +5 -0
  82. package/vue-components/v2/card/PaymentCard.vue +69 -0
  83. package/vue-components/v2/card/PaymentCardOptionButtons.vue +35 -0
  84. package/vue-components/v2/card/PaymentCards.vue +44 -0
  85. package/vue-components/v2/content/ContentHeader.vue +9 -5
  86. package/vue-components/v2/content/ContentTable.vue +12 -7
  87. package/vue-components/v2/editor/Editor.vue +38 -5
  88. package/vue-components/v2/editor/FilteredFileEditor.vue +189 -0
  89. package/vue-components/v2/editor/MonacoEditor.vue +125 -0
  90. package/vue-components/v2/editor/ResourceKeyValueEditor.vue +209 -0
  91. package/vue-components/v2/form/Form.vue +12 -7
  92. package/vue-components/v2/form-fields/Input.vue +1 -1
  93. package/vue-components/v2/header/Header.vue +0 -1
  94. package/vue-components/v2/loaders/ResourceLoader.vue +101 -0
  95. package/vue-components/v2/loaders/SidebarLoader.vue +43 -0
  96. package/vue-components/v2/modal/Modal.vue +40 -7
  97. package/vue-components/v2/modals/DeleteConfirmationModal.vue +79 -0
  98. package/vue-components/v2/modals/JsonShowModal.vue +12 -3
  99. package/vue-components/v2/navbar/Appdrawer.vue +10 -9
  100. package/vue-components/v2/navbar/ThemeMode.vue +120 -0
  101. package/vue-components/v2/navbar/User.vue +229 -17
  102. package/vue-components/v2/notification/Notification.vue +101 -0
  103. package/vue-components/v2/notification/NotificationItem.vue +44 -0
  104. package/vue-components/v2/pagination/Pagination.vue +24 -4
  105. package/vue-components/v2/preloader/Preloader.vue +5 -5
  106. package/vue-components/v2/sidebar/ClusterSwitcher.vue +126 -0
  107. package/vue-components/v2/sidebar/SidebarItem.vue +24 -2
  108. package/vue-components/v2/sidebar/SidebarItemWithDropDown.vue +19 -20
  109. package/vue-components/v2/tab/TabItem.vue +1 -1
  110. package/vue-components/v2/table/FakeTableCell.vue +36 -0
  111. package/vue-components/v2/table/InfoTable.vue +13 -3
  112. package/vue-components/v2/table/NarrowTable.vue +0 -2
  113. package/vue-components/v2/table/Table.vue +170 -10
  114. package/vue-components/v2/table/TableRow.vue +29 -2
  115. package/vue-components/v2/table/table-cell/CellValue.vue +33 -4
  116. package/vue-components/v2/table/table-cell/GenericCell.vue +56 -0
  117. package/vue-components/v2/table/table-cell/ObjectCell.vue +4 -1
  118. package/vue-components/v2/tabs/EditorTabs.vue +1 -1
  119. package/vue-components/v3/button/Button.vue +78 -0
  120. package/vue-components/v3/content/ContentHeader.vue +55 -0
  121. package/vue-components/v3/content/ContentTable.vue +83 -0
  122. package/vue-components/v3/dropdown/DropdownDivider.vue +3 -0
  123. package/vue-components/v3/dropdown/DropdownItem.vue +5 -0
  124. package/vue-components/v3/dropdown/DropdownMenu.vue +111 -0
  125. package/vue-components/v3/editor/Editor.vue +160 -0
  126. package/vue-components/v3/editor/FilteredFileEditor.vue +186 -0
  127. package/vue-components/v3/editor/MonacoEditor.vue +131 -0
  128. package/vue-components/v3/editor/ResourceKeyValueEditor.vue +125 -0
  129. package/vue-components/v3/form/Form.vue +63 -0
  130. package/vue-components/v3/form-fields/Input.vue +22 -0
  131. package/vue-components/v3/header/Header.vue +45 -0
  132. package/vue-components/v3/header/HeaderItem.vue +5 -0
  133. package/vue-components/v3/header/HeaderItems.vue +5 -0
  134. package/vue-components/v3/loaders/ResourceLoader.vue +83 -0
  135. package/vue-components/v3/loaders/SidebarLoader.vue +34 -0
  136. package/vue-components/v3/long-running-tasks/LongRunningTaskItem.vue +92 -0
  137. package/vue-components/v3/modal/Modal.vue +158 -0
  138. package/vue-components/v3/modals/DeleteConfirmationModal.vue +85 -0
  139. package/vue-components/v3/modals/JsonShowModal.vue +96 -0
  140. package/vue-components/v3/modals/LongRunningTasksModal.vue +373 -0
  141. package/vue-components/v3/navbar/Appdrawer.vue +63 -0
  142. package/vue-components/v3/navbar/ThemeMode.vue +120 -0
  143. package/vue-components/v3/navbar/User.vue +288 -0
  144. package/vue-components/v3/notification/Notification.vue +98 -0
  145. package/vue-components/v3/notification/NotificationItem.vue +52 -0
  146. package/vue-components/v3/pagination/Pagination.vue +172 -0
  147. package/vue-components/v3/searchbars/SearchBar.vue +47 -0
  148. package/vue-components/v3/sidebar/ClusterSwitcher.vue +133 -0
  149. package/vue-components/v3/sidebar/SidebarItemWithDropDown.vue +120 -0
  150. package/vue-components/v3/tab/TabItem.vue +17 -0
  151. package/vue-components/v3/table/FakeTableCell.vue +39 -0
  152. package/vue-components/v3/table/InfoTable.vue +105 -0
  153. package/vue-components/v3/table/MultiInfoTable.vue +143 -0
  154. package/vue-components/v3/table/Table.vue +272 -0
  155. package/vue-components/v3/table/TableCell.vue +28 -0
  156. package/vue-components/v3/table/TableContainer.vue +34 -0
  157. package/vue-components/v3/table/TableRow.vue +147 -0
  158. package/vue-components/v3/table/table-cell/ArrayCell.vue +111 -0
  159. package/vue-components/v3/table/table-cell/CellValue.vue +133 -0
  160. package/vue-components/v3/table/table-cell/GenericCell.vue +75 -0
  161. package/vue-components/v3/table/table-cell/ObjectCell.vue +110 -0
  162. package/vue-components/v3/table/table-cell/ValueWithModal.vue +43 -0
  163. package/vue-components/v3/tabs/EditorTabs.vue +36 -0
  164. package/vue-components/v3/tag/Tag.vue +17 -0
  165. package/vue-components/v3/terminal/LongRunningTaskTerminal.vue +148 -0
@@ -0,0 +1,63 @@
1
+ <template>
2
+ <div class="app-drawer-wrapper is-flex">
3
+ <div
4
+ class="drawer-icon is-flex is-justify-content-center is-align-items-center"
5
+ >
6
+ <svg
7
+ class="gb_We"
8
+ focusable="false"
9
+ viewBox="0 0 24 24"
10
+ style="width: 22px;margin-top: 2px;"
11
+ :style="{ fill: 'white' }"
12
+ >
13
+ <path
14
+ d="M6,8c1.1,0 2,-0.9 2,-2s-0.9,-2 -2,-2 -2,0.9 -2,2 0.9,2 2,2zM12,20c1.1,0 2,-0.9 2,-2s-0.9,-2 -2,-2 -2,0.9 -2,2 0.9,2 2,2zM6,20c1.1,0 2,-0.9 2,-2s-0.9,-2 -2,-2 -2,0.9 -2,2 0.9,2 2,2zM6,14c1.1,0 2,-0.9 2,-2s-0.9,-2 -2,-2 -2,0.9 -2,2 0.9,2 2,2zM12,14c1.1,0 2,-0.9 2,-2s-0.9,-2 -2,-2 -2,0.9 -2,2 0.9,2 2,2zM16,6c0,1.1 0.9,2 2,2s2,-0.9 2,-2 -0.9,-2 -2,-2 -2,0.9 -2,2zM12,8c1.1,0 2,-0.9 2,-2s-0.9,-2 -2,-2 -2,0.9 -2,2 0.9,2 2,2zM18,14c1.1,0 2,-0.9 2,-2s-0.9,-2 -2,-2 -2,0.9 -2,2 0.9,2 2,2zM18,20c1.1,0 2,-0.9 2,-2s-0.9,-2 -2,-2 -2,0.9 -2,2 0.9,2 2,2z"
15
+ ></path>
16
+ </svg>
17
+ </div>
18
+ <!-- dropdown start -->
19
+ <div class="ac-menu-content app-drawer-dropdown is-active">
20
+ <ul>
21
+ <li v-for="app in apps" :key="app.url">
22
+ <a :href="app.url">
23
+ <article class="media">
24
+ <figure class="media-left">
25
+ <p class="image">
26
+ <img :src="app.icon_url" />
27
+ </p>
28
+ </figure>
29
+ <div class="media-content">
30
+ <div class="content">
31
+ <p>
32
+ <strong>{{ app.title }}</strong>
33
+ <span>{{ app.sub_title }}</span>
34
+ </p>
35
+ </div>
36
+ </div>
37
+ </article>
38
+ </a>
39
+ </li>
40
+ </ul>
41
+ </div>
42
+ </div>
43
+ </template>
44
+
45
+ <script>
46
+ import { defineComponent, defineAsyncComponent } from "vue";
47
+
48
+ export default defineComponent({
49
+ props: {
50
+ apps: {
51
+ type: Array,
52
+ default: () => []
53
+ }
54
+ },
55
+ components: {
56
+ NavbarItemContent: defineAsyncComponent(() =>
57
+ import("../../v2/navbar/NavbarItemContent.vue").then(
58
+ module => module.default
59
+ )
60
+ )
61
+ }
62
+ });
63
+ </script>
@@ -0,0 +1,120 @@
1
+ <template>
2
+ <li class="mt-10 b-t-1 pt-10">
3
+ <ul class="ac-vscrollbar">
4
+ <li>
5
+ <div class="ac-menu-contentt theme-choicee">
6
+ <ul class="is-flex is-flex-direction-row is-justify-content-center">
7
+ <li
8
+ v-for="theme of Object.keys(themeModes)"
9
+ :title="themeModes[theme].displayName"
10
+ @click="themeMode = theme"
11
+ class="p-10 pl-30 pr-30 is-flex-grow-1 has-text-centered"
12
+ :class="{ 'is-active': themeMode === theme }"
13
+ :key="theme"
14
+ >
15
+ <i :class="['fa', themeModes[theme].iconClass]" />
16
+ </li>
17
+ </ul>
18
+ </div>
19
+ </li>
20
+ </ul>
21
+ </li>
22
+ </template>
23
+ <script>
24
+ import { defineComponent } from "vue";
25
+
26
+ export default defineComponent({
27
+ data() {
28
+ return {
29
+ themeMode: "",
30
+ themeModes: {
31
+ light: {
32
+ displayName: "Light Theme",
33
+ iconClass: "fa-sun-o",
34
+ },
35
+ dark: {
36
+ displayName: "Dark Theme",
37
+ iconClass: "fa-moon-o",
38
+ },
39
+ system: {
40
+ displayName: "System Theme",
41
+ iconClass: "fa-desktop",
42
+ },
43
+ },
44
+ };
45
+ },
46
+
47
+ emits: ["set:theme"],
48
+
49
+ mounted() {
50
+ // get theme mode from localStorage or set default one
51
+ this.themeMode = localStorage.getItem("themeMode") || "light";
52
+ },
53
+
54
+ unmounted() {
55
+ this.removeColorSchemeEventListener();
56
+ },
57
+
58
+ watch: {
59
+ themeMode: {
60
+ handler(n) {
61
+ this.onThemeModeChange(n);
62
+ },
63
+ },
64
+ },
65
+
66
+ methods: {
67
+ // handle theme mode button click
68
+ toggleTheme() {
69
+ if (this.themeMode === "light") this.themeMode = "dark";
70
+ else if (this.themeMode === "dark") this.themeMode = "system";
71
+ else if (this.themeMode === "system") this.themeMode = "light";
72
+ },
73
+
74
+ // triggered when theme mode is updated
75
+ onThemeModeChange(n) {
76
+ localStorage.setItem("themeMode", n);
77
+
78
+ let theme = n;
79
+ if (n === "system") {
80
+ const isDarkMode =
81
+ window.matchMedia &&
82
+ window.matchMedia("(prefers-color-scheme: dark)").matches;
83
+ this.addColorSchemeEventListener();
84
+ theme = isDarkMode ? "dark" : "light";
85
+ } else {
86
+ this.removeColorSchemeEventListener();
87
+ }
88
+ this.$emit("set:theme", theme);
89
+ this.handleDarkThemeClass(theme);
90
+ },
91
+
92
+ // add proper css class to update the ui theme
93
+ handleDarkThemeClass(currentTheme) {
94
+ if (currentTheme === "light") {
95
+ document.documentElement.classList.remove("is-dark-theme");
96
+ } else {
97
+ document.documentElement.classList.add("is-dark-theme");
98
+ }
99
+ },
100
+
101
+ // add system theme listener event
102
+ addColorSchemeEventListener() {
103
+ window
104
+ .matchMedia("(prefers-color-scheme: dark)")
105
+ .addEventListener("change", this.handleSystemThemeChange);
106
+ },
107
+
108
+ // remove system theme listener event
109
+ removeColorSchemeEventListener() {
110
+ window
111
+ .matchMedia("(prefers-color-scheme: dark)")
112
+ .removeEventListener("change", this.handleSystemThemeChange);
113
+ },
114
+
115
+ handleSystemThemeChange() {
116
+ this.onThemeModeChange(this.themeMode);
117
+ },
118
+ },
119
+ });
120
+ </script>
@@ -0,0 +1,288 @@
1
+ <template>
2
+ <navbar-item>
3
+ <button class="button ac-nav-button ac-profile-button">
4
+ {{ user.full_name || user.username }}
5
+ <i class="fa fa-angle-down" aria-hidden="true"></i>
6
+ <div class="ac-user-profile">
7
+ <img :src="user.avatar_url" alt="User Photo" />
8
+ </div>
9
+ </button>
10
+ <navbar-item-content class="navbar-dropdown-wrapper">
11
+ <div
12
+ v-if="user.username"
13
+ class="user-profile-wrapper"
14
+ @mouseleave="onMouseLeave()"
15
+ >
16
+ <div class="profile-area">
17
+ <div class="profile-photo">
18
+ <img
19
+ :src="user.avatar_url"
20
+ alt="User Photo"
21
+ class="width-50 height-50"
22
+ />
23
+ <button class="camera-icon"></button>
24
+ </div>
25
+ <div class="profile-info" style="width: calc(100% - 60px)">
26
+ <a
27
+ :href="`${serverDomain}/${user.username}`"
28
+ :title="user.username.toUpperCase()"
29
+ data-testid="user-profile-link"
30
+ class="line-break-anywhere is-ellipsis-1"
31
+ >{{ user.username.toUpperCase() }}</a
32
+ >
33
+ <a :href="`mailto:${user.email}`"> {{ user.email }}</a>
34
+ </div>
35
+ </div>
36
+ <transition-group name="list" tag="ul">
37
+ <li key="settings">
38
+ <a
39
+ data-testid="user-settings-link"
40
+ :href="`${serverDomain}/user/settings/`"
41
+ >Settings</a
42
+ >
43
+ </li>
44
+ <li v-if="user.is_admin" key="site-admin">
45
+ <a data-testid="site-admin-link" :href="`${accountsDomain}/admin`"
46
+ >Site Administration</a
47
+ >
48
+ </li>
49
+ <li
50
+ v-if="showAccountSwitcher"
51
+ :class="`is-${dropDownStatus}`"
52
+ key="switcher"
53
+ >
54
+ <a
55
+ class="
56
+ ac-dropdown-button
57
+ is-fullwidth
58
+ is-flex
59
+ is-justify-content-space-between
60
+ is-align-items-center
61
+ "
62
+ @click="toggleList()"
63
+ >
64
+ <span>Switch Account</span>
65
+ <span
66
+ ><i
67
+ :class="`fa fa-angle-${
68
+ dropDownStatus === 'open' ? 'up' : 'down'
69
+ }`"
70
+ ></i
71
+ ></span>
72
+ </a>
73
+ <transition-group
74
+ name="list"
75
+ tag="ul"
76
+ class="ac-vscrollbar"
77
+ ref="dropdownItems"
78
+ :style="{ maxHeight: dropDownSectionHeight }"
79
+ >
80
+ <li
81
+ v-for="(org, idx) in formattedOrganizations"
82
+ :key="org.username"
83
+ >
84
+ <a
85
+ class="is-flex is-align-items-center"
86
+ @click="onOrganizationClick(org.username)"
87
+ >
88
+ <div class="width-30 height-30 image">
89
+ <img
90
+ :src="org.avatar_url"
91
+ class="ac-user-profile is-rounded"
92
+ alt="icon"
93
+ />
94
+ </div>
95
+ <div
96
+ class="
97
+ is-flex
98
+ is-align-items-center
99
+ is-justify-content-space-between
100
+ is-fullwidth
101
+ ml-10
102
+ "
103
+ >
104
+ <div class="org-info">
105
+ <strong
106
+ :title="org.username"
107
+ class="line-break-anywhere is-ellipsis-1"
108
+ >{{ org.username }}</strong
109
+ >
110
+ <p>
111
+ {{
112
+ org.isPersonalAccount
113
+ ? "Personal Account"
114
+ : "Organization"
115
+ }}
116
+ </p>
117
+ </div>
118
+ <span
119
+ v-if="idx === 0"
120
+ class="
121
+ material-icons-outlined
122
+ font-size-18
123
+ ml-10
124
+ is-pulled-right
125
+ "
126
+ >
127
+ check
128
+ </span>
129
+ </div>
130
+ </a>
131
+ </li>
132
+ </transition-group>
133
+ </li>
134
+ <li key="dashboard">
135
+ <nuxt-link
136
+ v-if="isPlatformDomain"
137
+ to="/dashboard"
138
+ data-testid="user-dashboard-link"
139
+ >
140
+ Dashboard
141
+ </nuxt-link>
142
+ <a
143
+ v-else
144
+ :href="`${serverDomain}/dashboard`"
145
+ data-testid="user-dashboard-link"
146
+ >
147
+ Dashboard
148
+ </a>
149
+ </li>
150
+ <li key="signout" @click="$emit('on-logout')">
151
+ <a
152
+ data-testid="user-logout-link"
153
+ :href="`${accountsDomain}/user/logout`"
154
+ >
155
+ Sign out
156
+ </a>
157
+ </li>
158
+ <li key="theme" v-if="showThemeMode">
159
+ <theme-mode @set:theme="setTheme" />
160
+ </li>
161
+ </transition-group>
162
+ </div>
163
+ </navbar-item-content>
164
+ </navbar-item>
165
+ </template>
166
+
167
+ <script>
168
+ import { defineComponent, defineAsyncComponent } from "vue";
169
+
170
+ export default defineComponent({
171
+ props: {
172
+ // active user info
173
+ user: {
174
+ type: Object,
175
+ default: () => ({}),
176
+ },
177
+ serverDomain: {
178
+ type: String,
179
+ default: "",
180
+ },
181
+ accountsDomain: {
182
+ type: String,
183
+ default: "",
184
+ },
185
+ showAccountSwitcher: {
186
+ type: Boolean,
187
+ default: false,
188
+ },
189
+ // all available organization list including personal account
190
+ organizations: {
191
+ type: Array,
192
+ default: () => [],
193
+ },
194
+ showThemeMode: {
195
+ type: Boolean,
196
+ default: false,
197
+ },
198
+ isPlatformDomain: {
199
+ type: Boolean,
200
+ default: false,
201
+ },
202
+ },
203
+ emits: ["set:theme", "on-logout"],
204
+
205
+ components: {
206
+ NavbarItem: defineAsyncComponent(() =>
207
+ import("../../v2/navbar/NavbarItem.vue").then((module) => module.default)
208
+ ),
209
+ NavbarItemContent: defineAsyncComponent(() =>
210
+ import("../../v2/navbar/NavbarItemContent.vue").then(
211
+ (module) => module.default
212
+ )
213
+ ),
214
+ ThemeMode: defineAsyncComponent(() =>
215
+ import("../../v3/navbar/ThemeMode.vue").then((module) => module.default)
216
+ ),
217
+ },
218
+
219
+ computed: {
220
+ formattedOrganizations() {
221
+ let activeUser;
222
+ const filteredList = this.organizations.filter((item) => {
223
+ if (item.username === this.user.username) {
224
+ activeUser = item;
225
+ } else {
226
+ return true;
227
+ }
228
+ return false;
229
+ });
230
+
231
+ filteredList.unshift(activeUser);
232
+
233
+ return filteredList || [];
234
+ },
235
+ },
236
+
237
+ data() {
238
+ return {
239
+ dropDownStatus: "close",
240
+ dropDownSectionHeight: null,
241
+ };
242
+ },
243
+
244
+ methods: {
245
+ toggleList() {
246
+ this.dropDownStatus = this.dropDownStatus === "open" ? "close" : "open";
247
+ this.$nextTick(() => {
248
+ this.$refs["dropdownItems"].$el.scrollTo(0, 0);
249
+ });
250
+ },
251
+ onOrganizationClick(orgName) {
252
+ this.$refs["dropdownItems"].$el.scrollTo(0, 0);
253
+ this.$emit("activeorg$set", orgName);
254
+ },
255
+ onMouseLeave() {
256
+ this.dropDownStatus = "close";
257
+ },
258
+ setTheme(val) {
259
+ this.$emit("set:theme", val);
260
+ },
261
+ },
262
+
263
+ watch: {
264
+ dropDownStatus: {
265
+ immediate: true,
266
+ handler(n) {
267
+ if (n === "open") {
268
+ this.$nextTick(() => {
269
+ const dropDownUl = this.$refs["dropdownItems"];
270
+ if (dropDownUl)
271
+ this.dropDownSectionHeight = `${dropDownUl.scrollHeight}px`;
272
+ });
273
+ } else {
274
+ this.dropDownSectionHeight = null;
275
+ }
276
+ },
277
+ },
278
+ },
279
+ });
280
+ </script>
281
+ <style lang="scss" scoped>
282
+ .ac-vscrollbar {
283
+ overflow: auto !important;
284
+ }
285
+ .line-break-anywhere {
286
+ line-break: anywhere;
287
+ }
288
+ </style>
@@ -0,0 +1,98 @@
1
+ <template>
2
+ <div
3
+ @mouseenter="notificationPanelOpen = true"
4
+ @mouseleave="notificationPanelOpen = false"
5
+ >
6
+ <button class="button ac-nav-button">
7
+ <span v-if="unreadCount">{{ unreadCount }}</span>
8
+ <i
9
+ class="fa fa-bell"
10
+ :class="{ 'ac-shake': unreadCount }"
11
+ aria-hidden="true"
12
+ ></i>
13
+ </button>
14
+ <div class="ac-menu-content is-notification">
15
+ <div class="notification-header">
16
+ <div class="left-content">
17
+ <p>
18
+ Notifications <span>({{ notifications.length }})</span>
19
+ </p>
20
+ </div>
21
+ <div class="right-content"></div>
22
+ </div>
23
+ <div :key="notificationPanelOpen ? 1 : 0" class="notification-body">
24
+ <transition-group v-if="notifications.length" name="slide-right">
25
+ <notification-item
26
+ v-for="notification in notifications"
27
+ :key="`${notification.id}${unreadCount}`"
28
+ :notification="notification"
29
+ />
30
+ </transition-group>
31
+ <span v-else class="single-notification-item"
32
+ >No new notifications</span
33
+ >
34
+ </div>
35
+ </div>
36
+ </div>
37
+ </template>
38
+
39
+ <script setup lang="ts">
40
+ import { NatsConnection, StringCodec, Subscription } from "nats.ws";
41
+ import {
42
+ computed,
43
+ defineAsyncComponent,
44
+ getCurrentInstance,
45
+ ref,
46
+ Ref,
47
+ watch,
48
+ } from "vue";
49
+ import { TaskLog } from "../../../typings/long-running-tasks";
50
+ import { Notification } from "../../../typings/notification";
51
+
52
+ const NotificationItem = defineAsyncComponent(
53
+ () => import("./NotificationItem.vue")
54
+ );
55
+
56
+ const notifications: Ref<Notification[]> = ref([]);
57
+ const notificationsRead = ref(0);
58
+ const unreadCount = computed(
59
+ () => notifications.value.length - notificationsRead.value
60
+ );
61
+
62
+ const notificationPanelOpen = ref(false);
63
+ watch(notificationPanelOpen, (n) => {
64
+ if (n) notificationsRead.value = notifications.value.length;
65
+ });
66
+
67
+ function addNewNotification(notification: Notification) {
68
+ notifications.value.unshift(notification);
69
+ if (notificationPanelOpen.value) {
70
+ notificationsRead.value = notifications.value.length;
71
+ }
72
+ }
73
+
74
+ const app = getCurrentInstance();
75
+ const $nats: NatsConnection = app?.appContext.config.globalProperties.$nc;
76
+ let subscription: Subscription;
77
+
78
+ async function subscribeToNotifcations() {
79
+ subscription = $nats?.subscribe("notifications");
80
+ console.log("Started listening to Notifications");
81
+
82
+ if (subscription) {
83
+ // listen to channel events
84
+ for await (const msg of subscription) {
85
+ console.log("notifications ===>");
86
+ console.log({ data: StringCodec().decode(msg.data) });
87
+ const log: TaskLog = JSON.parse(StringCodec().decode(msg.data));
88
+ console.log({ log });
89
+ const currentTime = new Date().getTime();
90
+ addNewNotification({ ...log, id: currentTime, time: currentTime });
91
+ msg.respond();
92
+ }
93
+ console.log("Stopped listening to Notifications");
94
+ console.log("Closed Channel Notifications");
95
+ }
96
+ }
97
+ subscribeToNotifcations();
98
+ </script>
@@ -0,0 +1,52 @@
1
+ <template>
2
+ <a class="single-notification-item is-complete">
3
+ <p>
4
+ {{ notification.msg }}
5
+ </p>
6
+ <div class="notification-status">
7
+ <p
8
+ :class="{
9
+ 'is-success': notification.status === 'Success',
10
+ 'has-text-danger': notification.status === 'Failed',
11
+ 'is-info':
12
+ notification.status === 'Started' ||
13
+ notification.status === 'Running',
14
+ 'is-warning': notification.status === 'Pending',
15
+ }"
16
+ >
17
+ <i
18
+ class="fa mr-5"
19
+ :class="{
20
+ 'fa-check': notification.status === 'Success',
21
+ 'fa-exclamation-triangle': notification.status === 'Failed',
22
+ 'fa-info-circle':
23
+ notification.status === 'Started' ||
24
+ notification.status === 'Pending' ||
25
+ notification.status === 'Running',
26
+ }"
27
+ />
28
+ {{ notification.status }}
29
+ </p>
30
+ <p>{{ notificationTime }} ago</p>
31
+ </div>
32
+ </a>
33
+ </template>
34
+
35
+ <script setup lang="ts">
36
+ import { computed, toRefs } from 'vue'
37
+ import { Notification } from '../../../typings/notification'
38
+ import TimeConvert from '../../../plugins/time-convert'
39
+
40
+ const props = withDefaults(defineProps<{ notification: Notification }>(), {
41
+ notification: () => ({
42
+ id: 0,
43
+ status: 'Pending',
44
+ time: 0,
45
+ }),
46
+ })
47
+
48
+ const { notification } = toRefs(props)
49
+ const notificationTime = computed(() =>
50
+ TimeConvert.getDayDifferences({ past: notification.value.time })
51
+ )
52
+ </script>