Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
70 changes: 70 additions & 0 deletions shell/components/EmptyProductPage.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
<script>
export default {
name: 'EmptyProductPage',

layout: 'plain',

Check warning on line 5 in shell/components/EmptyProductPage.vue

View workflow job for this annotation

GitHub Actions / lint

Trailing spaces not allowed

data() {
const err = this.$route.meta?.pageError;

let msg;

switch (err) {
case 'no-nav':

Check warning on line 13 in shell/components/EmptyProductPage.vue

View workflow job for this annotation

GitHub Actions / lint

Expected indentation of 4 spaces but found 6
msg = [

Check warning on line 14 in shell/components/EmptyProductPage.vue

View workflow job for this annotation

GitHub Actions / lint

Expected indentation of 6 spaces but found 8
'When a component is not provided for a product, the layout with side navigation is used',

Check warning on line 15 in shell/components/EmptyProductPage.vue

View workflow job for this annotation

GitHub Actions / lint

Expected indentation of 8 spaces but found 10
'No child items were specified, so this "Default" empty view has been added',

Check warning on line 16 in shell/components/EmptyProductPage.vue

View workflow job for this annotation

GitHub Actions / lint

Expected indentation of 8 spaces but found 10
'Please add child items to this product'

Check warning on line 17 in shell/components/EmptyProductPage.vue

View workflow job for this annotation

GitHub Actions / lint

Expected indentation of 8 spaces but found 10
];

Check warning on line 18 in shell/components/EmptyProductPage.vue

View workflow job for this annotation

GitHub Actions / lint

Expected indentation of 6 spaces but found 8
break;

Check warning on line 19 in shell/components/EmptyProductPage.vue

View workflow job for this annotation

GitHub Actions / lint

Expected indentation of 6 spaces but found 8
default:

Check warning on line 20 in shell/components/EmptyProductPage.vue

View workflow job for this annotation

GitHub Actions / lint

Expected indentation of 4 spaces but found 6
msg = ['No component defined for this product'];

Check warning on line 21 in shell/components/EmptyProductPage.vue

View workflow job for this annotation

GitHub Actions / lint

Expected indentation of 6 spaces but found 8
}

return {
img: require('~shell/assets/images/generic-plugin.svg'),
msg,
};
},
};
</script>

<template>
<div class="empty-product-page">
<img :src="img" alt="Extension Product Error" />

Check failure on line 34 in shell/components/EmptyProductPage.vue

View workflow job for this annotation

GitHub Actions / lint

'alt' should be on a new line

Check failure on line 34 in shell/components/EmptyProductPage.vue

View workflow job for this annotation

GitHub Actions / lint

Disallow self-closing on HTML void elements (<img/>)
<div class="err-messages">
<p v-for="(m, index) in msg" :key="index">{{ m }}</p>

Check failure on line 36 in shell/components/EmptyProductPage.vue

View workflow job for this annotation

GitHub Actions / lint

':key' should be on a new line
</div>
</div>
</template>

