Skip to content

Insights (Weekly Usage Graphs) ​

Overview ​

  1. Dashboard Widget: A "Last 7 Days" chart panel on the workspace dashboard that renders bar graphs of asset activity — views, downloads, uploads — for the trailing seven calendar days.
  2. Tabbed Metrics: The InsightsTabGraph component renders one tab per metric type returned by the API, allowing admins to switch between activity categories without navigating away.
  3. Plan Gating: Metric tabs can be individually locked behind subscription tiers. When a metric returns a 402 code, the tab is disabled and shows an upgrade prompt rather than graph data.
  4. Access Control: An additional environment-level gate (INSIGHTS_ACCESS_PERSONS) restricts full insights visibility to a comma-separated email allowlist.
  5. Chart Library: Powered by Chart.js 2.9 via the vue-chartjs 3.x wrapper, rendered through a shared Bar.vue plugin component using the reactiveProp mixin for reactive data updates.

Architecture ​

The insights system is anchored entirely on the dashboard page (pages/_workspace_id/dam/dashboard/index.vue). On mount, the page calls fetchWeeklyInsights(), which POSTs to /digital-assets/new-dashboard/weekly-insights with the current date and the date six days prior. The API response is a flat object whose keys are metric names (views, downloads, uploads, etc.) and whose values each contain a graph_data object mapping date strings to integer counts.

The dashboard page transforms this raw response into Chart.js-compatible datasets before passing the data down to the InsightsTabGraph component. Each metric gets a cloned copy of the base InsightsBarData template, with labels set to the date keys and two datasets: a bar series for the raw counts and a scatter overlay for highlighting bars whose value falls below 20% of the maximum — useful for visually flagging near-zero days. Chart options are defined inline on the page and passed as props, including a fully custom tooltip renderer that positions an absolutely-placed DOM element rather than relying on Chart.js's built-in tooltip.

The InsightsTabGraph component handles the tab-level rendering, iterating over the metric object to build one v-tab and one v-tab-item per key. If a metric has a 402 error code in its response, the tab is rendered in a disabled state with a v-tooltip instructing the admin to upgrade. The companion InsightsGraph component is a simpler variant without tabs — it renders each metric as a stacked card in a vertical list and is available for layouts that do not require tabbed switching.

The Vuex analytics store (store/analytics/index.js) holds date range state and a deprecated insightsTransactionAdd action that was used to record anonymous tracking events (base64-encoded, reversed). It remains in the codebase but is marked for removal.

File Structure ​

JavaScript Files (.js) ​

  • store/analytics/index.js — Analytics Vuex module
    • InsightsTransaction and InsightsTransactionShare state for tracking response storage
    • Date range state (dStartDate, dEndDate, lastDate, activeDate) for filter coordination
    • insightsTransactionAdd action for sending encoded transaction activity (deprecated)
    • Getters exposing date state to components via getLastDate, getStartDate, getEndDate

Vue Component Files (.vue) ​

  • components/plugins/Bar.vue — Chart.js bar chart plugin wrapper

    • Extends vue-chartjs Bar with reactiveProp mixin for reactive dataset updates
    • Accepts options and plugins props forwarded to renderChart
    • Re-renders automatically when chartData prop changes via Vue reactivity
  • components/dam/Insights/InsightsTabGraph.vue — Tabbed insights card

    • Renders one v-tab per metric returned by the weekly-insights API
    • Disables tabs for locked metrics (402 response) with a subscription upgrade tooltip
    • Delegates chart rendering to Bar.vue (InsightsBar) for each tab item
    • Accepts dataLoading, weeklyInsightList, barOptions, and barPlugin props
  • components/dam/Insights/InsightsGraph.vue — Stacked insights card (non-tabbed)

    • Renders each metric as a separate 75px-height card stacked vertically
    • Uses the same Bar.vue plugin as InsightsTabGraph
    • Contains a hasAccess computed property gated on INSIGHTS_ACCESS_PERSONS env variable
    • Shows skeleton loaders when dataLoading is true or weeklyInsightList is empty
  • pages/_workspace_id/dam/dashboard/index.vue — Dashboard page (insights host)

    • Calls fetchWeeklyInsights() on mounted to load the trailing 7-day window
    • Holds InsightsBarData template object, InsightsBarOptions config, and InsightBarPlugin array
    • Transforms raw API response into Chart.js datasets (bar series + scatter overlay)
    • Passes composed data to WeeklyInsights (alias for InsightsTabGraph) as props

SVG Icon Components ​

  • components/svg/CollageInsightIcon.vue — Insight/analytics icon used in navigation
  • components/svg/CollageBarChartIcon.vue — Bar chart icon for UI affordances

InsightsTabGraph Component ​

Features ​

  • Tab per metric with label derived from the API response key
  • Disabled tab state with upgrade tooltip for 402-gated metrics
  • Active tab index tracked in activeTab local data
  • Skeleton loader for both the title area and the chart area while loading
  • Empty-state skeleton when weeklyInsightList is an empty object

Props ​

