I have added a custom tab on my module’s details page, however, the tab is rendered but the content for the tab isn’t showing. There isn’t any error in the console log as well.
index.js
import './page/wt-shopfinder-list';
import './page/wt-shopfinder-detail';
import './view/wt-shopfinder-detail-base';
import './view/wt-shopfinder-detail-review';
const { Module } = Shopware;
Module.register('example-shopfinder', {
type: 'plugin',
name: 'ExampleShopFinder',
title: 'example-shopfinder.general.mainMenuItemGeneral',
description: 'example-shopfinder.general.descriptionTextModule',
version: '1.0.0',
targetVersion: '1.0.0',
color: '#9AA8B5',
icon: 'default-shopping-paper-bag',
entity:'wt_shop_finder',
routes: {
index: {
components: {
default: "wt-shopfinder-list"
},
path: 'index',
},
detail: {
component: 'wt-shopfinder-detail',
path: 'detail/:id',
redirect: {
name: 'example.shopfinder.detail.base',
},
children: {
base: {
component: 'wt-shopfinder-detail-base',
path: 'base',
meta: {
parentPath: 'example.shopfinder.index'
},
},
review: {
component: 'wt-shopfinder-detail-review',
path: 'review',
meta: {
parentPath: 'example.shopfinder.index'
},
},
},
meta: {
appSystem: {
view: 'detail',
},
},
props: {
default(route) {
return {
shopFinderId: route.params.id,
};
},
},
}
},
navigation: [{
id: 'wt-shopfinder',
label: 'example-shopfinder.menu.mainMenuItemGeneral',
color: '#ff3d58',
icon: 'default-shopping-paper-bag-product',
path: 'example.shopfinder.index',
parent: "sw-marketing",
position: 100,
}],
});
wt-shopfinder-detail/wt-shopfinder-detail-html.twig
<sw-tabs
class="wt_shopfinder-detail-page__tabs"
position-identifier="wt-shopfinder-detail"
>
{% block wt_shopfinder_detail_content_tabs_general %}
<sw-tabs-item
:route="generalRoute"
:title="$tc('sw-customer.detail.tabGeneral')"
:disabled="false"
>
{{ $tc('sw-promotion-v2.detail.tabs.tabGeneral') }}
</sw-tabs-item>
{% endblock %}
{% block wt_shopfinder_detail_content_tabs_general2 %}
<sw-tabs-item
:route="reviewRoute"
:title="$tc('sw-customer.detail.tabGeneral')"
:disabled="false"
>
Review
</sw-tabs-item>
{% endblock %}
</sw-tabs>
wt-shopfinder-detail/index.js
//Sharing only the url part for tab navigation
generalRoute() {
console.log("ID = "+this.shopFinderId);
return {
name: 'webbytroops.shopfinder.detail.base',
params: { id: this.shopFinderId },
};
},
wt-shopfinder-detail-base/index.js
import template from './wt-shopfinder-detail-base.html.twig';
const { Component } = Shopware;
const { Criteria } = Shopware.Data;
Component.register('wt-shopfinder-detail-base', {
template,
inject: ['repositoryFactory'],
metaInfo() {
return {
title: "Custom"
};
}
});
wt-shopfinder-detail-base/wt-shopfinder-detail-base.html.twig
<sw-card title="Custom">
Hello world!
</sw-card>
The correct pattern for the route would be {moduleName}.{routeName}.{childName} and in the module name dashes are replaced by dots. So the correct route in your case should be example.shopfinder.detail.base.
Also, unless you omitted it, you're missing the router-view tag after the sw-tabs component.
<sw-container>
<sw-tabs>
...
</sw-tabs>
<router-view />
</sw-container>
Related
I'm trying to add an wysiwyg field with the sw-text-edtior component for my cms-element as an config field, but it doesn't show up at all. If I try an sw-text-field instead of an sw-text-editor component it does show up. I can't seem to find it in the docs if I am missing something.
My code:
config/sw-cms-el-config-collapse.html.twig
{% block sw_cms_element_collapse_config %}
<sw-text-editor
v-model="blockContent"
:allow-inline-data-mapping="true"
sanitize-input
#element-update="onElementUpdate">
</sw-text-field>
{% endblock %}
config/index.js
import template from './sw-cms-el-config-collapse.html.twig';
Shopware.Component.register('sw-cms-el-config-collapse', {
template,
mixins: ['cms-element'],
computed: {
blockContent: {
get() {
return this.element.config.blockContent.value;
},
set(value) {
this.element.config.blockContent.value = value;
},
},
},
created() {
this.createdComponent();
},
methods: {
createdComponent() {
this.initElementConfig('s7-collapse');
},
onElementUpdate(element) {
this.emitChanges(element);
},
},
});
I have a Switch component that renders Routes based on a switch statement that takes useRouteMatch().path as the argument and returns a string.
In my unit test I want to dynamically mock this but it seems I can only set one jest.mock per file.
SectionComponent.tsx:
import React from 'react'
import { useRouteMatch } from 'react-router-dom'
import * as strings from '../../../strings'
import Header from '../../shared/header/Header'
const SectionComponent: React.FC = ({ children }) => {
const { path } = useRouteMatch()
const sectionTitle = () => {
switch (path) {
case '/header':
return strings.demo.header.title
case '/navbars':
return strings.demo.navbar.title
case '/button':
// ...etc
default:
return ''
}
}
return (
<div>
<Header
title={sectionTitle()}
titleColor={strings.theme.orange}
titleSize="S"
bgColor={strings.theme.white}
size="S"
/>
{children}
</div>
)
}
export default SectionComponent
SectionComponent.spec.tsx:
import React from 'react'
import { render } from '#testing-library/react'
import SectionComponent from './SectionComponent'
import * as strings from '../../../strings'
// list I want to dynamically generate useRouteMatch().path and expected result from
const options = [
{ name: 'header', to: '/header' },
{ name: 'navbars', to: '/navbars' },
{ name: 'button', to: '/button' },
{ name: 'typography', to: '/typography' },
{ name: 'form', to: '/form' },
{ name: 'navs', to: '/navs' },
{ name: 'indicators', to: '/indicators' },
{ name: 'list-group', to: '/list-group' },
{ name: 'cards', to: '/cards' },
]
// Can only do this once per file
jest.mock('react-router-dom', () => ({
...jest.requireActual('react-router-dom'), // use actual for all non-hook parts
useRouteMatch: () => ({ path: '/header' }), // return value can't access outside variables eg option.to ('/header')
}))
describe('SectionComponent', () => {
// ideally want to map thorugh options and test here:
it('should render with each Title', () => {
const { getByText } = render(<SectionComponent />)
expect(getByText(strings.demo.header.title)).toBeInTheDocument()
})
})
Does anyone have any suggestions? I'm happy to provide more info if necessary
Figured a workaround using jest.fn().mockReturnValueOnce() multiple times
import React from 'react'
import { render } from '#testing-library/react'
import SectionComponent from './SectionComponent'
const options = [
{ name: 'Headers' },
{ name: 'Navbars' },
{ name: 'Button' },
{ name: 'Typography' },
{ name: 'Forms' },
{ name: 'Navs' },
{ name: 'Indicators' },
{ name: 'List Group' },
{ name: 'Cards' },
]
jest.mock('react-router', () => ({
useRouteMatch: jest
.fn()
.mockReturnValueOnce({ path: '/header' })
.mockReturnValueOnce({ path: '/navbars' })
.mockReturnValueOnce({ path: '/button' })
.mockReturnValueOnce({ path: '/typography' })
.mockReturnValueOnce({ path: '/form' })
.mockReturnValueOnce({ path: '/navs' })
.mockReturnValueOnce({ path: '/indicators' })
.mockReturnValueOnce({ path: '/list-group' })
.mockReturnValueOnce({ path: '/cards' }),
}))
options.forEach(option => {
describe('SectionComponent', () => {
it('should render with each Title', () => {
const { getByText } = render(<SectionComponent />)
expect(getByText(option.name)).toBeInTheDocument()
})
})
})
Maybe not the most efficient but it works
This question has been asked several times in various forms over the years in the Tabulator GitHub repository. Here are a few instances:
https://github.com/olifolkerd/tabulator/issues/527, https://github.com/olifolkerd/tabulator/issues/1759
I'm looking for an example of how to achieve this using a dropdown menu of some form --- ideally as described in #1759 (dropdown with checkboxes) but another solution that would work for us is a "select" editor that adds/removes CSVs in the header filter when a value is selected/deselected (extending on the example provided in #527).
Hopefully someone with experience working with custom header filters / editors in tabulator can provide an example of a multi-select header filter dropdown, but if not, then I will post a JSFiddle link myself once I've got something that works.
Checkout: https://github.com/olifolkerd/tabulator/issues/527#issuecomment-850900451
Simple Answer by AkshayaBrianTauro
{
field: "book_name",
title: "Book Name",
headerFilterPlaceholder: " ",
headerFilter: 'select',
headerFilterFunc:"in",
headerFilterParams: {values:true, sortValuesList:"asc", multiselect:true}
},
Here is an example of a custom header filter for tabulator of 'select multiple' type. It can be converted to a dropdown style if desired using external sources such as Chosen or multiselect.js
(I recommend running the below Code Snippet in Full Page view).
const speciesTypes = ['Human', 'Android', 'Betazoid', 'Klingon', 'Ferengi', 'Tamarian'];
function multiSelectHeaderFilter(cell) {
var values = speciesTypes;
const filterFunc = (rowData) => {
return values.includes(rowData['species']);
}
const getSelectedValues = (multiSelect) => {
var result = [];
var options = multiSelect && multiSelect.options;
var opt;
for (var i = 0, iLen = options.length; i < iLen; i++) {
opt = options[i];
if (opt.selected) {
result.push(opt.value || opt.text);
}
}
return result;
}
const onChange = () => {
var editor = document.getElementById('speciesSelector');
values = getSelectedValues(editor);
console.log("values: " + values);
cell.getColumn().getTable().removeFilter(filterFunc);
cell.getColumn().getTable().addFilter(filterFunc);
}
var select = document.createElement("select");
select.multiple = "multiple";
select.id = 'speciesSelector';
select.class = "chosen-select";
select.style = 'width: 100%';
speciesTypes.forEach(species => {
select.innerHTML += "<option id='" + species + "' value='" + species + "' selected='selected'>" + species + "</option>";
});
cell.getColumn().getTable().addFilter(filterFunc);
select.addEventListener('change', onChange);
return select;
}
var table = new Tabulator("#tabulator", {
layout: "fitColumns",
data: [{
name: 'Geordi La Forge',
species: 'Human'
}, {
name: 'Dathon',
species: 'Tamarian'
}, {
name: 'Jean-Luc Picard',
species: 'Human'
}, {
name: 'Worf, son of Mogh',
species: 'Klingon'
}, {
name: 'Tasha Yarr',
species: 'Human'
}, {
name: 'Data',
species: 'Android'
}, {
name: 'Wesley Crusher',
species: 'Human'
}, {
name: 'Jalad',
species: 'Tamarian'
}, {
name: 'Lwaxana Troi',
species: 'Betazoid'
}, {
name: 'Temba',
species: 'Tamarian'
}, {
name: 'T\'Kuvma',
species: 'Klingon'
}, {
name: 'Lore',
species: 'Android'
}, {
name: 'Noonian Soongh',
species: 'Human'
}, {
name: 'Darmok',
species: 'Tamarian'
}, {
name: 'Reittan Grax',
species: 'Betazoid'
}, {
name: 'Quark',
species: 'Ferengi'
}],
headerSort: true,
columns: [{
title: 'Name',
field: 'name',
sorter: 'string'
}, {
title: 'Species',
field: 'species',
sorter: 'string',
headerFilter: multiSelectHeaderFilter,
headerFilterLiveFilter: false
}, ],
});
<html>
<head>
<link href="https://unpkg.com/tabulator-tables#4.5.3/dist/css/tabulator.min.css" rel="stylesheet">
<script type="text/javascript" src="https://unpkg.com/tabulator-tables#4.5.3/dist/js/tabulator.min.js"></script>
</head>
<body>
<div id="tabulator"></div>
</body>
</html>
JSFiddle: https://jsfiddle.net/jjech/3th28pv0/
See my answer to Tabulator Multiple Filter in the same Column (show dropbox)
Extend as you see fit...
I dont think <select> support checkboxes as <option>'s, but it would be trivial to replace the <select> with a different style of "pulldown" that does.
Hello and Happy new Year guys,
Again I ask about v-treeview search. When I do my filter, the behavior do not satisfy me.
I updated my version of vuetify to 1.4.0. And I'm using vue 2.5.15
https://codepen.io/anon/pen/PXeMmy?&editors=101
HTML
<div id="app">
<v-container grid-list-md>
<v-layout wrap>
<v-flex xs6>
<!-- Search Field -->
<v-text-field label="search" v-model="search" box>
</v-text-field>
<!-- Treeview -->
<v-treeview :items="filteredTree"
v-model="selected"
active-class="grey lighten-4 indigo--text"
item-key="name"
selected-color="blue"
selectable
hoverable>
</v-treeview>
</v-flex>
<v-flex xs6>
<v-chip v-for="(s , i) in selected" :key="i">
{{s}}
</v-chip>
</v-flex>
</v-layout>
</v-container>
</div>
JS :
new Vue({
el: '#app',
data(){
return{
search: '',
tree: [
{
id: 1,
name: 'Applications',
children: [
{ id: 2, name: 'Calendar' },
{ id: 3, name: 'Chrome' },
{ id: 4, name: 'Webstorm' }
]
},
{
id: 5,
name: 'Languages',
children: [
{ id: 6, name: 'English' },
{ id: 7, name: 'French' },
{ id: 8, name: 'Spannish' }
]
}
],
selected: []
}
},
computed:{
filteredTree: {
get: function() {
let regexp = new RegExp(this.search, "i")
return this.filterTree(this.tree, regexp) || []
},
},
},
methods: {
filterTree: function(tree, filter) {
if (!Array.isArray(tree)) return null
return JSON.parse(JSON.stringify(tree)).filter(function matchName(o) {
let temp;
if (o.name.match(filter)) {
return true;
}
if (!Array.isArray(o.children)) {
return false;
}
temp = o.children.filter(matchName);
if (temp.length) {
o.children = temp;
return true;
}
});
}
}
})
In this exemple when I search "Calen", only "Application -> Calendar" is visible. Until now, it's what I want.
But when I select Calendar, "Application" is also selected; and when I clear the filter, all the children of "Application" are selected too. And I'd like to select "Calendar" and when I clear I don't want its siblings to be selected.
Thank you for reading
I'm working on a Flowchart editor and I want the ui.inspector to edit labels on links.
I did the following:
function createInspector(cellView) {
if (!inspector || inspector.options.cellView !== cellView) {
if (inspector) {
inspector.remove();
}
inspector = new joint.ui.Inspector({
inputs: {
labels:
attrs: {
text:{
text: { type: 'textarea', group: 'Labels', label: 'Label', index: 2 },
}
}
},
},
},
groups: {
labels:[ { label: 'Labels', index: 1 },
}],
cellView: cellView
});
$('#inspector-holder-create').html(inspector.render().el);
}
}
paper.on('cell:pointerdown', function(cellView) {
createInspector(cellView);
});
However, when I edit a link it shows in the JSON output:
"labels": {
"0": {
"attrs": {
"text": {
"text": "Text I entered"
}
}
}
},
but doesn't actually render on the link in the stencil.
I think the problem is with the { "0": part the inspector adds. I want to remove that and replace with it [ ] so the output will be
labels: [
{ attrs: { text: { text: 'label' } } }
]
What should I do ??
It is possible to define Inspector inputs with paths.
'labels/0/attrs/text/text': {
type: 'text',
group: 'Text',
index: 1,
label: 'Label'
}
Or as a combination of attributes nesting and paths.
'labels/0/attrs': {
text: {
text: {
type: 'text',
group: 'Text',
index: 1,
label: 'Label'
},
fontSize: {
type: 'number',
group: 'Text',
index: 2,
label: 'Font Size'
}
}
}
This is valid for Rappid v2.4.0+.
inspector = new joint.ui.Inspector({
inputs: {
'labels': [
{attrs: {
text: {
text: {
type: 'text',
group: 'someGroup',
index: 1,
label: "Label"
}
}
}}
]
}});