🎩 You're Invited:Meet the Socket team at Black Hat in Las Vegas, August 3-6.RSVP
Sign In

@ax2/xms-dashboard-module

Package Overview
Dependencies
Maintainers
1
Versions
16
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

@ax2/xms-dashboard-module - npm Package Compare versions

Comparing version
0.3.1
to
0.4.0
+139
src/components/ChartsArea.vue
<template>
<WidgetTemplate
:title="title"
:loading="isLoading"
:filters="filters"
@updateFilters="updateFilters"
>
<apexchart
v-if="!isLoading && datas && isEmpty !== true"
:options="datas.options"
:series="datas.series"
:height="options.style ? '100%' : 'auto'"
/>
<p v-else-if="!isLoading && error">
{{ error }}
</p>
<p v-else-if="!isLoading && isEmpty">
No data to display
</p>
</WidgetTemplate>
</template>
<script>
import gql from 'graphql-tag';
import VueApexCharts from 'vue-apexcharts';
import { get } from 'lodash';
import filterMixins from '../mixins/filter';
import WidgetTemplate from './WidgetTemplate';
export default {
name: 'ChartsArea',
components: {
'apexchart': VueApexCharts,
WidgetTemplate,
},
mixins: [
filterMixins,
],
props: {
title: {
type: String,
required: false,
default: null,
},
options: {
type: Object,
required: true,
},
},
data () {
return {
show: false,
responsive: [
{
breakpoint: 2000,
options: {
legend: {
position: "bottom"
}
}
},
],
error: null,
query: `
query Query($query: String, $chartType: String, $groupByVariable: String, $labels: [String]){
datas: chart(query: $query, chartType: $chartType, groupByVariable: $groupByVariable, labels: $labels) {
options {
chart { type },
labels,
xaxis { categories }
}
series
}
}
`,
};
},
apollo: {
datas: {
query () {
return gql(this.query);
},
variables () {
return this.gqlVariables;
},
skip () {
return this.filtersLoading;
},
result (data) {
if (data.error) {
this.error = data.error;
return;
}
data.data.datas.options = { ...data.data.datas.options, ...{ legend: { position: 'bottom'} } };
return data.data.datas;
}
},
},
computed: {
gqlVariables () {
let filter = this.options.filter ? this.options.filter : null;
if (Object.keys(this.selectedFilters).length > 0) {
filter = filter ? `${filter},${this.getFilterValue()}` : this.getFilterValue();
}
let query = `
query {
datas: ${this.options.id} ${filter ? `(queryInput: { filter: "${filter}" })`: ''} {
id,
${this.options.related}
}
}
`;
if (this.options.filterValue) {
query = query.replace(`\${${this.options.filterValue.key}}`, get(this, this.options.filterValue.value));
}
return {
query,
chartType: this.options.type,
groupByVariable: this.options.groupBy,
labels: this.options.labels
};
},
isLoading () {
return this.$apolloData.queries.datas.loading;
},
isEmpty () {
switch (this.options.type) {
case 'area':
case 'pie':
return get(this.datas, 'options.xaxis.categories', []).length === 0 && get(this.datas, 'series[0].data', []).length === 0;
}
return false;
}
},
beforeDestroy () {
this.$apollo.queries.datas.stop();
},
};
</script>
<template>
<WidgetTemplate
:title="title"
:loading="$apolloData.queries.datas.loading"
:filters="filters"
@updateFilters="updateFilters"
>
<v-data-table
v-if="!$apolloData.queries.datas.loading"
:headers="headers"
:items="datas"
:items-per-page="5"
class="elevation-1"
/>
</WidgetTemplate>
</template>
<script>
import gql from 'graphql-tag';
import filterMixins from '../mixins/filter';
import WidgetTemplate from './WidgetTemplate';
export default {
name: 'DataTable',
components: {
WidgetTemplate,
},
mixins: [
filterMixins,
],
props: {
title: {
type: String,
required: false,
default: null,
},
entity: {
type: String,
required: false,
default: null,
},
query: {
type: String,
required: true,
},
},
data () {
return {
show: false,
};
},
apollo: {
datas: {
query () {
return gql(`query { datas: ${this.formatedQuery} }`);
},
variables () {
return this.gqlVariables;
},
skip () {
return this.filtersLoading;
},
},
},
computed: {
formatedQuery () {
return this.query.replaceAll("${filter}", this.getFilterValue());
},
headers () {
return Object.keys(this.datas[0]).map(header => {
return {
text: this.entity && this.$t(`${this.entity}.${header}`) !== `${this.entity}.${header}` ? this.$t(`${this.entity}.${header}`) : this.$t(header),
value: header
};
});
},
},
beforeDestroy () {
this.$apollo.queries.datas.stop();
},
};
</script>
<template>
<v-card>
<v-card-title v-t="title" />
<v-card-text>
<filters-form
v-if="filtersWithOptions.length > 0"
:items="filtersWithOptions"
:value="selectedFilters"
:search="false"
:type-name="'typeName'"
class="mb-4"
@update:value="$emit('updateFilters', $event)"
/>
<slot v-if="!loading"/>
<!-- Loading spinner -->
<BaseSpinner v-else />
</v-card-text>
</v-card>
</template>
<script>
import filterMixins from '../mixins/filter';
export default {
name: 'WidgetTemplate',
mixins: [
filterMixins,
],
props: {
title: {
type: String,
required: false,
default: null,
},
loading: {
type: Boolean,
required: false,
default: true,
},
},
data () {
return {
show: false,
};
},
};
</script>
import gql from 'graphql-tag';
export default {
props: {
filters: {
type: Array,
required: false,
default: () => [],
}
},
data () {
return {
selectedFilters: {},
filtersLoading: true,
};
},
apollo: {
filtersOptions: {
query () {
return this.createFiltersOptionsQuery(this.filters);
},
skip () {
// Skip query if no gql query is returned
return !this.createFiltersOptionsQuery(this.filters);
},
update (data) {
return data;
}
},
},
created () {
for (const filter of this.filters) {
if (filter.defaultValue !== null || filter.defaultValue !== undefined) {
this.updateFilters({ key: filter.id, value: filter.defaultValue });
}
}
this.filtersLoading = false;
},
methods: {
updateFilters ({ key, value }) {
const newFilter = {};
newFilter[key] = value;
this.selectedFilters[key] = value;
this.selectedFilters = {
... this.selectedFilters,
...newFilter
};
},
getFilterValue () {
// Build array of all filters selected by user
const selectedFiltersArray = Object.keys(this.selectedFilters)
.map(selectedFilterId => {
const filterValue = this.selectedFilters[selectedFilterId];
const filterConfig = this.filters.find(filter => filter.id === selectedFilterId);
if (selectedFilterId === 'dates' && this.selectedFilters[selectedFilterId].length > 0) {
// Handle filter dates with range values
let result = `${filterConfig.whereClause[0]}:${this.selectedFilters[selectedFilterId][0]}`;
if (this.selectedFilters[selectedFilterId][1]) {
result = `${result},${filterConfig.whereClause[1]}:${this.selectedFilters[selectedFilterId][1]} 23-59-59`;
}
return result;
} else if (typeof filterValue === 'object') {
// Handle multiple filter values
const { clauseSeparator } = filterConfig;
const separator = clauseSeparator !== undefined ? clauseSeparator : '(&&)';
const concatValues = filterValue.map(item => {
return item.value;
}).join(separator);
return `${filterConfig.whereClause}:${concatValues}`;
}
if (filterValue === undefined || filterConfig == null) {
return null;
}
return `${filterConfig.whereClause}:${filterValue}`;
})
.filter(filterItem => filterItem !== null);
return selectedFiltersArray.filter(filter => filter).join(',');
},
createFiltersOptionsQuery (filters = []) {
// Get only filters that require options
const requestFilters = filters.filter(filter => {
// Won't request filters that have static options set
return filter.type === 'select' && !filter.options;
});
if (!requestFilters.length) {
return false;
}
// Create a query for every one
const queries = requestFilters.map(filter => {
return `${filter.id}: filter (key: "${filter.id}") {
value: key,
text: value,
}`;
});
return gql`{ ${queries.join(',')} }`;
},
},
computed: {
filtersWithOptions () {
/**
* Translate option function
*/
const translateOption = option => ({
value: option.value,
text: this.$t(option.text)
});
if (!Array.isArray(this.filters)) return [];
return this.filters.map(filterConfig => {
const filter = { ...filterConfig };
// Fetched options take priority over static options
if (this.filtersOptions && this.filtersOptions[filter.id]) {
filter.options = this.filtersOptions[filter.id].map(translateOption);
} else if (filter.options) {
filter.options = filter.options.map(translateOption);
}
return filter;
});
},
},
};
import Vue from 'vue';
const ChartsArea = () => import('../components/ChartsArea');
function installGlobalComponents (Vue) {
Vue.component('ChartsArea', ChartsArea);
}
export default function useGlobalComponents () {
Vue.use(installGlobalComponents);
}
+19
-0