javascript
{
  mainClass: {
    type: String,
    default: 'boxview collageTabs weekly-insights-tab h-auto mb-4'
  },
  heading: {
    type: String,
    default: 'Last 7 Days'
  },
  dataLoading: {
    type: Boolean,
    default: false
  },
  weeklyInsightList: {
    type: Object,
    default: () => ({})
  },
  barOptions: {
    type: Object,
    default: () => ({})
  },
  barPlugin: {
    type: Array,
    default: () => []
  }
}

Events ​

javascript
{
  // InsightsTabGraph emits no events — it is a pure display component
}

Methods ​

javascript
{
  // No public methods — state is managed via props and local activeTab data
}

Usage ​

vue
<template>
  <WeeklyInsights
    mainClass="boxview collageTabs weekly-insights-tab h-auto mb-4"
    heading="Last 7 Days"
    :dataLoading="weeklyInsightLoading"
    :weeklyInsightList="weeklyInsightList"
    :barOptions="InsightsBarOptions"
    :barPlugin="InsightBarPlugin"
  />
</template>

<script>
export default {
  components: {
    WeeklyInsights: () =>
      import('~/components/dam/Insights/InsightsTabGraph.vue'),
  },
  data() {
    return {
      weeklyInsightLoading: false,
      weeklyInsightList: {},
      InsightsBarOptions: {
        maintainAspectRatio: false,
        responsive: true,
        legend: { display: false },
      },
      InsightBarPlugin: [],
    }
  },
}
</script>

InsightsGraph Component ​

Features ​

  • Stacked card layout — one card per metric, fixed 75px height per card
  • Bar chart rendered inside each card with InsightsBar (Bar.vue)
  • Access guard computed property checks INSIGHTS_ACCESS_PERSONS env list
  • Skeleton loader while data loads or when metric list is empty

Props ​

javascript
{
  mainClass: {
    type: String,
    default: 'boxview weekly-insights h-auto mb-4'
  },
  heading: {
    type: String,
    default: 'Last 7 Days'
  },
  dataLoading: {
    type: Boolean,
    default: false
  },
  weeklyInsightList: {
    type: Object,
    default: () => ({})
  },
  barOptions: {
    type: Object,
    default: () => ({})
  },
  barPlugin: {
    type: Array,
    default: () => []
  }
}

Events ​

javascript
{
  // No events emitted — pure display component
}

Methods ​

javascript
{
  // No public methods
}

Usage ​

vue
<template>
  <InsightsGraph
    heading="Last 7 Days"
    :dataLoading="loading"
    :weeklyInsightList="weeklyInsightList"
    :barOptions="barOptions"
    :barPlugin="[]"
  />
</template>

<script>
export default {
  components: {
    InsightsGraph: () =>
      import('~/components/dam/Insights/InsightsGraph.vue'),
  },
}
</script>

Workflows ​

Fetch and Render Insights ​

1. Dashboard page mounts
   Page: pages/_workspace_id/dam/dashboard/index.vue
   ↓
2. mounted() calls fetchWeeklyInsights()
   Computes date range: today minus 6 days → today (YYYY-MM-DD)
   Sets weeklyInsightLoading: true
   ↓
3. POST /digital-assets/new-dashboard/weekly-insights
   Body: { date_type: 'week', from_date, to_date }
   Response: { views: {...}, downloads: {...}, uploads: {...} }
   ↓
4. Transform response into Chart.js datasets
   For each metric key in response:
   a. Check for 402 error — if present, store code + message, skip chart
   b. Clone base InsightsBarData template (deep clone)
   c. Set labels = Object.keys(insight.graph_data) (date strings)
   d. Set bar dataset data = Object.values(insight.graph_data) (counts)
   e. Set scatter dataset data = map values to { x, y, show } objects
      → show = true when value < 20% of max (highlight near-zero bars)
   f. Attach card_label = metric key name
   ↓
5. weeklyInsightList assigned (triggers prop reactivity)
   Component: InsightsTabGraph.vue re-renders
   ↓
6. InsightsTabGraph renders v-tabs
   One tab per metric key
   Disabled tab + tooltip for any metric with code 402
   ↓
7. User clicks a tab
   activeTab data updates
   Corresponding v-tab-item with InsightsBar renders the chart
   ↓
8. Chart.js renders the bar + scatter overlay
   Custom tooltip DOM element positioned absolutely on hover

Plan-Gated Metric Handling ​

1. API returns metric with error shape
   { original: { code: 402, message: 'Upgrade required' } }
   ↓
2. fetchWeeklyInsights detects original.code == 402
   Sets insight.code = 402
   Sets insight.message = original.message
   Skips chart data transformation
   ↓
3. InsightsTabGraph renders disabled v-tab
   v-tooltip wraps the tab: "Please upgrade your subscription plan..."
   v-tab-item shows the message string instead of InsightsBar

API Integration ​

Endpoints ​

MethodPathDescription
POST/digital-assets/new-dashboard/weekly-insightsFetch 7-day usage metrics per activity type

Weekly Insights Request ​

json
POST /digital-assets/new-dashboard/weekly-insights

