diff --git a/.eslintrc.js b/.eslintrc.js index 79cbb055..c4b10d87 100644 --- a/.eslintrc.js +++ b/.eslintrc.js @@ -43,6 +43,15 @@ module.exports = { }, ], + "sort-imports": ["error", { + "ignoreCase": true, + "ignoreDeclarationSort": false, + "ignoreMemberSort": false, + "memberSyntaxSortOrder": ["none", "all", "multiple", "single"], + "allowSeparatedGroups": false + }], + + // eslint rule customization here: "no-console": 0, // allow console.log() in our services "no-unused-vars": 0, // allow unused variables (webpack will remove them) diff --git a/.github/workflows/e2e-tests.yml b/.github/workflows/e2e-tests.yml index 02971523..5c29bb81 100644 --- a/.github/workflows/e2e-tests.yml +++ b/.github/workflows/e2e-tests.yml @@ -1,88 +1,88 @@ name: E2E Tests on: - workflow_call: + workflow_call: inputs: ref: type: string default: ${{ github.ref }} jobs: - e2e-tests: - name: E2E Tests - runs-on: ubuntu-latest - env: - CYPRESS_RESPONSE_TIMEOUT: 200000 - CYPRESS_DEFAULT_COMMAND_TIMEOUT: 30000 - CYPRESS_RETRIES: 2 - strategy: - fail-fast: true - matrix: - include: - - branch: develop - webpack: dev - - branch: master - webpack: update - steps: - - uses: actions/checkout@v4 - with: - path: ab_platform_web - submodules: true - ref: ${{ inputs.ref }} - - uses: actions/checkout@v4 - with: - path: web - repository: CruGlobal/ab_service_web - token: ${{ secrets.GITHUB_TOKEN }} - ref: ${{ matrix.branch }} + e2e-tests: + name: E2E Tests + runs-on: ubuntu-latest + env: + CYPRESS_RESPONSE_TIMEOUT: 200000 + CYPRESS_DEFAULT_COMMAND_TIMEOUT: 30000 + CYPRESS_RETRIES: 2 + strategy: + fail-fast: true + matrix: + include: + - branch: develop + webpack: dev + - branch: master + webpack: update + steps: + - uses: actions/checkout@v4 + with: + path: ab_platform_web + submodules: true + ref: ${{ inputs.ref }} + - uses: actions/checkout@v4 + with: + path: web + repository: CruGlobal/ab_service_web + token: ${{ secrets.GITHUB_TOKEN }} + ref: ${{ matrix.branch }} - - run: npm i - working-directory: ./ab_platform_web + - run: npm i + working-directory: ./ab_platform_web - - name: Webpack - run: npm run build:${{ matrix.webpack }} - working-directory: ./ab_platform_web + - name: Webpack + run: npm run build:${{ matrix.webpack }} + working-directory: ./ab_platform_web - # webpack expects the folder to be called "web" ab-install action expects "ab_service_web" - - run: mv web ab_service_web + # webpack expects the folder to be called "web" ab-install action expects "ab_service_web" + - run: mv web ab_service_web - - uses: CruGlobal/ab-install-action@v1 - with: - port: 8080 - folder: ab - repository: CruGlobal/ab_service_web + - uses: CruGlobal/ab-install-action@v1 + with: + port: 8080 + folder: ab + repository: CruGlobal/ab_service_web - - name: Check out kitchen-sink tests - uses: actions/checkout@v4 - with: - repository: CruGlobal/kitchensink_app - path: ab/test/e2e/cypress/e2e/kitchensink_app + - name: Check out kitchen-sink tests + uses: actions/checkout@v4 + with: + repository: CruGlobal/kitchensink_app + path: ab/test/e2e/cypress/e2e/kitchensink_app - # These next steps are to save our ablogs to file - - run: npm install pm2@latest -g - - name: Save Logs - run: pm2 start ./logs.js -- --toFile logs/ABServices.log - working-directory: ./ab + # These next steps are to save our ablogs to file + - run: npm install pm2@latest -g + - name: Save Logs + run: pm2 start ./logs.js -- --toFile logs/ABServices.log + working-directory: ./ab - #Run test - - name: Wait for AB - # Skipping the wait step. Cypress has a bit of wait time built in. It might be enough. - if: false - uses: ifaxity/wait-on-action@v1.1.0 - with: - resource: http://localhost:8080 - timeout: 300000 + #Run test + - name: Wait for AB + # Skipping the wait step. Cypress has a bit of wait time built in. It might be enough. + if: false + uses: ifaxity/wait-on-action@v1.1.0 + with: + resource: http://localhost:8080 + timeout: 300000 - - name: Run Cypress Tests - run: npm run test:e2e:app -- --browser chrome - working-directory: ./ab + - name: Run Cypress Tests + run: npm run test:e2e:app -- --browser chrome + working-directory: ./ab - - uses: actions/upload-artifact@v4 - if: failure() - with: - name: cypress-screenshots - path: ./ab/test/e2e/cypress/screenshots + - uses: actions/upload-artifact@v4 + if: failure() + with: + name: cypress-screenshots + path: ./ab/test/e2e/cypress/screenshots - - uses: actions/upload-artifact@v4 - if: failure() - with: - name: ABServices.log - path: ./ab/logs/ABServices.log + - uses: actions/upload-artifact@v4 + if: failure() + with: + name: ABServices.log + path: ./ab/logs/ABServices.log diff --git a/.github/workflows/lighthouse.yml b/.github/workflows/lighthouse.yml index 5ba4bce6..76074b17 100644 --- a/.github/workflows/lighthouse.yml +++ b/.github/workflows/lighthouse.yml @@ -1,133 +1,133 @@ name: Lighthouse CI on: - push: - branches: ["master"] - pull_request: - branches: ["master"] + push: + branches: ["master"] + pull_request: + branches: ["master"] jobs: - lighthouse: - runs-on: ubuntu-latest - steps: - - name: Checkout Platform Web - uses: actions/checkout@v3 - with: - path: ab_platform_web - submodules: true + lighthouse: + runs-on: ubuntu-latest + steps: + - name: Checkout Platform Web + uses: actions/checkout@v6 + with: + path: ab_platform_web + submodules: true - - name: Checkout Web Service - uses: actions/checkout@v3 - with: - path: web - repository: CruGlobal/ab_service_web - token: ${{ secrets.GITHUB_TOKEN }} - ref: master + - name: Checkout Web Service + uses: actions/checkout@v6 + with: + path: web + repository: CruGlobal/ab_service_web + token: ${{ secrets.GITHUB_TOKEN }} + ref: master - - name: Install NPM Dependencies - run: npm i - working-directory: ./ab_platform_web + - name: Install NPM Dependencies + run: npm i + working-directory: ./ab_platform_web - - name: Run Webpack - run: npm run build:update - working-directory: ./ab_platform_web + - name: Run Webpack + run: npm run build:update + working-directory: ./ab_platform_web - # webpack expects the folder to be called "web" ab-install action expects "ab_service_web" - - name: Fix Web Servive Foledr Name - run: mv web ab_service_web + # webpack expects the folder to be called "web" ab-install action expects "ab_service_web" + - name: Fix Web Servive Foledr Name + run: mv web ab_service_web - - name: Install AppBuilder - uses: CruGlobal/ab-install-action@v1 - with: - repository: CruGlobal/ab_service_web + - name: Install AppBuilder + uses: CruGlobal/ab-install-action@v1 + with: + repository: CruGlobal/ab_service_web - - name: Wait for AppBuilder - # Skipping the wait step. Cypress has a bit of wait time built in. It might be enough. - if: false - uses: ifaxity/wait-on-action@v1.1.0 - with: - resource: http://localhost - timeout: 300000 + - name: Wait for AppBuilder + # Skipping the wait step. Cypress has a bit of wait time built in. It might be enough. + if: false + uses: ifaxity/wait-on-action@v1.1.0 + with: + resource: http://localhost + timeout: 300000 - - name: Run Lighthouse CI - run: | - npm install -g @lhci/cli puppeteer - lhci autorun - working-directory: ./ab_platform_web - env: - LHCI_UPLOAD__TARGET: "lhci" - LHCI_UPLOAD__SERVER_BASE_URL: "https://lighthouse.digiserve.org/" - LHCI_UPLOAD__TOKEN: ${{ secrets.LHCI_BUILD_TOKEN }} - LHCI_COLLECT__URL: "http://127.0.0.1" - LHCI_GITHUB_APP_TOKEN: ${{ secrets.LHCI_GITHUB_APP_TOKEN }} - LHCI_COLLECT__PUPPETEER_SCRIPT: "ciLighthouseAuth.js" + - name: Run Lighthouse CI + run: | + npm install -g @lhci/cli puppeteer + lhci autorun + working-directory: ./ab_platform_web + env: + LHCI_UPLOAD__TARGET: "lhci" + LHCI_UPLOAD__SERVER_BASE_URL: "https://lighthouse.digiserve.org/" + LHCI_UPLOAD__TOKEN: ${{ secrets.LHCI_BUILD_TOKEN }} + LHCI_COLLECT__URL: "http://127.0.0.1" + LHCI_GITHUB_APP_TOKEN: ${{ secrets.LHCI_GITHUB_APP_TOKEN }} + LHCI_COLLECT__PUPPETEER_SCRIPT: "ciLighthouseAuth.js" - - name: Get the Lighouse Reports - if: ${{ github.event_name == 'pull_request' }} - id: get_report - run: | - echo "LH_REPORT_A=$(ls | grep lhr- | grep .json | sed -n 1p)" >> $GITHUB_OUTPUT - echo "LH_REPORT_B=$(ls | grep lhr- | grep .json | sed -n 2p)" >> $GITHUB_OUTPUT - echo "LH_REPORT_C=$(ls | grep lhr- | grep .json | sed -n 3p)" >> $GITHUB_OUTPUT - working-directory: ./ab_platform_web/.lighthouseci + - name: Get the Lighouse Reports + if: ${{ github.event_name == 'pull_request' }} + id: get_report + run: | + echo "LH_REPORT_A=$(ls | grep lhr- | grep .json | sed -n 1p)" >> $GITHUB_OUTPUT + echo "LH_REPORT_B=$(ls | grep lhr- | grep .json | sed -n 2p)" >> $GITHUB_OUTPUT + echo "LH_REPORT_C=$(ls | grep lhr- | grep .json | sed -n 3p)" >> $GITHUB_OUTPUT + working-directory: ./ab_platform_web/.lighthouseci - - name: Extract Report Highlights - if: ${{ github.event_name == 'pull_request' }} - uses: actions/github-script@v7 - env: - REPORT_A: ${{ steps.get_report.outputs.LH_REPORT_A }} - REPORT_B: ${{ steps.get_report.outputs.LH_REPORT_B }} - REPORT_C: ${{ steps.get_report.outputs.LH_REPORT_C }} - with: - script: | - const reports = [ - require(`./ab_platform_web/.lighthouseci/${process.env.REPORT_A}`), - require(`./ab_platform_web/.lighthouseci/${process.env.REPORT_B}`), - require(`./ab_platform_web/.lighthouseci/${process.env.REPORT_C}`), - ]; - const links = require("./ab_platform_web/.lighthouseci/links.json"); - const getColor = (score) => score - 49 <= 0 ? "FF3333" : score - 89 <= 0 ? "FFAA33": "00CC66"; - const average = (vals, multiply = 1) => Math.round(vals.reduce((a,b) => a + b) / vals.length * multiply); - const extractDetails = (key) => { - const reportEntry = reports[0].audits[key]; - const details = { - title: reportEntry.title, - score: average(reports.map(r => r.audits[key].score), 100), - }; - details.color = getColor(details.score); - if (reportEntry.scoreDisplayMode === "numeric") { - details.score = average(reports.map(r => r.audits[key].numericValue)); - } - return details; - } - const performance = average(reports.map(r => r.categories.performance.score), 100); - core.exportVariable("PERFORMANCE", performance); - core.exportVariable("PERFORMANCE_COLOR", getColor(performance)); - const fcp = extractDetails("first-contentful-paint"); - core.exportVariable("FCP", `${Math.round(fcp.score/100)/10}%20s`); - core.exportVariable("FCP_COLOR", fcp.color); - const lcp = extractDetails("largest-contentful-paint"); - core.exportVariable("LCP", `${Math.round(lcp.score/100)/10}%20s`); - core.exportVariable("LCP_COLOR", lcp.color); - const tbt = extractDetails("total-blocking-time"); - core.exportVariable("TBT", `${tbt.score}%20ms`); - core.exportVariable("TBT_COLOR", tbt.color); - const cls = extractDetails("cumulative-layout-shift"); - core.exportVariable("CLS", cls.score); - core.exportVariable("CLS_COLOR", cls.color); - const speed = extractDetails("speed-index"); - core.exportVariable("SPEED", `${Math.round(speed.score/100)/10}%20s`); - core.exportVariable("SPEED_COLOR", speed.color); - core.exportVariable("LINK", links[Object.keys(links)[0]]); + - name: Extract Report Highlights + if: ${{ github.event_name == 'pull_request' }} + uses: actions/github-script@v7 + env: + REPORT_A: ${{ steps.get_report.outputs.LH_REPORT_A }} + REPORT_B: ${{ steps.get_report.outputs.LH_REPORT_B }} + REPORT_C: ${{ steps.get_report.outputs.LH_REPORT_C }} + with: + script: | + const reports = [ + require(`./ab_platform_web/.lighthouseci/${process.env.REPORT_A}`), + require(`./ab_platform_web/.lighthouseci/${process.env.REPORT_B}`), + require(`./ab_platform_web/.lighthouseci/${process.env.REPORT_C}`), + ]; + const links = require("./ab_platform_web/.lighthouseci/links.json"); + const getColor = (score) => score - 49 <= 0 ? "FF3333" : score - 89 <= 0 ? "FFAA33": "00CC66"; + const average = (vals, multiply = 1) => Math.round(vals.reduce((a,b) => a + b) / vals.length * multiply); + const extractDetails = (key) => { + const reportEntry = reports[0].audits[key]; + const details = { + title: reportEntry.title, + score: average(reports.map(r => r.audits[key].score), 100), + }; + details.color = getColor(details.score); + if (reportEntry.scoreDisplayMode === "numeric") { + details.score = average(reports.map(r => r.audits[key].numericValue)); + } + return details; + } + const performance = average(reports.map(r => r.categories.performance.score), 100); + core.exportVariable("PERFORMANCE", performance); + core.exportVariable("PERFORMANCE_COLOR", getColor(performance)); + const fcp = extractDetails("first-contentful-paint"); + core.exportVariable("FCP", `${Math.round(fcp.score/100)/10}%20s`); + core.exportVariable("FCP_COLOR", fcp.color); + const lcp = extractDetails("largest-contentful-paint"); + core.exportVariable("LCP", `${Math.round(lcp.score/100)/10}%20s`); + core.exportVariable("LCP_COLOR", lcp.color); + const tbt = extractDetails("total-blocking-time"); + core.exportVariable("TBT", `${tbt.score}%20ms`); + core.exportVariable("TBT_COLOR", tbt.color); + const cls = extractDetails("cumulative-layout-shift"); + core.exportVariable("CLS", cls.score); + core.exportVariable("CLS_COLOR", cls.color); + const speed = extractDetails("speed-index"); + core.exportVariable("SPEED", `${Math.round(speed.score/100)/10}%20s`); + core.exportVariable("SPEED_COLOR", speed.color); + core.exportVariable("LINK", links[Object.keys(links)[0]]); - # NejcZdovc/comment-pr@v2 needs a checkout to the base path - - name: Fix for NejcZdovc/comment-pr - if: ${{ github.event_name == 'pull_request' }} - uses: actions/checkout@v3 + # NejcZdovc/comment-pr@v2 needs a checkout to the base path + - name: Fix for NejcZdovc/comment-pr + if: ${{ github.event_name == 'pull_request' }} + uses: actions/checkout@v6 - - name: Add Lighthouse Results to PR Commnet - if: ${{ github.event_name == 'pull_request' }} - uses: NejcZdovc/comment-pr@v2 - with: - file: lighthouse.md - identifier: LIGHTHOUSE_REPORT - env: - GITHUB_TOKEN: ${{secrets.GITHUB_TOKEN}} + - name: Add Lighthouse Results to PR Commnet + if: ${{ github.event_name == 'pull_request' }} + uses: NejcZdovc/comment-pr@v2 + with: + file: lighthouse.md + identifier: LIGHTHOUSE_REPORT + env: + GITHUB_TOKEN: ${{secrets.GITHUB_TOKEN}} diff --git a/AppBuilder/core b/AppBuilder/core index a740ae92..ac6a1c45 160000 --- a/AppBuilder/core +++ b/AppBuilder/core @@ -1 +1 @@ -Subproject commit a740ae923955823569f86421f4bc29b107f4fbc3 +Subproject commit ac6a1c45b11a9aad0d15d0111fc697331b3d316d diff --git a/AppBuilder/platform/plugins/included/index.js b/AppBuilder/platform/plugins/included/index.js index cdc4f0a9..26df8041 100644 --- a/AppBuilder/platform/plugins/included/index.js +++ b/AppBuilder/platform/plugins/included/index.js @@ -1,4 +1,5 @@ import viewCarousel from "./view_carousel/FNAbviewcarousel.js"; +import viewChart from "./view_chart/FNAbviewchart.js"; import viewComment from "./view_comment/FNAbviewcomment.js"; import viewCsvExporter from "./view_csvExporter/FNAbviewcsvexporter.js"; import viewCsvImporter from "./view_csvImporter/FNAbviewcsvimporter.js"; @@ -17,6 +18,7 @@ import viewText from "./view_text/FNAbviewtext.js"; const AllPlugins = [ viewCarousel, + viewChart, viewComment, viewCsvExporter, viewCsvImporter, diff --git a/AppBuilder/platform/plugins/included/view_chart/FNAbviewchart.js b/AppBuilder/platform/plugins/included/view_chart/FNAbviewchart.js new file mode 100644 index 00000000..3d6a0702 --- /dev/null +++ b/AppBuilder/platform/plugins/included/view_chart/FNAbviewchart.js @@ -0,0 +1,15 @@ +import viewChart from "./chart/FNAbviewchart.js"; +import viewChartArea from "./area/FNAbviewchartarea.js"; +import viewChartBar from "./bar/FNAbviewchartbar.js"; +import viewChartLine from "./line/FNAbviewchartline.js"; +import viewChartPie from "./pie/FNAbviewchartpie.js"; + +export default function ABchart(API) { + return [ + viewChart(API), + viewChartArea(API), + viewChartBar(API), + viewChartLine(API), + viewChartPie(API), + ]; +} \ No newline at end of file diff --git a/AppBuilder/platform/plugins/included/view_chart/area/FNAbviewchartarea.js b/AppBuilder/platform/plugins/included/view_chart/area/FNAbviewchartarea.js new file mode 100644 index 00000000..4b585134 --- /dev/null +++ b/AppBuilder/platform/plugins/included/view_chart/area/FNAbviewchartarea.js @@ -0,0 +1,122 @@ +import FNAbviewchartareaComponent from "./FNAbviewchartareaComponent.js"; +import { FNABViewChartCore } from "../chartBindings.js"; + +// FNAbviewchartarea Web +// A web side import for an ABView. +// +export default function FNAbviewchartarea({ + AB, + ABViewComponentPlugin, + ABViewWidgetPlugin, +}) { + const ABViewChartCore = FNABViewChartCore({ ABViewWidgetPlugin }); + const ABAbviewchartareaComponent = FNAbviewchartareaComponent({ + AB, + ABViewComponentPlugin, + }); + + const ABViewChartAreaPropertyComponentDefaults = { + areaType: "area", + isLegend: 1, + chartHeight: 200, + labelFontSize: 12, + stepValue: 20, + maxValue: 100, + }; + + const ABViewDefaults = { + key: "area", // {string} unique key for this view + icon: "area-chart", // {string} fa-[icon] reference for this view + labelKey: "Area", // {string} the multilingual label key for the class label + }; + + class ABViewChartAreaCore extends ABViewChartCore { + constructor(values, application, parent, defaultValues) { + super(values, application, parent, defaultValues || ABViewDefaults); + } + + static common() { + return ABViewDefaults; + } + + static defaultValues() { + return ABViewChartAreaPropertyComponentDefaults; + } + + /// + /// Instance Methods + /// + + /** + * @method fromValues() + * + * initialze this object with the given set of values. + * @param {obj} values + */ + fromValues(values) { + super.fromValues(values); + + this.settings.areaType = + this.settings.areaType || + ABViewChartAreaPropertyComponentDefaults.areaType; + + this.settings.isLegend = parseInt( + this.settings.isLegend ?? + ABViewChartAreaPropertyComponentDefaults.isLegend + ); + + // this.settings.chartWidth = parseInt(this.settings.chartWidth || ABViewChartAreaPropertyComponentDefaults.chartWidth); + this.settings.chartHeight = parseInt( + this.settings.chartHeight ?? + ABViewChartAreaPropertyComponentDefaults.chartHeight + ); + + this.settings.labelFontSize = parseInt( + this.settings.labelFontSize ?? + ABViewChartAreaPropertyComponentDefaults.labelFontSize + ); + this.settings.stepValue = parseInt( + this.settings.stepValue ?? + ABViewChartAreaPropertyComponentDefaults.stepValue + ); + this.settings.maxValue = parseInt( + this.settings.maxValue ?? + ABViewChartAreaPropertyComponentDefaults.maxValue + ); + + this.translate(this, this, ["areaLabel"]); + } + + /** + * @method componentList + * return the list of components available on this view to display in the editor. + */ + componentList() { + return []; + } + } + + return class ABViewChartArea extends ABViewChartAreaCore { + /** + * @method getPluginKey + * return the plugin key for this view. + * @return {string} plugin key + */ + static getPluginKey() { + return this.common().key; + } + + /** + * @method component() + * return a UI component based upon this view. + * @return {obj} UI component + */ + component() { + return new ABAbviewchartareaComponent(this); + } + + // constructor(values, application, parent, defaultValues) { + // super(values, application, parent, defaultValues); + // } + }; +} diff --git a/AppBuilder/platform/plugins/included/view_chart/area/FNAbviewchartareaComponent.js b/AppBuilder/platform/plugins/included/view_chart/area/FNAbviewchartareaComponent.js new file mode 100644 index 00000000..f550329b --- /dev/null +++ b/AppBuilder/platform/plugins/included/view_chart/area/FNAbviewchartareaComponent.js @@ -0,0 +1,60 @@ +import { FNAbviewchartcontainerComponent } from "../chartBindings.js"; + +export default function FNAbviewchartareaComponent({ ABViewComponentPlugin }) { + const ChartContainerComponent = FNAbviewchartcontainerComponent({ + ABViewComponentPlugin, + }); + + return class ABviewchartareaComponent extends ChartContainerComponent { + constructor(baseView, idBase, ids) { + super(baseView, idBase || `ABViewChartArea_${baseView.id}`, ids); + } + + ui() { + const settings = this.settings; + + return super.ui({ + view: "chart", + type: settings.areaType, + yAxis: { + start: 0, + step: settings.stepValue, //"#stepValue#", + end: settings.maxValue, //"#maxValue#" + }, + xAxis: { + template: settings.isLegend + ? `
#label#
` + : "", + }, + legend: settings.isLegend + ? { + template: `
#label#
`, + values: [], // TODO : bug in webix 5.1.7 + } + : null, + series: [ + { + alpha: 0.7, + value: "#value#", + color: "#ee4339", + }, + { + alpha: 0.4, + value: "#value2#", + color: "#a7ee70", + }, + ], + height: settings.chartHeight, + // width: settings.chartWidth, + }); + } + + async init(AB) { + await super.init(AB); + } + + onShow() { + super.onShow(); + } + }; +} diff --git a/AppBuilder/platform/plugins/included/view_chart/bar/FNAbviewchartbar.js b/AppBuilder/platform/plugins/included/view_chart/bar/FNAbviewchartbar.js new file mode 100644 index 00000000..b4ce0c6a --- /dev/null +++ b/AppBuilder/platform/plugins/included/view_chart/bar/FNAbviewchartbar.js @@ -0,0 +1,126 @@ +import FNAbviewchartbarComponent from "./FNAbviewchartbarComponent.js"; +import { FNABViewChartCore } from "../chartBindings.js"; + +// FNAbviewchartbar Web +// A web side import for an ABView. +// +export default function FNAbviewchartbar({ + ABViewComponentPlugin, + ABViewWidgetPlugin, +}) { + const ABViewChartCore = FNABViewChartCore({ ABViewWidgetPlugin }); + const ABAbviewchartbarComponent = FNAbviewchartbarComponent({ + ABViewComponentPlugin, + }); + + const ABViewChartBarPropertyComponentDefaults = { + barType: "bar", + barPreset: "column", + isLegend: 1, + // chartWidth: 600, + height: 200, + labelFontSize: 12, + stepValue: 20, + maxValue: 100, + }; + + const ABViewDefaults = { + key: "bar", // {string} unique key for this view + icon: "bar-chart", // {string} fa-[icon] reference for this view + labelKey: "Bar", // {string} the multilingual label key for the class label + }; + + class ABViewChartBarCore extends ABViewChartCore { + constructor(values, application, parent, defaultValues) { + super(values, application, parent, defaultValues || ABViewDefaults); + } + + static common() { + return ABViewDefaults; + } + + static defaultValues() { + return ABViewChartBarPropertyComponentDefaults; + } + + /// + /// Instance Methods + /// + + /** + * @method fromValues() + * + * initialze this object with the given set of values. + * @param {obj} values + */ + fromValues(values) { + super.fromValues(values); + + this.settings.barType = + this.settings.barType || + ABViewChartBarPropertyComponentDefaults.barType; + + this.settings.barPreset = + this.settings.barPreset || + ABViewChartBarPropertyComponentDefaults.barPreset; + + this.settings.isLegend = parseInt( + this.settings.isLegend ?? + ABViewChartBarPropertyComponentDefaults.isLegend + ); + + // this.settings.chartWidth = parseInt(this.settings.chartWidth || ABViewChartBarPropertyComponentDefaults.chartWidth); + this.settings.height = parseInt( + this.settings.height ?? + ABViewChartBarPropertyComponentDefaults.height + ); + + this.settings.labelFontSize = parseInt( + this.settings.labelFontSize ?? + ABViewChartBarPropertyComponentDefaults.labelFontSize + ); + this.settings.stepValue = parseInt( + this.settings.stepValue ?? + ABViewChartBarPropertyComponentDefaults.stepValue + ); + this.settings.maxValue = parseInt( + this.settings.maxValue ?? + ABViewChartBarPropertyComponentDefaults.maxValue + ); + + this.translate(this, this, ["barLabel"]); + } + + /** + * @method componentList + * return the list of components available on this view to display in the editor. + */ + componentList() { + return []; + } + } + + return class ABViewChartBar extends ABViewChartBarCore { + /** + * @method getPluginKey + * return the plugin key for this view. + * @return {string} plugin key + */ + static getPluginKey() { + return this.common().key; + } + + /** + * @method component() + * return a UI component based upon this view. + * @return {obj} UI component + */ + component() { + return new ABAbviewchartbarComponent(this); + } + + // constructor(values, application, parent, defaultValues) { + // super(values, application, parent, defaultValues); + // } + }; +} diff --git a/AppBuilder/platform/plugins/included/view_chart/bar/FNAbviewchartbarComponent.js b/AppBuilder/platform/plugins/included/view_chart/bar/FNAbviewchartbarComponent.js new file mode 100644 index 00000000..f142a190 --- /dev/null +++ b/AppBuilder/platform/plugins/included/view_chart/bar/FNAbviewchartbarComponent.js @@ -0,0 +1,58 @@ +import { FNAbviewchartcontainerComponent } from "../chartBindings.js"; + +export default function FNAbviewchartbarComponent({ + ABViewComponentPlugin, +}) { + const ChartContainerComponent = FNAbviewchartcontainerComponent({ + ABViewComponentPlugin, + }); + + return class FNAbviewchartbarComponent extends ChartContainerComponent { + constructor(baseView, idBase, ids) { + super(baseView, idBase || `ABViewChartBar_${baseView.id}`, ids); + } + + ui() { + const settings = this.settings; + + return super.ui({ + view: "chart", + type: settings.barType, + preset: settings.barPreset, + value: "#value#", + color: "#color#", + yAxis: { + start: 0, + step: settings.stepValue, //"#stepValue#", + end: settings.maxValue, //"#maxValue#" + }, + xAxis: { + template: settings.isLegend + ? `
#label#
` + : "", + }, + legend: + settings.barType === "bar" || !settings.barType + ? settings.isLegend + ? `
#label#
` + : "" + : settings.isLegend + ? { + template: `
#label#
`, + values: [], // TODO : bug in webix 5.1.7 + } + : null, + height: settings.height, + // width: settings.chartWidth, + }); + } + + async init(AB) { + await super.init(AB); + } + + onShow() { + super.onShow(); + } + }; +} diff --git a/AppBuilder/platform/plugins/included/view_chart/chart/FNAbviewchart.js b/AppBuilder/platform/plugins/included/view_chart/chart/FNAbviewchart.js new file mode 100644 index 00000000..76bb39ae --- /dev/null +++ b/AppBuilder/platform/plugins/included/view_chart/chart/FNAbviewchart.js @@ -0,0 +1,367 @@ + +import FNAbviewchartComponent from "./FNAbviewchartComponent.js"; + +// FNAbviewchart Web +// A web side import for an ABView. +// +export default function FNAbviewchart({ + AB, + ABViewContainerComponent, + ABViewContainer, +}) { + const ABAbviewchartComponent = FNAbviewchartComponent({ + AB, + ABViewContainerComponent, + }); + + const ABViewChartPropertyComponentDefaults = { + dataviewID: "", + columnValue: "", + columnLabel: "", + columnValue2: "", + isPercentage: 1, + showLabel: 1, + labelPosition: "left", + labelWidth: 120, + height: 200, + multipleSeries: 0, + }; + + const ABViewChartDefaults = { + key: "chart", // {string} unique key for this view + icon: "bar-chart", // {string} fa-[icon] reference for this view + labelKey: "Chart", // {string} the multilingual label key for the class label + }; + + // this needs to be a class that extends ABViewContainer + class ABViewChartCore extends ABViewContainer { + constructor(values, application, parent, defaultValues) { + super(values, application, parent, defaultValues || ABViewChartDefaults); + } + + static getPluginType() { + return "view"; + } + static common() { + return ABViewChartDefaults; + } + + static defaultValues() { + return ABViewChartPropertyComponentDefaults; + } + + /// + /// Instance Methods + /// + + /** + * @method fromValues() + * + * initialze this object with the given set of values. + * @param {obj} values + */ + fromValues(values) { + super.fromValues(values); + + this.settings.dataviewID = + this.settings.dataviewID ?? + ABViewChartPropertyComponentDefaults.dataviewID; + + this.settings.columnValue = + this.settings.columnValue ?? + ABViewChartPropertyComponentDefaults.columnValue; + + this.settings.columnLabel = + this.settings.columnLabel ?? + ABViewChartPropertyComponentDefaults.columnLabel; + + this.settings.columnValue2 = + this.settings.columnValue2 ?? + ABViewChartPropertyComponentDefaults.columnValue2; + + this.settings.isPercentage = parseInt( + this.settings.isPercentage ?? + ABViewChartPropertyComponentDefaults.isPercentage + ); + + this.settings.showLabel = parseInt( + this.settings.showLabel ?? + ABViewChartPropertyComponentDefaults.showLabel + ); + + this.settings.labelPosition = + this.settings.labelPosition || + ABViewChartPropertyComponentDefaults.labelPosition; + + this.settings.labelWidth = parseInt( + this.settings.labelWidth ?? + ABViewChartPropertyComponentDefaults.labelWidth + ); + + this.settings.height = parseInt( + this.settings.height ?? ABViewChartPropertyComponentDefaults.height + ); + + this.settings.multipleSeries = parseInt( + this.settings.multipleSeries ?? + ABViewChartPropertyComponentDefaults.multipleSeries + ); + + this.translate(this, this, ["chartLabel"]); + } + + /** + * @method componentList + * return the list of components available on this view to display in the editor. + */ + componentList() { + const viewsToAllow = ["label", "pie", "bar", "line", "area"]; + return this.application.viewAll((c) => { + return viewsToAllow.indexOf(c.common().key) > -1; + }); + } + + labelField() { + const dc = this.datacollection; + if (!dc) return null; + + const obj = dc.datasource; + if (!obj) return null; + + return obj.fieldByID(this.settings.columnLabel); + } + + valueField() { + const dc = this.datacollection; + if (!dc) return null; + + const obj = dc.datasource; + if (!obj) return null; + + return obj.fieldByID(this.settings.columnValue); + } + + valueField2() { + const dc = this.datacollection; + if (!dc) return null; + + const obj = dc.datasource; + if (!obj) return null; + + return obj.fieldByID(this.settings.columnValue2); + } + }; + + return class ABViewChart extends ABViewChartCore { + /** + * @method getPluginKey + * return the plugin key for this view. + * @return {string} plugin key + */ + static getPluginKey() { + return this.common().key; + } + + static getPluginType() { + return "view"; + } + + /** + * @method component() + * return a UI component based upon this view. + * @return {obj} UI component + */ + component(parentId) { + return new ABAbviewchartComponent(this, parentId); + } + + fromValues(values) { + super.fromValues(values); + this.refreshData(); + } + + getDCChart() { + if (!this._dcChart) this._dcChart = new webix.DataCollection(); + + return this._dcChart; + } + + refreshData() { + const dc = this.datacollection; + if (dc == null) { + return this.getDCChart(); + } + + const labelCol = this.labelField(); + const valueCol = this.valueField(); + const valueCol2 = this.valueField2(); + + if (!labelCol || !valueCol) { + return this.getDCChart(); + } + + const numberColName = valueCol.columnName; + + let numberColName2 = ""; + + if (this.settings.multipleSeries && valueCol2) { + numberColName2 = valueCol2.columnName; + } + + const colorList = [ + "#ee4339", + "#ee9336", + "#eed236", + "#d3ee36", + "#a7ee70", + "#58dccd", + "#36abee", + "#476cee", + "#a244ea", + "#e33fc7", + ]; + + const dInfo = dc.getData(); + + let results = []; + let sumData = {}; + let sumNumber = 0; + let sumNumber2 = 0; + let countNumber = dInfo.length; + + dInfo.forEach((item) => { + const labelKey = labelCol.format(item) || item.id; + + let numberVal = parseFloat(item[numberColName] || 0); + let numberVal2 = null; + + if (this.settings.multipleSeries) + numberVal2 = parseFloat(item[numberColName2]) || 0; + + switch (valueCol.key) { + case "formula": + numberVal = valueCol.format(item); + + break; + + case "calculate": + numberVal = parseFloat( + valueCol.constructor.convertToJs( + valueCol.object, + valueCol.settings.formula, + item, + valueCol.settings.decimalPlaces + ) + ); + + break; + + default: + break; + } + + if (sumData[labelKey] == null) { + let label = labelKey; + + if (labelCol.isConnection) { + let relateValues = labelCol.pullRelationValues(item); + if (relateValues != null) { + if (Array.isArray(relateValues)) + label = relateValues + .map((val) => val.text || "") + .join(", "); + else label = relateValues.text; + } + } + + if (this.settings.multipleSeries) { + sumData[labelKey] = { + label: label || item.id, + value: 0, + value2: 0, + }; + } else { + sumData[labelKey] = { + label: label || item.id, + value: 0, + }; + } + } + + sumData[labelKey].value += numberVal; + sumNumber += numberVal; + + if (this.settings.multipleSeries) { + sumData[labelKey].value2 += numberVal2; + sumNumber2 += numberVal2; + } + }); + + let index = 0; + + for (const key in sumData) { + let val = sumData[key].value; + + if (val <= 0) continue; + + if (this.settings.isPercentage) { + val = (val / sumNumber) * 100; + val = Math.round(val * 100) / 100; + val = val + " %"; + } + + if (this.settings.multipleSeries) { + let val2 = sumData[key].value2; + + if (val2 <= 0) continue; + + if (this.settings.isPercentage) { + val2 = (val2 / sumNumber2) * 100; + val2 = Math.round(val2 * 100) / 100; + val2 = val2 + " %"; + } + + results.push({ + label: sumData[key].label, + value: val, + value2: val2, + color: colorList[index % colorList.length], + count: countNumber, + }); + } else { + results.push({ + label: sumData[key].label, + value: val, + color: colorList[index % colorList.length], + count: countNumber, + }); + } + + index += 1; + } + + const dcChart = this.getDCChart(); + + dcChart.clearAll(); + dcChart.parse(results); + } + + warningsEval() { + super.warningsEval(); + + let labelField = this.labelField(); + if (!labelField) { + this.warningsMessage( + `can't resolve label field[${this.settings.columnLabel}]` + ); + } + + let valueField = this.valueField(); + if (!valueField) { + this.warningsMessage( + `can't resolve value field[${this.settings.columnValue}]` + ); + } + } + }; +} diff --git a/AppBuilder/platform/plugins/included/view_chart/chart/FNAbviewchartComponent.js b/AppBuilder/platform/plugins/included/view_chart/chart/FNAbviewchartComponent.js new file mode 100644 index 00000000..2ba26898 --- /dev/null +++ b/AppBuilder/platform/plugins/included/view_chart/chart/FNAbviewchartComponent.js @@ -0,0 +1,79 @@ +export default function FNAbviewchartComponent({ + AB, + ABViewContainerComponent, +}) { + return class FNAbviewchartComponent extends ABViewContainerComponent { + constructor(baseView, idBase, ids) { + super(baseView, idBase || `ABViewChart_${baseView.id}`, ids); + } + + async init(ABParam, accessLevel) { + await super.init(ABParam, accessLevel); + + const $component = $$(this.ids.component); + const abWebix = AB.Webix; + + if ($component) abWebix.extend($component, abWebix.ProgressBar); + + const baseView = this.view; + const dc = baseView.datacollections || baseView.datacollection; + + const ensureDcLoaded = async (d) => { + if (!d || typeof d.init !== "function") return; + d.init(); + if (d.dataStatus === d.dataStatusFlag.notInitial) { + await d.loadData(); + } + }; + + if (Array.isArray(dc)) { + for (const d of dc) { + await ensureDcLoaded(d); + } + } else if (dc) { + await ensureDcLoaded(dc); + } + + if (dc) { + const eventNames = [ + "changeCursor", + "cursorStale", + "create", + "update", + "delete", + "initializedData", + ]; + + ["changeCursor", "cursorStale"].forEach((key) => { + if ( + dc.datacollectionLink && + !(key in (dc.datacollectionLink._events ?? [])) + ) + baseView.eventAdd({ + emitter: dc.datacollectionLink, + eventName: key, + listener: () => { + baseView.refreshData(); + }, + }); + }); + + eventNames.forEach((evtName) => { + baseView.eventAdd({ + emitter: dc, + eventName: evtName, + listener: () => { + baseView.refreshData(); + }, + }); + }); + } + + baseView.refreshData(); + } + + onShow() { + super.onShow(); + } + }; +} diff --git a/AppBuilder/platform/plugins/included/view_chart/chartBindings.js b/AppBuilder/platform/plugins/included/view_chart/chartBindings.js new file mode 100644 index 00000000..a8923451 --- /dev/null +++ b/AppBuilder/platform/plugins/included/view_chart/chartBindings.js @@ -0,0 +1,2 @@ +export { default as FNABViewChartCore } from "./core/ABViewChartCore.js"; +export { default as FNAbviewchartcontainerComponent } from "./core/FNAbviewchartcontainerComponent.js"; diff --git a/AppBuilder/platform/plugins/included/view_chart/core/ABViewChartCore.js b/AppBuilder/platform/plugins/included/view_chart/core/ABViewChartCore.js new file mode 100644 index 00000000..f2f9ea6e --- /dev/null +++ b/AppBuilder/platform/plugins/included/view_chart/core/ABViewChartCore.js @@ -0,0 +1,330 @@ +export default function FNABViewChartCore({ ABViewWidgetPlugin }) { + const ABViewChartPropertyComponentDefaults = { + dataviewID: "", + columnValue: "", + columnLabel: "", + columnValue2: "", + isPercentage: 1, + showLabel: 1, + labelPosition: "left", + labelWidth: 120, + height: 200, + multipleSeries: 0, + }; + + const ABViewChartDefaults = { + key: "chart", // {string} unique key for this view + icon: "bar-chart", // {string} fa-[icon] reference for this view + labelKey: "Chart", // {string} the multilingual label key for the class label + }; + + return class ABViewChartCore extends ABViewWidgetPlugin { + constructor(values, application, parent, defaultValues) { + super( + values, + application, + parent, + defaultValues || ABViewChartDefaults + ); + } + + get datacollection() { + return this.parent.datacollection; + } + + static getPluginType() { + return "view"; + } + + static common() { + return ABViewChartDefaults; + } + + static defaultValues() { + return ABViewChartPropertyComponentDefaults; + } + + /// + /// Instance Methods + /// + + /** + * @method fromValues() + * + * initialze this object with the given set of values. + * @param {obj} values + */ + fromValues(values) { + super.fromValues(values); + + this.settings.dataviewID = + this.settings.dataviewID ?? + ABViewChartPropertyComponentDefaults.dataviewID; + + this.settings.columnValue = + this.settings.columnValue ?? + ABViewChartPropertyComponentDefaults.columnValue; + + this.settings.columnLabel = + this.settings.columnLabel ?? + ABViewChartPropertyComponentDefaults.columnLabel; + + this.settings.columnValue2 = + this.settings.columnValue2 ?? + ABViewChartPropertyComponentDefaults.columnValue2; + + this.settings.isPercentage = parseInt( + this.settings.isPercentage ?? + ABViewChartPropertyComponentDefaults.isPercentage + ); + + this.settings.showLabel = parseInt( + this.settings.showLabel ?? + ABViewChartPropertyComponentDefaults.showLabel + ); + + this.settings.labelPosition = + this.settings.labelPosition || + ABViewChartPropertyComponentDefaults.labelPosition; + + this.settings.labelWidth = parseInt( + this.settings.labelWidth ?? + ABViewChartPropertyComponentDefaults.labelWidth + ); + + this.settings.height = parseInt( + this.settings.height ?? ABViewChartPropertyComponentDefaults.height + ); + + this.settings.multipleSeries = parseInt( + this.settings.multipleSeries ?? + ABViewChartPropertyComponentDefaults.multipleSeries + ); + + this.translate(this, this, ["chartLabel"]); + + this.refreshData(); + } + + getDCChart() { + if (!this._dcChart) this._dcChart = new webix.DataCollection(); + + return this._dcChart; + } + + refreshData() { + const dc = this.datacollection; + if (dc == null) return this.getDCChart(); + + const labelCol = this.labelField(); + const valueCol = this.valueField(); + const valueCol2 = this.valueField2(); + + if (!labelCol || !valueCol) return this.getDCChart(); + + const numberColName = valueCol.columnName; + + let numberColName2 = ""; + + if (this.settings.multipleSeries && valueCol2) { + numberColName2 = valueCol2.columnName; + } + + const colorList = [ + "#ee4339", + "#ee9336", + "#eed236", + "#d3ee36", + "#a7ee70", + "#58dccd", + "#36abee", + "#476cee", + "#a244ea", + "#e33fc7", + ]; + + const dInfo = dc.getData(); + + let results = []; + let sumData = {}; + let sumNumber = 0; + let sumNumber2 = 0; + let countNumber = dInfo.length; + + dInfo.forEach((item) => { + const labelKey = labelCol.format(item) || item.id; + + let numberVal = parseFloat(item[numberColName] || 0); + let numberVal2 = null; + + if (this.settings.multipleSeries) + numberVal2 = parseFloat(item[numberColName2]) || 0; + + switch (valueCol.key) { + case "formula": + numberVal = valueCol.format(item); + + break; + + case "calculate": + numberVal = parseFloat( + valueCol.constructor.convertToJs( + valueCol.object, + valueCol.settings.formula, + item, + valueCol.settings.decimalPlaces + ) + ); + + break; + + default: + break; + } + + if (sumData[labelKey] == null) { + let label = labelKey; + + if (labelCol.isConnection) { + let relateValues = labelCol.pullRelationValues(item); + if (relateValues != null) { + if (Array.isArray(relateValues)) + label = relateValues + .map((val) => val.text || "") + .join(", "); + else label = relateValues.text; + } + } + + if (this.settings.multipleSeries) { + sumData[labelKey] = { + label: label || item.id, + value: 0, + value2: 0, + }; + } else { + sumData[labelKey] = { + label: label || item.id, + value: 0, + }; + } + } + + sumData[labelKey].value += numberVal; + sumNumber += numberVal; + + if (this.settings.multipleSeries) { + sumData[labelKey].value2 += numberVal2; + sumNumber2 += numberVal2; + } + }); + + let index = 0; + + for (const key in sumData) { + let val = sumData[key].value; + + if (val <= 0) continue; + + if (this.settings.isPercentage) { + val = (val / sumNumber) * 100; + val = Math.round(val * 100) / 100; + val = val + " %"; + } + + if (this.settings.multipleSeries) { + let val2 = sumData[key].value2; + + if (val2 <= 0) continue; + + if (this.settings.isPercentage) { + val2 = (val2 / sumNumber2) * 100; + val2 = Math.round(val2 * 100) / 100; + val2 = val2 + " %"; + } + + results.push({ + label: sumData[key].label, + value: val, + value2: val2, + color: colorList[index % colorList.length], + count: countNumber, + }); + } else { + results.push({ + label: sumData[key].label, + value: val, + color: colorList[index % colorList.length], + count: countNumber, + }); + } + + index += 1; + } + + const dcChart = this.getDCChart(); + + dcChart.clearAll(); + dcChart.parse(results); + } + + warningsEval() { + super.warningsEval(); + + let labelField = this.labelField(); + if (!labelField) { + this.warningsMessage( + `can't resolve label field[${this.settings.columnLabel}]` + ); + } + + let valueField = this.valueField(); + if (!valueField) { + this.warningsMessage( + `can't resolve value field[${this.settings.columnValue}]` + ); + } + } + + /** + * @method componentList + * return the list of components available on this view to display in the editor. + */ + componentList() { + const viewsToAllow = ["label", "pie", "bar", "line", "area"]; + return this.application.viewAll((c) => { + return viewsToAllow.indexOf(c.common().key) > -1; + }); + } + + labelField() { + const dc = this.datacollection; + if (!dc) return null; + + const obj = dc.datasource; + if (!obj) return null; + + return obj.fieldByID(this.settings.columnLabel); + } + + valueField() { + const dc = this.datacollection; + if (!dc) return null; + + const obj = dc.datasource; + if (!obj) return null; + + return obj.fieldByID(this.settings.columnValue); + } + + valueField2() { + const dc = this.datacollection; + if (!dc) return null; + + const obj = dc.datasource; + if (!obj) return null; + + return obj.fieldByID(this.settings.columnValue2); + } + }; +} diff --git a/AppBuilder/platform/plugins/included/view_chart/core/FNAbviewchartcontainerComponent.js b/AppBuilder/platform/plugins/included/view_chart/core/FNAbviewchartcontainerComponent.js new file mode 100644 index 00000000..acfce236 --- /dev/null +++ b/AppBuilder/platform/plugins/included/view_chart/core/FNAbviewchartcontainerComponent.js @@ -0,0 +1,80 @@ +function findAncestorWithGetDCChart(view) { + let cur = view && view.parent; + while (cur) { + if (typeof cur.getDCChart === "function") return cur; + cur = cur.parent; + } + return null; +} + +export default function FNAbviewchartcontainerComponent({ + ABViewComponentPlugin, +}) { + return class ABviewchartcontainerComponent extends ABViewComponentPlugin { + constructor(baseView, idBase, ids) { + super( + baseView, + idBase || `ABViewChartContainer_${baseView.id}`, + Object.assign( + { + chartContainer: "", + }, + ids + ) + ); + } + + ui(uiChartComponent) { + const _ui = super.ui([ + Object.assign( + { id: this.ids.chartContainer }, + uiChartComponent ?? {} + ), + ]); + + delete _ui.type; + + return _ui; + } + + async init(AB) { + await super.init(AB); + } + + onShow() { + super.onShow(); + const baseView = this.view; + + baseView._isShow = true; + + const chartAncestor = findAncestorWithGetDCChart(baseView); + let dcChart = null; + if (chartAncestor) { + if (typeof chartAncestor.refreshData === "function") { + chartAncestor.refreshData(); + } + dcChart = chartAncestor.getDCChart(); + } else if (typeof baseView.getDCChart === "function") { + if (typeof baseView.refreshData === "function") { + baseView.refreshData(); + } + dcChart = baseView.getDCChart(); + } + this.refreshData(dcChart); + } + + refreshData(dcChart) { + const $chartContainer = $$(this.ids.chartContainer); + const $chartComponent = $$(this.ids.component); + + if (dcChart && $chartContainer?.data) { + $chartContainer.data.sync(dcChart); + } + + setTimeout(() => { + $chartComponent?.adjust(); + $chartContainer?.adjust(); + }, 160); + } + }; +} diff --git a/AppBuilder/platform/plugins/included/view_chart/line/FNAbviewchartline.js b/AppBuilder/platform/plugins/included/view_chart/line/FNAbviewchartline.js new file mode 100644 index 00000000..40c3f5b6 --- /dev/null +++ b/AppBuilder/platform/plugins/included/view_chart/line/FNAbviewchartline.js @@ -0,0 +1,127 @@ +import { FNABViewChartCore } from "../chartBindings.js"; +import FNAbviewchartlineComponent from "./FNAbviewchartlineComponent.js"; + +// FNAbviewchartline Web +// A web side import for an ABView. +// +export default function FNAbviewchartline({ + ABViewComponentPlugin, + ABViewWidgetPlugin, +}) { + const ABViewChartCore = FNABViewChartCore({ ABViewWidgetPlugin }); + + const ABAbviewchartlineComponent = FNAbviewchartlineComponent({ + ABViewComponentPlugin, + }); + + const ABViewChartLinePropertyComponentDefaults = { + lineType: "line", + linePreset: "plot", + isLegend: 1, + // chartWidth: 600, + chartHeight: 200, + labelFontSize: 12, + stepValue: 20, + maxValue: 100, + }; + + const ABViewDefaults = { + key: "line", // {string} unique key for this view + icon: "line-chart", // {string} fa-[icon] reference for this view + labelKey: "Line", // {string} the multilingual label key for the class label + }; + + class ABViewChartLineCore extends ABViewChartCore { + constructor(values, application, parent, defaultValues) { + super(values, application, parent, defaultValues || ABViewDefaults); + } + + static common() { + return ABViewDefaults; + } + + static defaultValues() { + return ABViewChartLinePropertyComponentDefaults; + } + + /// + /// Instance Methods + /// + + /** + * @method fromValues() + * + * initialze this object with the given set of values. + * @param {obj} values + */ + fromValues(values) { + super.fromValues(values); + + this.settings.lineType = + this.settings.lineType || + ABViewChartLinePropertyComponentDefaults.lineType; + + this.settings.linePreset = + this.settings.linePreset || + ABViewChartLinePropertyComponentDefaults.linePreset; + + this.settings.isLegend = parseInt( + this.settings.isLegend ?? + ABViewChartLinePropertyComponentDefaults.isLegend + ); + + // this.settings.chartWidth = parseInt(this.settings.chartWidth || ABViewChartLinePropertyComponentDefaults.chartWidth); + this.settings.chartHeight = parseInt( + this.settings.chartHeight ?? + ABViewChartLinePropertyComponentDefaults.chartHeight + ); + + this.settings.labelFontSize = parseInt( + this.settings.labelFontSize ?? + ABViewChartLinePropertyComponentDefaults.labelFontSize + ); + this.settings.stepValue = parseInt( + this.settings.stepValue ?? + ABViewChartLinePropertyComponentDefaults.stepValue + ); + this.settings.maxValue = parseInt( + this.settings.maxValue ?? + ABViewChartLinePropertyComponentDefaults.maxValue + ); + + this.translate(this, this, ["lineLabel"]); + } + + /** + * @method componentList + * return the list of components available on this view to display in the editor. + */ + componentList() { + return []; + } + } + + return class ABViewChartLine extends ABViewChartLineCore { + /** + * @method getPluginKey + * return the plugin key for this view. + * @return {string} plugin key + */ + static getPluginKey() { + return this.common().key; + } + + /** + * @method component() + * return a UI component based upon this view. + * @return {obj} UI component + */ + component() { + return new ABAbviewchartlineComponent(this); + } + + // constructor(values, application, parent, defaultValues) { + // super(values, application, parent, defaultValues); + // } + }; +} diff --git a/AppBuilder/platform/plugins/included/view_chart/line/FNAbviewchartlineComponent.js b/AppBuilder/platform/plugins/included/view_chart/line/FNAbviewchartlineComponent.js new file mode 100644 index 00000000..7138072f --- /dev/null +++ b/AppBuilder/platform/plugins/included/view_chart/line/FNAbviewchartlineComponent.js @@ -0,0 +1,46 @@ +import { FNAbviewchartcontainerComponent } from "../chartBindings.js"; + +export default function FNAbviewchartlineComponent({ + /*AB,*/ + ABViewComponentPlugin, +}) { + const ChartContainerComponent = FNAbviewchartcontainerComponent({ + ABViewComponentPlugin, + }); + + return class FNAbviewchartlineComponent extends ChartContainerComponent { + constructor(baseView, idBase, ids) { + super(baseView, idBase || `ABViewChartLine_${baseView.id}`, ids); + } + + ui() { + const settings = this.settings; + + return super.ui({ + view: "chart", + type: settings.lineType, + preset: settings.linePreset, + value: "#value#", + color: "#color#", + yAxis: { + start: 0, + step: settings.stepValue, + end: settings.maxValue, //"#maxValue#" + }, + xAxis: { + template: settings.isLegend + ? `
#label#
` + : "", + }, + legend: settings.isLegend + ? { + template: `
#label#
`, + values: [], // TODO : bug in webix 5.1.7 + } + : null, + height: settings.chartHeight, + // width: settings.chartWidth, + }); + } + }; +} diff --git a/AppBuilder/platform/plugins/included/view_chart/pie/FNAbviewchartpie.js b/AppBuilder/platform/plugins/included/view_chart/pie/FNAbviewchartpie.js new file mode 100644 index 00000000..015d1e7d --- /dev/null +++ b/AppBuilder/platform/plugins/included/view_chart/pie/FNAbviewchartpie.js @@ -0,0 +1,119 @@ +import { FNABViewChartCore } from "../chartBindings.js"; +import FNAbviewchartpieComponent from "./FNAbviewchartpieComponent.js"; + +// FNAbviewchartpie Web +// A web side import for an ABView. +// +export default function FNAbviewchartpie({ + /*AB,*/ + ABViewPlugin, + ABViewComponentPlugin, + ABViewContainer, + ABViewWidgetPlugin, +}) { + const ABViewChartCore = FNABViewChartCore({ ABViewWidgetPlugin }); + const ABAbviewchartpieComponent = FNAbviewchartpieComponent({ + ABViewComponentPlugin, + }); + + const ABViewChartPiePropertyComponentDefaults = { + pieType: "pie", + isLegend: 1, + // chartWidth: 600, + height: 200, + innerFontSize: 12, + labelFontSize: 12, + }; + + const ABViewDefaults = { + key: "pie", // {string} unique key for this view + icon: "pie-chart", // {string} fa-[icon] reference for this view + labelKey: "Pie", // {string} the multilingual label key for the class label + }; + + class ABViewChartPieCore extends ABViewChartCore { + constructor(values, application, parent, defaultValues) { + super(values, application, parent, defaultValues || ABViewDefaults); + } + + static common() { + return ABViewDefaults; + } + + static defaultValues() { + return ABViewChartPiePropertyComponentDefaults; + } + + /// + /// Instance Methods + /// + + /** + * @method fromValues() + * + * initialze this object with the given set of values. + * @param {obj} values + */ + fromValues(values) { + super.fromValues(values); + + this.settings.pieType = + this.settings.pieType || + ABViewChartPiePropertyComponentDefaults.pieType; + + this.settings.isLegend = parseInt( + this.settings.isLegend ?? + ABViewChartPiePropertyComponentDefaults.isLegend + ); + + // this.settings.chartWidth = parseInt(this.settings.chartWidth || ABViewChartPiePropertyComponentDefaults.chartWidth); + this.settings.height = parseInt( + this.settings.height ?? + ABViewChartPiePropertyComponentDefaults.height + ); + + this.settings.innerFontSize = parseInt( + this.settings.innerFontSize ?? + ABViewChartPiePropertyComponentDefaults.innerFontSize + ); + this.settings.labelFontSize = parseInt( + this.settings.labelFontSize ?? + ABViewChartPiePropertyComponentDefaults.labelFontSize + ); + + this.translate(this, this, ["pieLabel"]); + } + + /** + * @method componentList + * return the list of components available on this view to display in the editor. + */ + componentList() { + return []; + } + } + + return class ABViewChartPie extends ABViewChartPieCore { + /** + * @method getPluginKey + * return the plugin key for this view. + * @return {string} plugin key + */ + static getPluginKey() { + return this.common().key; + } + + /** + * @method component() + * return a UI component based upon this view. + * @return {obj} UI component + */ + component() { + return new ABAbviewchartpieComponent(this); + } + + // constructor(values, application, parent, defaultValues) { + // super(values, application, parent, defaultValues); + // } + }; +} diff --git a/AppBuilder/platform/plugins/included/view_chart/pie/FNAbviewchartpieComponent.js b/AppBuilder/platform/plugins/included/view_chart/pie/FNAbviewchartpieComponent.js new file mode 100644 index 00000000..3fab2cc3 --- /dev/null +++ b/AppBuilder/platform/plugins/included/view_chart/pie/FNAbviewchartpieComponent.js @@ -0,0 +1,37 @@ +import { FNAbviewchartcontainerComponent } from "../chartBindings.js"; + +export default function FNAbviewchartpieComponent({ + /*AB,*/ + ABViewComponentPlugin, +}) { + const ChartContainerComponent = FNAbviewchartcontainerComponent({ + ABViewComponentPlugin, + }); + + return class FNAbviewchartpieComponent extends ChartContainerComponent { + constructor(baseView, idBase, ids) { + super(baseView, idBase || `ABViewChartPie_${baseView.id}`, ids); + } + + ui() { + const settings = this.settings; + + return super.ui({ + view: "chart", + type: settings.pieType, + value: "#value#", + color: "#color#", + legend: settings.isLegend + ? { + width: this.view.parent.settings.labelWidth, + template: `
#label#
`, + } + : null, + pieInnerText: `
#value#
`, + shadow: 1, + height: settings.height, + // width: settings.chartWidth, + }); + } + }; +} diff --git a/AppBuilder/platform/views/ABViewChart.js b/AppBuilder/platform/views/ABViewChart.js deleted file mode 100644 index 1a5df44c..00000000 --- a/AppBuilder/platform/views/ABViewChart.js +++ /dev/null @@ -1,214 +0,0 @@ -const ABViewChartCore = require("../../core/views/ABViewChartCore"); -const ABViewChartComponent = require("./viewComponent/ABViewChartComponent"); - -module.exports = class ABViewChart extends ABViewChartCore { - // constructor(values, application, parent, defaultValues) { - // super(values, application, parent, defaultValues); - // } - - /** - * @method component() - * return a UI component based upon this view. - * @param {obj} App - * @return {obj} UI component - */ - /** - * @method component() - * return a UI component based upon this view. - * @return {obj} UI component - */ - component() { - return new ABViewChartComponent(this); - } - - fromValues(values) { - super.fromValues(values); - this.refreshData(); - } - - getDCChart() { - if (!this._dcChart) this._dcChart = new webix.DataCollection(); - - return this._dcChart; - } - - refreshData() { - const dc = this.datacollection; - if (dc == null) return this.dcChart; - - const labelCol = this.labelField(); - const valueCol = this.valueField(); - const valueCol2 = this.valueField2(); - - if (!labelCol || !valueCol) return this.dcChart; - - // const labelColName = labelCol.columnName; - const numberColName = valueCol.columnName; - - let numberColName2 = ""; - - if (this.settings.multipleSeries && valueCol2) { - numberColName2 = valueCol2.columnName; - } - - const colorList = [ - "#ee4339", - "#ee9336", - "#eed236", - "#d3ee36", - "#a7ee70", - "#58dccd", - "#36abee", - "#476cee", - "#a244ea", - "#e33fc7", - ]; - - const dInfo = dc.getData(); - - let results = []; - let sumData = {}; - let sumNumber = 0; - let sumNumber2 = 0; - let countNumber = dInfo.length; - - dInfo.forEach((item) => { - const labelKey = labelCol.format(item) || item.id; - - let numberVal = parseFloat(item[numberColName] || 0); - let numberVal2 = null; - - if (this.settings.multipleSeries) - numberVal2 = parseFloat(item[numberColName2]) || 0; - - switch (valueCol.key) { - //Formula Datatype - case "formula": - numberVal = valueCol.format(item); - - break; - - //Calcualte Datatype - case "calculate": - numberVal = parseFloat( - valueCol.constructor.convertToJs( - valueCol.object, - valueCol.settings.formula, - item, - valueCol.settings.decimalPlaces - ) - ); - - break; - - default: - break; - } - - if (sumData[labelKey] == null) { - let label = labelKey; - - // Get label of the connect field - if (labelCol.isConnection) { - let relateValues = labelCol.pullRelationValues(item); - if (relateValues != null) { - if (Array.isArray(relateValues)) - label = relateValues - .map((val) => val.text || "") - .join(", "); - else label = relateValues.text; - } - } - - if (this.settings.multipleSeries) { - sumData[labelKey] = { - label: label || item.id, - value: 0, - value2: 0, - }; - } else { - sumData[labelKey] = { - label: label || item.id, - value: 0, - }; - } - } - - sumData[labelKey].value += numberVal; - sumNumber += numberVal; - - if (this.settings.multipleSeries) { - sumData[labelKey].value2 += numberVal2; - sumNumber2 += numberVal2; - } - }); - - let index = 0; - - for (const key in sumData) { - let val = sumData[key].value; - - if (val <= 0) continue; - - // Display to percent values - if (this.settings.isPercentage) { - val = (val / sumNumber) * 100; - val = Math.round(val * 100) / 100; // round decimal 2 digits - val = val + " %"; - } - - if (this.settings.multipleSeries) { - let val2 = sumData[key].value2; - - if (val2 <= 0) continue; - - // Display to percent values - if (this.settings.isPercentage) { - val2 = (val2 / sumNumber2) * 100; - val2 = Math.round(val2 * 100) / 100; // round decimal 2 digits - val2 = val2 + " %"; - } - - results.push({ - label: sumData[key].label, - value: val, - value2: val2, - color: colorList[index % colorList.length], - count: countNumber, - }); - } else { - results.push({ - label: sumData[key].label, - value: val, - color: colorList[index % colorList.length], - count: countNumber, - }); - } - - index += 1; - } - - const dcChart = this.getDCChart(); - - dcChart.clearAll(); - dcChart.parse(results); - } - - warningsEval() { - super.warningsEval(); - - let labelField = this.labelField(); - if (!labelField) { - this.warningsMessage( - `can't resolve label field[${this.settings.columnLabel}]` - ); - } - - let valueField = this.valueField(); - if (!valueField) { - this.warningsMessage( - `can't resolve value field[${this.settings.columnValue}]` - ); - } - } -}; diff --git a/AppBuilder/platform/views/ABViewChartArea.js b/AppBuilder/platform/views/ABViewChartArea.js deleted file mode 100644 index 5c6676db..00000000 --- a/AppBuilder/platform/views/ABViewChartArea.js +++ /dev/null @@ -1,17 +0,0 @@ -const ABViewChartAreaCore = require("../../core/views/ABViewChartAreaCore"); -const ABViewChartAreaComponent = require("./viewComponent/ABViewChartAreaComponent"); - -module.exports = class ABViewChartArea extends ABViewChartAreaCore { - // constructor(values, application, parent, defaultValues) { - // super(values, application, parent, defaultValues); - // } - - /** - * @method component() - * return a UI component based upon this view. - * @return {obj} UI component - */ - component() { - return new ABViewChartAreaComponent(this); - } -}; diff --git a/AppBuilder/platform/views/ABViewChartBar.js b/AppBuilder/platform/views/ABViewChartBar.js deleted file mode 100644 index c4f57d6b..00000000 --- a/AppBuilder/platform/views/ABViewChartBar.js +++ /dev/null @@ -1,17 +0,0 @@ -const ABViewChartBarCore = require("../../core/views/ABViewChartBarCore"); -const ABViewChartBarComponent = require("./viewComponent/ABViewChartBarComponent"); - -module.exports = class ABViewChartBar extends ABViewChartBarCore { - // constructor(values, application, parent, defaultValues) { - // super(values, application, parent, defaultValues); - // } - - /** - * @method component() - * return a UI component based upon this view. - * @return {obj} UI component - */ - component() { - return new ABViewChartBarComponent(this); - } -}; diff --git a/AppBuilder/platform/views/ABViewChartContainer.js b/AppBuilder/platform/views/ABViewChartContainer.js deleted file mode 100644 index bc7a625b..00000000 --- a/AppBuilder/platform/views/ABViewChartContainer.js +++ /dev/null @@ -1,17 +0,0 @@ -const ABViewWidget = require("./ABViewWidget"); -const ABViewChartContainerComponent = require("./viewComponent/ABViewChartContainerComponent"); - -module.exports = class ABViewChartContainer extends ABViewWidget { - /** - * @method component() - * return a UI component based upon this view. - * @return {obj} UI component - */ - component() { - return new ABViewChartContainerComponent(this); - } - - get datacollection() { - return this.parent.datacollection; - } -}; diff --git a/AppBuilder/platform/views/ABViewChartLine.js b/AppBuilder/platform/views/ABViewChartLine.js deleted file mode 100644 index 2933684a..00000000 --- a/AppBuilder/platform/views/ABViewChartLine.js +++ /dev/null @@ -1,17 +0,0 @@ -const ABViewChartLineCore = require("../../core/views/ABViewChartLineCore"); -const ABViewChartLineComponent = require("./viewComponent/ABViewChartLineComponent"); - -module.exports = class ABViewChartLine extends ABViewChartLineCore { - // constructor(values, application, parent, defaultValues) { - // super(values, application, parent, defaultValues); - // } - - /** - * @method component() - * return a UI component based upon this view. - * @return {obj} UI component - */ - component() { - return new ABViewChartLineComponent(this); - } -}; diff --git a/AppBuilder/platform/views/ABViewChartPie.js b/AppBuilder/platform/views/ABViewChartPie.js deleted file mode 100644 index 4ac5511f..00000000 --- a/AppBuilder/platform/views/ABViewChartPie.js +++ /dev/null @@ -1,17 +0,0 @@ -const ABViewChartPieCore = require("../../core/views/ABViewChartPieCore"); -const ABViewChartPieComponent = require("./viewComponent/ABViewChartPieComponent"); - -module.exports = class ABViewChartPie extends ABViewChartPieCore { - // constructor(values, application, parent, defaultValues) { - // super(values, application, parent, defaultValues); - // } - - /** - * @method component() - * return a UI component based upon this view. - * @return {obj} UI component - */ - component() { - return new ABViewChartPieComponent(this); - } -}; diff --git a/AppBuilder/platform/views/viewComponent/ABViewChartAreaComponent.js b/AppBuilder/platform/views/viewComponent/ABViewChartAreaComponent.js deleted file mode 100644 index 8c79fefa..00000000 --- a/AppBuilder/platform/views/viewComponent/ABViewChartAreaComponent.js +++ /dev/null @@ -1,56 +0,0 @@ -const ABViewChartContainerComponent = require("./ABViewChartContainerComponent"); - -module.exports = class ABViewChartAreaComponent extends ( - ABViewChartContainerComponent -) { - constructor(baseView, idBase, ids) { - super(baseView, idBase || `ABViewChartArea_${baseView.id}`, ids); - } - - ui() { - const settings = this.settings; - - return super.ui({ - view: "chart", - type: settings.areaType, - yAxis: { - start: 0, - step: settings.stepValue, //"#stepValue#", - end: settings.maxValue, //"#maxValue#" - }, - xAxis: { - template: settings.isLegend - ? `
#label#
` - : "", - }, - legend: settings.isLegend - ? { - template: `
#label#
`, - values: [], // TODO : bug in webix 5.1.7 - } - : null, - series: [ - { - alpha: 0.7, - value: "#value#", - color: "#ee4339", - }, - { - alpha: 0.4, - value: "#value2#", - color: "#a7ee70", - }, - ], - height: settings.chartHeight, - // width: settings.chartWidth, - }); - } - - async init(AB) { - await super.init(AB); - } - - onShow() { - super.onShow(); - } -}; diff --git a/AppBuilder/platform/views/viewComponent/ABViewChartBarComponent.js b/AppBuilder/platform/views/viewComponent/ABViewChartBarComponent.js deleted file mode 100644 index 767b59ab..00000000 --- a/AppBuilder/platform/views/viewComponent/ABViewChartBarComponent.js +++ /dev/null @@ -1,52 +0,0 @@ -const ABViewChartContainerComponent = require("./ABViewChartContainerComponent"); - -module.exports = class ABViewChartBarComponent extends ( - ABViewChartContainerComponent -) { - constructor(baseView, idBase, ids) { - super(baseView, idBase || `ABViewChartBar_${baseView.id}`, ids); - } - - ui() { - const settings = this.settings; - - return super.ui({ - view: "chart", - type: settings.barType, - preset: settings.barPreset, - value: "#value#", - color: "#color#", - yAxis: { - start: 0, - step: settings.stepValue, //"#stepValue#", - end: settings.maxValue, //"#maxValue#" - }, - xAxis: { - template: settings.isLegend - ? `
#label#
` - : "", - }, - legend: - settings.barType === "bar" || !settings.barType - ? settings.isLegend - ? `
#label#
` - : "" - : settings.isLegend - ? { - template: `
#label#
`, - values: [], // TODO : bug in webix 5.1.7 - } - : null, - height: settings.height, - // width: settings.chartWidth, - }); - } - - async init(AB) { - await super.init(AB); - } - - onShow() { - super.onShow(); - } -}; diff --git a/AppBuilder/platform/views/viewComponent/ABViewChartComponent.js b/AppBuilder/platform/views/viewComponent/ABViewChartComponent.js deleted file mode 100644 index ce59c0d4..00000000 --- a/AppBuilder/platform/views/viewComponent/ABViewChartComponent.js +++ /dev/null @@ -1,62 +0,0 @@ -const ABViewContainerComponent = require("./ABViewContainerComponent"); - -module.exports = class ABViewChartComponent extends ABViewContainerComponent { - constructor(baseView, idBase, ids) { - super(baseView, idBase || `ABViewChart_${baseView.id}`, ids); - } - - async init(AB, accessLevel) { - await super.init(AB, accessLevel); - - const $component = $$(this.ids.component); - const abWebix = this.AB.Webix; - - if ($component) abWebix.extend($component, abWebix.ProgressBar); - - const baseView = this.view; - const dc = this.datacollection; - - if (dc) { - const eventNames = [ - "changeCursor", - "cursorStale", - "create", - "update", - "delete", - "initializedData", - ]; - - ["changeCursor", "cursorStale"].forEach((key) => { - // QUESTION: is this a problem if the check !(key in (...)) finds - // an event that some OTHER widget has added and not this one? - if ( - dc.datacollectionLink && - !(key in (dc.datacollectionLink._events ?? [])) - ) - baseView.eventAdd({ - emitter: dc.datacollectionLink, - eventName: key, - listener: () => { - baseView.refreshData(); - }, - }); - }); - - eventNames.forEach((evtName) => { - baseView.eventAdd({ - emitter: dc, - eventName: evtName, - listener: () => { - baseView.refreshData(); - }, - }); - }); - } - - baseView.refreshData(); - } - - onShow() { - super.onShow(); - } -}; diff --git a/AppBuilder/platform/views/viewComponent/ABViewChartContainerComponent.js b/AppBuilder/platform/views/viewComponent/ABViewChartContainerComponent.js deleted file mode 100644 index 4f23324e..00000000 --- a/AppBuilder/platform/views/viewComponent/ABViewChartContainerComponent.js +++ /dev/null @@ -1,55 +0,0 @@ -const ABViewComponent = require("./ABViewComponent").default; - -module.exports = class ABViewChartContainerComponent extends ABViewComponent { - constructor(baseView, idBase, ids) { - super( - baseView, - idBase || `ABViewChartContainer_${baseView.id}`, - Object.assign( - { - chartContainer: "", - }, - ids - ) - ); - } - - ui(uiChartComponent) { - const _ui = super.ui([ - Object.assign({ id: this.ids.chartContainer }, uiChartComponent ?? {}), - ]); - - delete _ui.type; - - return _ui; - } - - async init(AB) { - await super.init(AB); - } - - onShow() { - super.onShow(); - // if (!this._isShow) { - - // Mark this widget is showing - const baseView = this.view; - - baseView._isShow = true; - - this.refreshData(baseView.parent.getDCChart()); - // } - } - - refreshData(dcChart) { - const $chartContainer = $$(this.ids.chartContainer); - const $chartComponent = $$(this.ids.component); - - if ($chartContainer?.data) $chartContainer.data.sync(dcChart); - - setTimeout(() => { - $chartComponent?.adjust(); - $chartContainer?.adjust(); - }, 160); - } -}; diff --git a/AppBuilder/platform/views/viewComponent/ABViewChartLineComponent.js b/AppBuilder/platform/views/viewComponent/ABViewChartLineComponent.js deleted file mode 100644 index f5052ea0..00000000 --- a/AppBuilder/platform/views/viewComponent/ABViewChartLineComponent.js +++ /dev/null @@ -1,39 +0,0 @@ -const ABViewChartContainerComponent = require("./ABViewChartContainerComponent"); - -module.exports = class ABViewChartLineComponent extends ( - ABViewChartContainerComponent -) { - constructor(baseView, idBase, ids) { - super(baseView, idBase || `ABViewChartLine_${baseView.id}`, ids); - } - - ui() { - const settings = this.settings; - - return super.ui({ - view: "chart", - type: settings.lineType, - preset: settings.linePreset, - value: "#value#", - color: "#color#", - yAxis: { - start: 0, - step: settings.stepValue, - end: settings.maxValue, //"#maxValue#" - }, - xAxis: { - template: settings.isLegend - ? `
#label#
` - : "", - }, - legend: settings.isLegend - ? { - template: `
#label#
`, - values: [], // TODO : bug in webix 5.1.7 - } - : null, - height: settings.chartHeight, - // width: settings.chartWidth, - }); - } -}; diff --git a/AppBuilder/platform/views/viewComponent/ABViewChartPieComponent.js b/AppBuilder/platform/views/viewComponent/ABViewChartPieComponent.js deleted file mode 100644 index 0060f439..00000000 --- a/AppBuilder/platform/views/viewComponent/ABViewChartPieComponent.js +++ /dev/null @@ -1,30 +0,0 @@ -const ABViewChartContainerComponent = require("./ABViewChartContainerComponent"); - -module.exports = class ABViewChartPieComponent extends ( - ABViewChartContainerComponent -) { - constructor(baseView, idBase, ids) { - super(baseView, idBase || `ABViewChartPie_${baseView.id}`, ids); - } - - ui() { - const settings = this.settings; - - return super.ui({ - view: "chart", - type: settings.pieType, - value: "#value#", - color: "#color#", - legend: settings.isLegend - ? { - width: this.view.parent.settings.labelWidth, - template: `
#label#
`, - } - : null, - pieInnerText: `
#value#
`, - shadow: 1, - height: settings.height, - // width: settings.chartWidth, - }); - } -}; diff --git a/test/_setup.js b/test/_setup.js index ed53c8e1..6ecb2168 100644 --- a/test/_setup.js +++ b/test/_setup.js @@ -9,9 +9,12 @@ global.window = dom.window; global.document = dom.window.document; global.FileReader = global.window.FileReader; global.Blob = global.window.Blob; -global.navigator = { - userAgent: "node.js", -}; +Object.defineProperty(global, "navigator", { + value: dom.window.navigator, + writable: true, + configurable: true, + enumerable: true, +}); // Set webix globally global.$$ = webixElement;