@@ -6,2 +6,21 @@ # Change Log

# [0.4.0](https://github.com/ax2inc/xms-modules/compare/@ax2/xms-dashboard-module@0.3.1...@ax2/xms-dashboard-module@0.4.0) (2022-09-19)
### Bug Fixes
* Fix fetch select ([71af129](https://github.com/ax2inc/xms-modules/commit/71af129d15279907aad5a6bb13df83847a45b22c))
* Wait default filter value to be set before execute query ([35b0c8e](https://github.com/ax2inc/xms-modules/commit/35b0c8e8ca70452f89178924908309e15a3e3a23))
### Features
* Add dashboard widget ([5688db1](https://github.com/ax2inc/xms-modules/commit/5688db1159992c70f7561608ffa573e99d713235))
* Add default value to filters ([b054179](https://github.com/ax2inc/xms-modules/commit/b05417955c488bbe408cda93bf90fd4e8b79218a))
* Add dynamic charts ([8659dbe](https://github.com/ax2inc/xms-modules/commit/8659dbee9592fedf06abcba60305ef11e7f60b4a))
## [0.3.1](https://github.com/ax2inc/xms-modules/compare/@ax2/xms-dashboard-module@0.3.0...@ax2/xms-dashboard-module@0.3.1) (2022-02-24)

@@ -8,0 +27,0 @@

+2
-2
{
"name": "@ax2/xms-dashboard-module",
"version": "0.3.1",
"version": "0.4.0",
"main": "src/main.js",

@@ -43,3 +43,3 @@ "publishConfig": {

},
"gitHead": "6f0ad152c0af0c38bde1f8b94abd526ff363bd83"
"gitHead": "b879b2b253456e82092d9b442549f16718c50621"
}

@@ -77,3 +77,6 @@ <template>

},
destroyed () {
this.$_apollo.queries.details.stop();
}
};
</script>

@@ -5,2 +5,3 @@ import useConfig from './plugins/config';

import registerRoutes from './router';
import useGlobalComponents from './plugins/global-components';

@@ -11,3 +12,4 @@ export default function loadModule (context) {

useI18n(context);
useGlobalComponents(context);
registerRoutes(context);
};

@@ -23,2 +23,4 @@ <template>

import Charts from '../components/Charts';
import ChartsArea from '../components/ChartsArea';
import DataTable from '../components/DataTable';

@@ -31,2 +33,4 @@ export default {

Charts,
ChartsArea,
DataTable,
},

@@ -33,0 +37,0 @@ computed: {