Compare commits
13
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
42b9b06824 | ||
|
|
1fae9c59c6 | ||
|
|
6197bba54d | ||
|
|
13b28b5db9 | ||
|
|
46340d7146 | ||
|
|
b32685a27f | ||
|
|
5ef8b84137 | ||
|
|
1772450945 | ||
|
|
692aba278b | ||
|
|
4027c026e3 | ||
|
|
27c778b526 | ||
|
|
5d91bb4ffc | ||
|
|
72a17409f3 |
@@ -0,0 +1,68 @@
|
|||||||
|
import { describe, it, expect, vi } from 'vitest';
|
||||||
|
import { usePortal } from '../usePortal';
|
||||||
|
import { useAccount } from 'dashboard/composables/useAccount';
|
||||||
|
import { useRoute } from 'dashboard/composables/route';
|
||||||
|
import { frontendURL } from 'dashboard/helper/URLHelper';
|
||||||
|
import allLocales from 'shared/constants/locales.js';
|
||||||
|
|
||||||
|
vi.mock('dashboard/composables/useAccount');
|
||||||
|
vi.mock('dashboard/composables/route');
|
||||||
|
vi.mock('dashboard/helper/URLHelper');
|
||||||
|
|
||||||
|
describe('usePortal', () => {
|
||||||
|
beforeEach(() => {
|
||||||
|
vi.mocked(useAccount).mockReturnValue({ accountId: { value: 123 } });
|
||||||
|
});
|
||||||
|
|
||||||
|
it('returns the correct properties', () => {
|
||||||
|
vi.mocked(useRoute).mockReturnValue({
|
||||||
|
params: { portalSlug: 'test-portal', locale: 'en' },
|
||||||
|
});
|
||||||
|
|
||||||
|
const portal = usePortal();
|
||||||
|
|
||||||
|
expect(portal).toHaveProperty('accountId');
|
||||||
|
expect(portal).toHaveProperty('portalSlug');
|
||||||
|
expect(portal).toHaveProperty('locale');
|
||||||
|
expect(portal).toHaveProperty('articleUrl');
|
||||||
|
expect(portal).toHaveProperty('localeName');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('computes portalSlug and locale correctly', () => {
|
||||||
|
vi.mocked(useRoute).mockReturnValue({
|
||||||
|
params: { portalSlug: 'test-portal', locale: 'fr' },
|
||||||
|
});
|
||||||
|
|
||||||
|
const { portalSlug, locale } = usePortal();
|
||||||
|
|
||||||
|
expect(portalSlug.value).toBe('test-portal');
|
||||||
|
expect(locale.value).toBe('fr');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('generates correct article URL', () => {
|
||||||
|
vi.mocked(useAccount).mockReturnValue({ accountId: { value: 456 } });
|
||||||
|
vi.mocked(useRoute).mockReturnValue({
|
||||||
|
params: { portalSlug: 'help-center', locale: 'es' },
|
||||||
|
});
|
||||||
|
vi.mocked(frontendURL).mockReturnValue('https://example.com/article');
|
||||||
|
|
||||||
|
const { articleUrl } = usePortal();
|
||||||
|
const url = articleUrl(789);
|
||||||
|
|
||||||
|
expect(frontendURL).toHaveBeenCalledWith(
|
||||||
|
'accounts/456/portals/help-center/es/articles/789'
|
||||||
|
);
|
||||||
|
expect(url).toBe('https://example.com/article');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('returns correct locale name', () => {
|
||||||
|
vi.mocked(useRoute).mockReturnValue({
|
||||||
|
params: { portalSlug: 'test-portal', locale: 'ja' },
|
||||||
|
});
|
||||||
|
|
||||||
|
const { localeName } = usePortal();
|
||||||
|
const name = localeName('ja');
|
||||||
|
|
||||||
|
expect(name).toBe(allLocales.ja);
|
||||||
|
});
|
||||||
|
});
|
||||||
@@ -0,0 +1,53 @@
|
|||||||
|
import { useAccount } from 'dashboard/composables/useAccount';
|
||||||
|
import { frontendURL } from 'dashboard/helper/URLHelper';
|
||||||
|
import allLocales from 'shared/constants/locales.js';
|
||||||
|
import { useRoute } from 'dashboard/composables/route';
|
||||||
|
import { computed } from 'vue';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @typedef {Object} PortalComposable
|
||||||
|
* @property {import('vue').ComputedRef<number>} accountId - The current account ID.
|
||||||
|
* @property {import('vue').ComputedRef<string>} portalSlug - The slug of the current portal.
|
||||||
|
* @property {import('vue').ComputedRef<string>} locale - The current locale code.
|
||||||
|
* @property {function(number): string} articleUrl - A function to generate the URL for an article.
|
||||||
|
* @property {function(string): string} localeName - A function to get the localized name of a locale.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A composable for managing portal-related data and utilities.
|
||||||
|
* @returns {PortalComposable} An object containing portal-related properties and functions.
|
||||||
|
*/
|
||||||
|
export const usePortal = () => {
|
||||||
|
const { accountId } = useAccount();
|
||||||
|
const route = useRoute();
|
||||||
|
const portalSlug = computed(() => route.params.portalSlug);
|
||||||
|
const locale = computed(() => route.params.locale);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Generates the URL for an article.
|
||||||
|
* @param {number} id - The ID of the article.
|
||||||
|
* @returns {string} The full URL for the article.
|
||||||
|
*/
|
||||||
|
const articleUrl = id => {
|
||||||
|
return frontendURL(
|
||||||
|
`accounts/${accountId.value}/portals/${portalSlug.value}/${locale.value}/articles/${id}`
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the localized name of a locale.
|
||||||
|
* @param {string} code - The locale code.
|
||||||
|
* @returns {string} The localized name of the locale.
|
||||||
|
*/
|
||||||
|
const localeName = code => {
|
||||||
|
return allLocales[code];
|
||||||
|
};
|
||||||
|
|
||||||
|
return {
|
||||||
|
accountId,
|
||||||
|
portalSlug,
|
||||||
|
locale,
|
||||||
|
articleUrl,
|
||||||
|
localeName,
|
||||||
|
};
|
||||||
|
};
|
||||||
@@ -1,14 +1,14 @@
|
|||||||
<script>
|
<script>
|
||||||
import { dynamicTime } from 'shared/helpers/timeHelper';
|
import { dynamicTime } from 'shared/helpers/timeHelper';
|
||||||
import portalMixin from '../mixins/portalMixin';
|
import { usePortal } from 'dashboard/composables/usePortal';
|
||||||
import { frontendURL } from 'dashboard/helper/URLHelper';
|
import { frontendURL } from 'dashboard/helper/URLHelper';
|
||||||
import Thumbnail from 'dashboard/components/widgets/Thumbnail.vue';
|
import Thumbnail from 'dashboard/components/widgets/Thumbnail.vue';
|
||||||
|
import { useAccount } from 'dashboard/composables/useAccount';
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
components: {
|
components: {
|
||||||
Thumbnail,
|
Thumbnail,
|
||||||
},
|
},
|
||||||
mixins: [portalMixin],
|
|
||||||
props: {
|
props: {
|
||||||
showDragIcon: {
|
showDragIcon: {
|
||||||
type: Boolean,
|
type: Boolean,
|
||||||
@@ -44,7 +44,11 @@ export default {
|
|||||||
default: 0,
|
default: 0,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
setup() {
|
||||||
|
const { accountId } = useAccount();
|
||||||
|
const { articleUrl, portalSlug, locale, localeName } = usePortal();
|
||||||
|
return { accountId, portalSlug, locale, localeName, articleUrl };
|
||||||
|
},
|
||||||
computed: {
|
computed: {
|
||||||
lastUpdatedAt() {
|
lastUpdatedAt() {
|
||||||
return dynamicTime(this.updatedAt);
|
return dynamicTime(this.updatedAt);
|
||||||
|
|||||||
+5
-2
@@ -7,7 +7,7 @@ import SearchResults from './SearchResults.vue';
|
|||||||
import ArticleView from './ArticleView.vue';
|
import ArticleView from './ArticleView.vue';
|
||||||
import ArticlesAPI from 'dashboard/api/helpCenter/articles';
|
import ArticlesAPI from 'dashboard/api/helpCenter/articles';
|
||||||
import { buildPortalArticleURL } from 'dashboard/helper/portalHelper';
|
import { buildPortalArticleURL } from 'dashboard/helper/portalHelper';
|
||||||
import portalMixin from '../../mixins/portalMixin';
|
import { usePortal } from 'dashboard/composables/usePortal';
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
name: 'ArticleSearchPopover',
|
name: 'ArticleSearchPopover',
|
||||||
@@ -16,13 +16,16 @@ export default {
|
|||||||
SearchResults,
|
SearchResults,
|
||||||
ArticleView,
|
ArticleView,
|
||||||
},
|
},
|
||||||
mixins: [portalMixin],
|
|
||||||
props: {
|
props: {
|
||||||
selectedPortalSlug: {
|
selectedPortalSlug: {
|
||||||
type: String,
|
type: String,
|
||||||
required: true,
|
required: true,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
setup() {
|
||||||
|
const { localeName } = usePortal();
|
||||||
|
return { localeName };
|
||||||
|
},
|
||||||
data() {
|
data() {
|
||||||
return {
|
return {
|
||||||
searchQuery: '',
|
searchQuery: '',
|
||||||
|
|||||||
+7
-4
@@ -10,7 +10,8 @@ import WootKeyShortcutModal from 'dashboard/components/widgets/modal/WootKeyShor
|
|||||||
import AccountSelector from 'dashboard/components/layout/sidebarComponents/AccountSelector.vue';
|
import AccountSelector from 'dashboard/components/layout/sidebarComponents/AccountSelector.vue';
|
||||||
import NotificationPanel from 'dashboard/routes/dashboard/notifications/components/NotificationPanel.vue';
|
import NotificationPanel from 'dashboard/routes/dashboard/notifications/components/NotificationPanel.vue';
|
||||||
import { useUISettings } from 'dashboard/composables/useUISettings';
|
import { useUISettings } from 'dashboard/composables/useUISettings';
|
||||||
import portalMixin from '../mixins/portalMixin';
|
import { useAccount } from 'dashboard/composables/useAccount';
|
||||||
|
import { usePortal } from 'dashboard/composables/usePortal';
|
||||||
import AddCategory from '../pages/categories/AddCategory.vue';
|
import AddCategory from '../pages/categories/AddCategory.vue';
|
||||||
import { FEATURE_FLAGS } from 'dashboard/featureFlags';
|
import { FEATURE_FLAGS } from 'dashboard/featureFlags';
|
||||||
const CommandBar = () =>
|
const CommandBar = () =>
|
||||||
@@ -28,13 +29,16 @@ export default {
|
|||||||
UpgradePage,
|
UpgradePage,
|
||||||
WootKeyShortcutModal,
|
WootKeyShortcutModal,
|
||||||
},
|
},
|
||||||
mixins: [portalMixin],
|
|
||||||
setup() {
|
setup() {
|
||||||
const { uiSettings, updateUISettings } = useUISettings();
|
const { uiSettings, updateUISettings } = useUISettings();
|
||||||
|
const { accountId } = useAccount();
|
||||||
|
const { locale, localeName } = usePortal();
|
||||||
return {
|
return {
|
||||||
uiSettings,
|
uiSettings,
|
||||||
updateUISettings,
|
updateUISettings,
|
||||||
|
accountId,
|
||||||
|
locale,
|
||||||
|
localeName,
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
data() {
|
data() {
|
||||||
@@ -51,7 +55,6 @@ export default {
|
|||||||
|
|
||||||
computed: {
|
computed: {
|
||||||
...mapGetters({
|
...mapGetters({
|
||||||
accountId: 'getCurrentAccountId',
|
|
||||||
portals: 'portals/allPortals',
|
portals: 'portals/allPortals',
|
||||||
categories: 'categories/allCategories',
|
categories: 'categories/allCategories',
|
||||||
meta: 'portals/getMeta',
|
meta: 'portals/getMeta',
|
||||||
|
|||||||
+5
-3
@@ -1,7 +1,6 @@
|
|||||||
<script>
|
<script>
|
||||||
import portalMixin from '../mixins/portalMixin';
|
import { usePortal } from 'dashboard/composables/usePortal';
|
||||||
export default {
|
export default {
|
||||||
mixins: [portalMixin],
|
|
||||||
props: {
|
props: {
|
||||||
locales: {
|
locales: {
|
||||||
type: Array,
|
type: Array,
|
||||||
@@ -12,7 +11,10 @@ export default {
|
|||||||
default: '',
|
default: '',
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
setup() {
|
||||||
|
const { localeName } = usePortal();
|
||||||
|
return { localeName };
|
||||||
|
},
|
||||||
methods: {
|
methods: {
|
||||||
changeDefaultLocale(localeCode) {
|
changeDefaultLocale(localeCode) {
|
||||||
this.$emit('changeDefaultLocale', { localeCode });
|
this.$emit('changeDefaultLocale', { localeCode });
|
||||||
|
|||||||
@@ -1,12 +1,11 @@
|
|||||||
<script>
|
<script>
|
||||||
import Thumbnail from 'dashboard/components/widgets/Thumbnail.vue';
|
import Thumbnail from 'dashboard/components/widgets/Thumbnail.vue';
|
||||||
import portalMixin from '../mixins/portalMixin';
|
import { usePortal } from 'dashboard/composables/usePortal';
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
components: {
|
components: {
|
||||||
Thumbnail,
|
Thumbnail,
|
||||||
},
|
},
|
||||||
mixins: [portalMixin],
|
|
||||||
props: {
|
props: {
|
||||||
portal: {
|
portal: {
|
||||||
type: Object,
|
type: Object,
|
||||||
@@ -25,6 +24,10 @@ export default {
|
|||||||
default: '',
|
default: '',
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
setup() {
|
||||||
|
const { localeName } = usePortal();
|
||||||
|
return { localeName };
|
||||||
|
},
|
||||||
data() {
|
data() {
|
||||||
return {
|
return {
|
||||||
selectedLocale: null,
|
selectedLocale: null,
|
||||||
|
|||||||
@@ -1,24 +0,0 @@
|
|||||||
import { mapGetters } from 'vuex';
|
|
||||||
import { frontendURL } from 'dashboard/helper/URLHelper';
|
|
||||||
import allLocales from 'shared/constants/locales.js';
|
|
||||||
export default {
|
|
||||||
computed: {
|
|
||||||
...mapGetters({ accountId: 'getCurrentAccountId' }),
|
|
||||||
portalSlug() {
|
|
||||||
return this.$route.params.portalSlug;
|
|
||||||
},
|
|
||||||
locale() {
|
|
||||||
return this.$route.params.locale;
|
|
||||||
},
|
|
||||||
},
|
|
||||||
methods: {
|
|
||||||
articleUrl(id) {
|
|
||||||
return frontendURL(
|
|
||||||
`accounts/${this.accountId}/portals/${this.portalSlug}/${this.locale}/articles/${id}`
|
|
||||||
);
|
|
||||||
},
|
|
||||||
localeName(code) {
|
|
||||||
return allLocales[code];
|
|
||||||
},
|
|
||||||
},
|
|
||||||
};
|
|
||||||
@@ -1,76 +0,0 @@
|
|||||||
import { shallowMount, createLocalVue } from '@vue/test-utils';
|
|
||||||
import portalMixin from '../portalMixin';
|
|
||||||
import Vuex from 'vuex';
|
|
||||||
import VueRouter from 'vue-router';
|
|
||||||
const localVue = createLocalVue();
|
|
||||||
localVue.use(Vuex);
|
|
||||||
localVue.use(VueRouter);
|
|
||||||
import ListAllArticles from '../../pages/portals/ListAllPortals.vue';
|
|
||||||
|
|
||||||
const router = new VueRouter({
|
|
||||||
routes: [
|
|
||||||
{
|
|
||||||
path: ':portalSlug/:locale/articles',
|
|
||||||
name: 'list_all_locale_articles',
|
|
||||||
component: ListAllArticles,
|
|
||||||
},
|
|
||||||
],
|
|
||||||
});
|
|
||||||
|
|
||||||
describe('portalMixin', () => {
|
|
||||||
let getters;
|
|
||||||
let store;
|
|
||||||
let wrapper;
|
|
||||||
|
|
||||||
beforeEach(() => {
|
|
||||||
getters = {
|
|
||||||
getCurrentAccountId: () => 1,
|
|
||||||
};
|
|
||||||
const Component = {
|
|
||||||
render() {},
|
|
||||||
title: 'TestComponent',
|
|
||||||
mixins: [portalMixin],
|
|
||||||
router,
|
|
||||||
};
|
|
||||||
store = new Vuex.Store({ getters });
|
|
||||||
wrapper = shallowMount(Component, { store, localVue });
|
|
||||||
});
|
|
||||||
|
|
||||||
it('return account id', () => {
|
|
||||||
expect(wrapper.vm.accountId).toBe(1);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('returns article url', () => {
|
|
||||||
router.push({
|
|
||||||
name: 'list_all_locale_articles',
|
|
||||||
params: { portalSlug: 'fur-rent', locale: 'en' },
|
|
||||||
});
|
|
||||||
expect(wrapper.vm.articleUrl(1)).toBe(
|
|
||||||
'/app/accounts/1/portals/fur-rent/en/articles/1'
|
|
||||||
);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('returns portal locale', () => {
|
|
||||||
router.push({
|
|
||||||
name: 'list_all_locale_articles',
|
|
||||||
params: { portalSlug: 'fur-rent', locale: 'es' },
|
|
||||||
});
|
|
||||||
expect(wrapper.vm.portalSlug).toBe('fur-rent');
|
|
||||||
});
|
|
||||||
|
|
||||||
it('returns portal slug', () => {
|
|
||||||
router.push({
|
|
||||||
name: 'list_all_locale_articles',
|
|
||||||
params: { portalSlug: 'campaign', locale: 'es' },
|
|
||||||
});
|
|
||||||
expect(wrapper.vm.portalSlug).toBe('campaign');
|
|
||||||
});
|
|
||||||
|
|
||||||
it('returns locale name', () => {
|
|
||||||
router.push({
|
|
||||||
name: 'list_all_locale_articles',
|
|
||||||
params: { portalSlug: 'fur-rent', locale: 'es' },
|
|
||||||
});
|
|
||||||
expect(wrapper.vm.localeName('es')).toBe('Spanish');
|
|
||||||
});
|
|
||||||
});
|
|
||||||
@@ -5,7 +5,7 @@ import EditArticleHeader from '../../components/Header/EditArticleHeader.vue';
|
|||||||
import ArticleEditor from '../../components/ArticleEditor.vue';
|
import ArticleEditor from '../../components/ArticleEditor.vue';
|
||||||
import ArticleSettings from './ArticleSettings.vue';
|
import ArticleSettings from './ArticleSettings.vue';
|
||||||
import Spinner from 'shared/components/Spinner.vue';
|
import Spinner from 'shared/components/Spinner.vue';
|
||||||
import portalMixin from '../../mixins/portalMixin';
|
import { usePortal } from 'dashboard/composables/usePortal';
|
||||||
import wootConstants from 'dashboard/constants/globals';
|
import wootConstants from 'dashboard/constants/globals';
|
||||||
import { buildPortalArticleURL } from 'dashboard/helper/portalHelper';
|
import { buildPortalArticleURL } from 'dashboard/helper/portalHelper';
|
||||||
import { PORTALS_EVENTS } from '../../../../../helper/AnalyticsHelper/events';
|
import { PORTALS_EVENTS } from '../../../../../helper/AnalyticsHelper/events';
|
||||||
@@ -18,7 +18,10 @@ export default {
|
|||||||
Spinner,
|
Spinner,
|
||||||
ArticleSettings,
|
ArticleSettings,
|
||||||
},
|
},
|
||||||
mixins: [portalMixin],
|
setup() {
|
||||||
|
const { locale } = usePortal();
|
||||||
|
return { locale };
|
||||||
|
},
|
||||||
data() {
|
data() {
|
||||||
return {
|
return {
|
||||||
isUpdating: false,
|
isUpdating: false,
|
||||||
|
|||||||
@@ -3,7 +3,7 @@ import { mapGetters } from 'vuex';
|
|||||||
import { useAlert } from 'dashboard/composables';
|
import { useAlert } from 'dashboard/composables';
|
||||||
import EditArticleHeader from 'dashboard/routes/dashboard/helpcenter/components/Header/EditArticleHeader.vue';
|
import EditArticleHeader from 'dashboard/routes/dashboard/helpcenter/components/Header/EditArticleHeader.vue';
|
||||||
import ArticleEditor from '../../components/ArticleEditor.vue';
|
import ArticleEditor from '../../components/ArticleEditor.vue';
|
||||||
import portalMixin from '../../mixins/portalMixin';
|
import { usePortal } from 'dashboard/composables/usePortal';
|
||||||
import ArticleSettings from './ArticleSettings.vue';
|
import ArticleSettings from './ArticleSettings.vue';
|
||||||
import { PORTALS_EVENTS } from '../../../../../helper/AnalyticsHelper/events';
|
import { PORTALS_EVENTS } from '../../../../../helper/AnalyticsHelper/events';
|
||||||
export default {
|
export default {
|
||||||
@@ -12,7 +12,10 @@ export default {
|
|||||||
ArticleEditor,
|
ArticleEditor,
|
||||||
ArticleSettings,
|
ArticleSettings,
|
||||||
},
|
},
|
||||||
mixins: [portalMixin],
|
setup() {
|
||||||
|
const { locale } = usePortal();
|
||||||
|
return { locale };
|
||||||
|
},
|
||||||
data() {
|
data() {
|
||||||
return {
|
return {
|
||||||
articleTitle: '',
|
articleTitle: '',
|
||||||
|
|||||||
Reference in New Issue
Block a user