diff --git a/.eslintrc.yml b/.eslintrc.yml
index 1e6df6f5a77..fddaf4929fe 100644
--- a/.eslintrc.yml
+++ b/.eslintrc.yml
@@ -48,3 +48,4 @@ overrides:
- '**/spec/**/*'
rules:
"@gitlab/require-i18n-strings": off
+ "@gitlab/no-runtime-template-compiler": off
diff --git a/app/assets/javascripts/admin/cohorts/components/usage_ping_disabled.vue b/app/assets/javascripts/admin/users/components/usage_ping_disabled.vue
similarity index 100%
rename from app/assets/javascripts/admin/cohorts/components/usage_ping_disabled.vue
rename to app/assets/javascripts/admin/users/components/usage_ping_disabled.vue
diff --git a/app/assets/javascripts/admin/users/index.js b/app/assets/javascripts/admin/users/index.js
index f35b57c4e1a..00a84259c22 100644
--- a/app/assets/javascripts/admin/users/index.js
+++ b/app/assets/javascripts/admin/users/index.js
@@ -1,8 +1,9 @@
import Vue from 'vue';
import { convertObjectPropsToCamelCase } from '~/lib/utils/common_utils';
+import UsagePingDisabled from './components/usage_ping_disabled.vue';
import AdminUsersApp from './components/app.vue';
-export default function (el = document.querySelector('#js-admin-users-app')) {
+export const initAdminUsersApp = (el = document.querySelector('#js-admin-users-app')) => {
if (!el) {
return false;
}
@@ -19,4 +20,24 @@ export default function (el = document.querySelector('#js-admin-users-app')) {
},
}),
});
-}
+};
+
+export const initCohortsEmptyState = (el = document.querySelector('#js-cohorts-empty-state')) => {
+ if (!el) {
+ return false;
+ }
+
+ const { emptyStateSvgPath, enableUsagePingLink, docsLink } = el.dataset;
+
+ return new Vue({
+ el,
+ provide: {
+ svgPath: emptyStateSvgPath,
+ primaryButtonPath: enableUsagePingLink,
+ docsLink,
+ },
+ render(h) {
+ return h(UsagePingDisabled);
+ },
+ });
+};
diff --git a/app/assets/javascripts/admin/users/tabs.js b/app/assets/javascripts/admin/users/tabs.js
new file mode 100644
index 00000000000..9ada77396c7
--- /dev/null
+++ b/app/assets/javascripts/admin/users/tabs.js
@@ -0,0 +1,23 @@
+import { historyPushState } from '~/lib/utils/common_utils';
+import { mergeUrlParams } from '~/lib/utils/url_utility';
+
+const COHORTS_PANE = 'cohorts';
+
+const tabClickHandler = (e) => {
+ const { hash } = e.currentTarget;
+ const tab = hash === `#${COHORTS_PANE}` ? COHORTS_PANE : null;
+ const newUrl = mergeUrlParams({ tab }, window.location.href);
+ historyPushState(newUrl);
+};
+
+const initTabs = () => {
+ const tabLinks = document.querySelectorAll('.js-users-tab-item a');
+
+ if (tabLinks.length) {
+ tabLinks.forEach((tabLink) => {
+ tabLink.addEventListener('click', (e) => tabClickHandler(e));
+ });
+ }
+};
+
+export default initTabs;
diff --git a/app/assets/javascripts/boards/components/board_sidebar.js b/app/assets/javascripts/boards/components/board_sidebar.js
index bf3dc5c608f..32640f83b83 100644
--- a/app/assets/javascripts/boards/components/board_sidebar.js
+++ b/app/assets/javascripts/boards/components/board_sidebar.js
@@ -1,4 +1,7 @@
-/* eslint-disable no-new */
+// This is a true violation of @gitlab/no-runtime-template-compiler, as it
+// relies on app/views/shared/boards/components/_sidebar.html.haml for its
+// template.
+/* eslint-disable no-new, @gitlab/no-runtime-template-compiler */
import $ from 'jquery';
import Vue from 'vue';
diff --git a/app/assets/javascripts/boards/components/toggle_focus.vue b/app/assets/javascripts/boards/components/toggle_focus.vue
new file mode 100644
index 00000000000..59ee47937c9
--- /dev/null
+++ b/app/assets/javascripts/boards/components/toggle_focus.vue
@@ -0,0 +1,52 @@
+
+
+
+