{
  "date_type": "week",
  "from_date": "2026-08-04",
  "to_date": "2026-08-10"
}

Weekly Insights Response (success) ​

json
{
  "data": {
    "views": {
      "card_label": "views",
      "graph_data": {
        "Aug 4": 12,
        "Aug 5": 0,
        "Aug 6": 34,
        "Aug 7": 8,
        "Aug 8": 21,
        "Aug 9": 5,
        "Aug 10": 17
      }
    },
    "downloads": {
      "card_label": "downloads",
      "graph_data": {
        "Aug 4": 3,
        "Aug 5": 0,
        "Aug 6": 7,
        "Aug 7": 2,
        "Aug 8": 9,
        "Aug 9": 1,
        "Aug 10": 4
      }
    },
    "uploads": {
      "card_label": "uploads",
      "graph_data": {
        "Aug 4": 5,
        "Aug 5": 2,
        "Aug 6": 11,
        "Aug 7": 0,
        "Aug 8": 3,
        "Aug 9": 6,
        "Aug 10": 2
      }
    }
  }
}

Weekly Insights Response (plan-gated metric) ​

json
{
  "data": {
    "views": {
      "original": {
        "code": 402,
        "message": "Please upgrade your plan to access view analytics."
      }
    }
  }
}

Component Integration ​

Full example showing how the dashboard page composes insights with the chart plugin:

vue
<template>
  <div class="collage-body">
    <WeeklyInsights
      mainClass="boxview collageTabs weekly-insights-tab h-auto mb-4"
      heading="Last 7 Days"
      :dataLoading="weeklyInsightLoading"
      :weeklyInsightList="weeklyInsightList"
      :barOptions="InsightsBarOptions"
      :barPlugin="InsightBarPlugin"
    />
  </div>
</template>

<script>
import { cloneDeep } from 'lodash'
import moment from 'moment'

export default {
  layout: 'damLayout',
  components: {
    WeeklyInsights: () =>
      import('~/components/dam/Insights/InsightsTabGraph.vue'),
  },
  data() {
    return {
      weeklyInsightLoading: true,
      weeklyInsightList: {},
      InsightsBarData: {
        labels: [],
        datasets: [
          {
            label: 'Graph Data',
            data: [],
            backgroundColor: '#A8A8F0',
            borderColor: '#A8A8F0',
            hoverBackgroundColor: '#075850',
            hoverBorderColor: '#075850',
            borderWidth: 1,
            fill: true,
          },
          {
            type: 'scatter',
            label: 'Points',
            data: [],
            showLine: false,
            pointBackgroundColor: '#075850',
            pointBorderColor: '#075850',
            pointRadius: 0,
            pointHoverRadius: (ctx) => {
              const pointData = ctx.dataset.data[ctx.dataIndex]
              return pointData && pointData.show ? 5 : 0
            },
          },
        ],
      },
      InsightsBarOptions: {
        maintainAspectRatio: false,
        responsive: true,
        legend: { display: false },
        tooltips: { enabled: false },
      },
      InsightBarPlugin: [],
    }
  },
  async mounted() {
    await this.fetchWeeklyInsights()
  },
  methods: {
    async fetchWeeklyInsights() {
      try {
        this.weeklyInsightLoading = true
        const pastDate = new Date()
        pastDate.setDate(pastDate.getDate() - 6)
        const to_date = moment(new Date()).format('YYYY-MM-DD')
        const from_date = moment(pastDate).format('YYYY-MM-DD')

        const { data } = await this.$axios.$post(
          '/digital-assets/new-dashboard/weekly-insights',
          { date_type: 'week', to_date, from_date }
        )

        this.weeklyInsightList = data
        Object.keys(this.weeklyInsightList).forEach((key) => {
          const insight = this.weeklyInsightList[key]
          if (insight?.original?.code === 402) {
            insight.code = insight.original.code
            insight.message = insight.original.message
            insight.card_label = key
          } else if (insight && typeof insight === 'object') {
            insight.card_label = key
            insight.bar_data = cloneDeep(this.InsightsBarData)
            insight.bar_data.labels = Object.keys(insight.graph_data)
            insight.bar_data.datasets[0].card_label = key
            insight.bar_data.datasets[0].data = Object.values(insight.graph_data)
            insight.bar_data.datasets[1].card_label = key
            const maxValue = Math.max(...Object.values(insight.graph_data))
            insight.bar_data.datasets[1].data = Object.values(insight.graph_data).map(
              (value, index) => ({
                x: index + 0.5,
                y: value,
                show: value <= 0.2 * maxValue,
              })
            )
          }
        })
      } catch (error) {
        this.weeklyInsightList = {}
        this.$snackbar.error(this.$getErrorMessage(error))
      } finally {
        this.weeklyInsightLoading = false
      }
    },
  },
}
</script>
  • Dashboard — The host page for the weekly insights widget
  • File Upload — Upload system that generates the activity tracked in insights
  • Analytics Store — Vuex module for date range state and transaction tracking
  • Chart.js Integration — Bar chart plugin via vue-chartjs