<style lang="scss" scoped>
.empty-product-page {
align-items: center;
display: flex;
justify-content: center;
opacity: 0.75;

> img {
width: 128px;
margin-bottom: 20px;
}

.err-messages {
display: flex;
align-items: center;
text-align: center;
flex-direction: column;

> * {
margin-bottom: 8px;
font-size: 16px;

&:last-child {
font-weight: bold;
color: var(--error);
}
}
}
}
</style>
5 changes: 4 additions & 1 deletion shell/components/nav/Group.vue
Original file line number Diff line number Diff line change
Expand Up @@ -196,7 +196,10 @@ export default {
const matchesNavLevel = navLevels.filter((param) => !this.$route.params[param] || this.$route.params[param] !== item.route.params[param]).length === 0;
const withoutHash = this.$route.hash ? this.$route.fullPath.slice(0, this.$route.fullPath.indexOf(this.$route.hash)) : this.$route.fullPath;
const withoutQuery = withoutHash.split('?')[0];
const itemFullPath = this.$router.resolve(item.route).fullPath;

let itemFullPath;

try { itemFullPath = this.$router.resolve(item.route).fullPath; } catch (e) { console.error(e); }

if (matchesNavLevel || itemFullPath === withoutQuery) {
return true;
Expand Down
29 changes: 28 additions & 1 deletion shell/components/nav/Header.vue
Original file line number Diff line number Diff line change
Expand Up @@ -239,6 +239,26 @@
isHarvester() {
return this.$store.getters['currentProduct'].inStore === HARVESTER;
},

productLabel() {
// Old-style product will just show the branding logo
// version 2 products will show the product label if set
if (!this.currentProduct?.version === 2) {
return false;
}

if (this.currentProduct?.label) {
return this.currentProduct.label;
}

if (this.currentProduct?.labelKey) {
return this.$store.getters['i18n/t'](this.currentProduct.labelKey);
}

const name = this.currentProduct.name;

return this.$store.getters['i18n/withFallback'](`product."${ name }"`, null, ucFirst(name));;

Check failure on line 260 in shell/components/nav/Header.vue

View workflow job for this annotation

GitHub Actions / lint

Unnecessary semicolon
}
},

watch: {
Expand Down Expand Up @@ -518,7 +538,7 @@
:alt="t('branding.logos.label')"
>
<div class="product-name">
{{ prod }}
{{ productLabel || prod }}
</div>
</div>
</div>
Expand All @@ -534,6 +554,13 @@
{{ t(isSingleProduct.productNameKey) }}
</div>

<div
v-if="productLabel"
class="product-name"
>
{{ productLabel }}
</div>

<div
v-else
class="side-menu-logo"
Expand Down
17 changes: 16 additions & 1 deletion shell/components/nav/TopLevelMenu.vue
Original file line number Diff line number Diff line change
Expand Up @@ -182,8 +182,23 @@ export default {
to.params.product = p.name;
}

let label;

// Allow product to specify its label if it is a version 2 product, rather than use convention and a fallback
if (p.version === 2) {
if (p.labelKey) {
label = this.$store.getters['i18n/t'](p.labelKey);
} else if (p.label) {
label = p.label;
}
}

if (!label) {
label = this.$store.getters['i18n/withFallback'](`product.${ p.name }`, null, ucFirst(p.name));
}

return {
label: this.$store.getters['i18n/withFallback'](`product."${ p.name }"`, null, ucFirst(p.name)),
label,
icon: `icon-${ p.icon || 'copy' }`,
svg: p.svg,
value: p.name,
Expand Down
25 changes: 25 additions & 0 deletions shell/core/extension-manager-impl.js
Original file line number Diff line number Diff line change
Expand Up @@ -407,6 +407,11 @@ const createExtensionManager = (context) => {
}
},

// Internal use only
_add(id, plugin) {
plugins[id] = plugin;
},

// For debugging
getAll() {
return dynamic;
Expand Down Expand Up @@ -510,6 +515,26 @@ const createExtensionManager = (context) => {
}
});
}

// Load products and product extensions using the simpler API
if (plugin.productConfigs?.length) {
// Add new products first
plugin.productConfigs.filter(p => p.newProduct).forEach((productConfig) => {
productConfig.apply(plugin, store, app.router, pluginRoutes);
});

// Extend existing products after new products are added
plugin.productConfigs.filter(p => !p.newProduct).forEach((productConfig) => {
productConfig.apply(plugin, store, app.router, pluginRoutes);
});
}

// Apply all type configurations
if (plugin.resourceTypeConfigs?.length) {
plugin.resourceTypeConfigs.forEach((resourceTypeConfig) => {
resourceTypeConfig.apply(plugin, store, app.router, pluginRoutes);
});
}
});
},
};
Expand Down
Loading
Loading