<commit_before>import crossfilter from "crossfilter2";
import { max, mean, median, sum } from "d3-array";
import { scaleThreshold } from "d3-scale";
import { money } from "lib/shared";
import {
  AmountDistributionBars,
  GroupPctDistributionBars
} from "lib/visualizations";
import Vue from "vue";
import VueRouter from "vue-router";
import { getRemoteData, sortByField, calculateSumMeanMedian } from "../webapp/lib/utils";
import { EventBus } from "../webapp/mixins/event_bus";

const d3 = { scaleThreshold, sum, mean, median, max };

Vue.use(VueRouter);
Vue.config.productionTip = false;

export class SubsidiesController {
  constructor(options) {
    this.charts = {};

    const selector = "gobierto-visualizations-subsidies-app";

    // Mount Vue applications
    const entryPoint = document.getElementById(selector);

    if (entryPoint) {
      const htmlRouterBlock = `<router-view></router-view>`;

      entryPoint.innerHTML = htmlRouterBlock;

      const Home = () => import("../webapp/containers/subsidies/Home.vue");
      const Summary = () =>
        import("../webapp/containers/subsidies/Summary.vue");
      const SubsidiesIndex = () =>
        import("../webapp/containers/subsidies/SubsidiesIndex.vue");
      const SubsidiesShow = () =>
        import("../webapp/containers/subsidies/SubsidiesShow.vue");

      Promise.all([getRemoteData(options.subsidiesEndpoint)]).then(rawData => {
        this.setGlobalVariables(rawData);

        const router = new VueRouter({
          mode: "history",
          routes: [
            {
              path: "/visualizaciones/subvenciones",
              component: Home,
              props: { dataDownloadEndpoint: options.dataDownloadEndpoint },
              children: [
                { path: "", name: "summary", component: Summary },
                {
                  path: "subvenciones",
                  name: "subsidies_index",
                  component: SubsidiesIndex
                },
                {
                  path: "subvenciones/:id",
                  name: "subsidies_show",
                  component: SubsidiesShow
                }
              ]
            }
          ]
        });

        const baseTitle = document.title;
        router.afterEach(to => {
          // Wait 2 ticks
          Vue.nextTick(() =>
            Vue.nextTick(() => {
              let title = baseTitle;

              if (to.name === "subsidies_show") {
                const { item: { title: itemTitle } = {} } = to.params;

                if (itemTitle) {
                  title = `${itemTitle}${baseTitle}`;
                }
              }

              document.title = title;
            })
          );
        });

        this.vueApp = new Vue({
          router,
          data: Object.assign(options, this.data)
        }).$mount(entryPoint);

        EventBus.$on("summary-ready", () => {
          this._renderSummary();
        });

        EventBus.$on("filter-changed", options => {
          this._updateChartsFromFilter(options);
        });

        // - dc charts are drawn even if the summary page is not the page where the user lands for the first time
        //   i.e.: they could first land on a subsidy page, but still this page would need to render for the filters to work
        // - dc charts sizes are calculated automatically, but if the page is not visible it won't calculate sizes properly
        // - Given all that: when we go from a page that is not summary to summary for the first time, the sizes must
        //   be calculated and the charts redrawn. This is why this event only needs to be listened once.
        EventBus.$once("moved-to-summary", () => {
          this._redrawCharts();
        });

        const loadingElement = document.querySelector(".js-loading");
        if (loadingElement) {
          loadingElement.classList.add("hidden");
        }
      });
    }
  }

  setGlobalVariables(rawData) {
    let subsidiesData = rawData[0];

    // Precalculations and normalizations
    this._amountRange = {
      domain: [501, 1001, 5001, 10001, 15001],
      range: [0, 1, 2, 3, 4, 5]
    };
    var rangeFormat = d3
      .scaleThreshold()
      .domain(this._amountRange.domain)
      .range(this._amountRange.range);

    subsidiesData = subsidiesData.map(({ amount = 0, beneficiary = "", beneficiary_type = "", grant_date, ...rest }, index) => {
      let [beneficiary_id, ...beneficiary_name] = beneficiary.split(" ");

      if (beneficiary === '' && beneficiary_type === 'persona') {
        beneficiary = I18n.t('gobierto_visualizations.visualizations.subsidies.person')
      }

      return {
        amount: amount && !Number.isNaN(amount) ? parseFloat(amount) : 0.0,
        range: rangeFormat(+amount),
        beneficiary,
        beneficiary_type,
        beneficiary_id,
        beneficiary_name,
        grant_date,
        id: `${grant_date.replace(/\D+/g,"")}${beneficiary_id.replace(/\D+/g, "")}${parseInt(amount) || 0}${index}`,
        ...rest,
      }
    })

    this.data = {
      subsidiesData: subsidiesData.sort(sortByField("grant_date"))
    };
  }

  _renderSummary() {
    this.ndx = crossfilter(this._currentDataSource().subsidiesData);

    this._renderSubsidiesMetricsBox();

    this._renderByAmountsChart();
    this._renderCategoryChart();
    this._renderDateChart();
  }

  _refreshData(reducedSubsidiesData) {
    this.reduced = { subsidiesData: reducedSubsidiesData };

    this.vueApp.subsidiesData = reducedSubsidiesData;
    EventBus.$emit("refresh-summary-data");<commit_msg>join array names<commit_after>import crossfilter from "crossfilter2";
import { max, mean, median, sum } from "d3-array";
import { scaleThreshold } from "d3-scale";
import { money } from "lib/shared";
import {
  AmountDistributionBars,
  GroupPctDistributionBars
} from "lib/visualizations";
import Vue from "vue";
import VueRouter from "vue-router";
import { getRemoteData, sortByField, calculateSumMeanMedian } from "../webapp/lib/utils";
import { EventBus } from "../webapp/mixins/event_bus";

const d3 = { scaleThreshold, sum, mean, median, max };

Vue.use(VueRouter);
Vue.config.productionTip = false;

export class SubsidiesController {
  constructor(options) {
    this.charts = {};

    const selector = "gobierto-visualizations-subsidies-app";

    // Mount Vue applications
    const entryPoint = document.getElementById(selector);

    if (entryPoint) {
      const htmlRouterBlock = `<router-view></router-view>`;

      entryPoint.innerHTML = htmlRouterBlock;

      const Home = () => import("../webapp/containers/subsidies/Home.vue");
      const Summary = () =>
        import("../webapp/containers/subsidies/Summary.vue");
      const SubsidiesIndex = () =>
        import("../webapp/containers/subsidies/SubsidiesIndex.vue");
      const SubsidiesShow = () =>
        import("../webapp/containers/subsidies/SubsidiesShow.vue");

      Promise.all([getRemoteData(options.subsidiesEndpoint)]).then(rawData => {
        this.setGlobalVariables(rawData);

        const router = new VueRouter({
          mode: "history",
          routes: [
            {
              path: "/visualizaciones/subvenciones",
              component: Home,
              props: { dataDownloadEndpoint: options.dataDownloadEndpoint },
              children: [
                { path: "", name: "summary", component: Summary },
                {
                  path: "subvenciones",
                  name: "subsidies_index",
                  component: SubsidiesIndex
                },
                {
                  path: "subvenciones/:id",
                  name: "subsidies_show",
                  component: SubsidiesShow
                }
              ]
            }
          ]
        });

        const baseTitle = document.title;
        router.afterEach(to => {
          // Wait 2 ticks
          Vue.nextTick(() =>
            Vue.nextTick(() => {
              let title = baseTitle;

              if (to.name === "subsidies_show") {
                const { item: { title: itemTitle } = {} } = to.params;

                if (itemTitle) {
                  title = `${itemTitle}${baseTitle}`;
                }
              }

              document.title = title;
            })
          );
        });

        this.vueApp = new Vue({
          router,
          data: Object.assign(options, this.data)
        }).$mount(entryPoint);

        EventBus.$on("summary-ready", () => {
          this._renderSummary();
        });

        EventBus.$on("filter-changed", options => {
          this._updateChartsFromFilter(options);
        });

        // - dc charts are drawn even if the summary page is not the page where the user lands for the first time
        //   i.e.: they could first land on a subsidy page, but still this page would need to render for the filters to work
        // - dc charts sizes are calculated automatically, but if the page is not visible it won't calculate sizes properly
        // - Given all that: when we go from a page that is not summary to summary for the first time, the sizes must
        //   be calculated and the charts redrawn. This is why this event only needs to be listened once.
        EventBus.$once("moved-to-summary", () => {
          this._redrawCharts();
        });

        const loadingElement = document.querySelector(".js-loading");
        if (loadingElement) {
          loadingElement.classList.add("hidden");
        }
      });
    }
  }

  setGlobalVariables(rawData) {
    let subsidiesData = rawData[0];

    // Precalculations and normalizations
    this._amountRange = {
      domain: [501, 1001, 5001, 10001, 15001],
      range: [0, 1, 2, 3, 4, 5]
    };
    var rangeFormat = d3
      .scaleThreshold()
      .domain(this._amountRange.domain)
      .range(this._amountRange.range);

    subsidiesData = subsidiesData.map(({ amount = 0, beneficiary = "", beneficiary_type = "", grant_date, ...rest }, index) => {
      let [beneficiary_id, ...beneficiary_name] = beneficiary.split(" ");

      if (beneficiary === '' && beneficiary_type === 'persona') {
        beneficiary = I18n.t('gobierto_visualizations.visualizations.subsidies.person')
      }

      return {
        amount: amount && !Number.isNaN(amount) ? parseFloat(amount) : 0.0,
        range: rangeFormat(+amount),
        beneficiary,
        beneficiary_type,
        beneficiary_id,
        beneficiary_name: beneficiary_name.join(" "),
        grant_date,
        id: `${grant_date.replace(/\D+/g,"")}${beneficiary_id.replace(/\D+/g, "")}${parseInt(amount) || 0}${index}`,
        ...rest,
      }
    })

    this.data = {
      subsidiesData: subsidiesData.sort(sortByField("grant_date"))
    };
  }

  _renderSummary() {
    this.ndx = crossfilter(this._currentDataSource().subsidiesData);

    this._renderSubsidiesMetricsBox();

    this._renderByAmountsChart();
    this._renderCategoryChart();
    this._renderDateChart();
  }

  _refreshData(reducedSubsidiesData) {
    this.reduced = { subsidiesData: reducedSubsidiesData };

    this.vueApp.subsidiesData = reducedSubsidiesData;
    EventBus.$emit("refresh-summary-data");
{'fraction_non_alphanumeric': 0.12765195595738968, 'fraction_numerical': 0.0071614000537105005, 'mean_word_length': 2.197481396680023, 'pattern_counts': {'":': 0, '<': 7, '<?xml version=': 0, '>': 31, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 4, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '3873625', 'n_tokens_mistral': 3321, 'n_tokens_neox': 3102, 'n_words': 696}