UNPKG

@tanglemedia/directus-extension-bundle-page-views

Version:

A Directus extension bundle that adds a page views collection and dashboard to track page views.

495 lines (486 loc) 8.66 kB
import crypto from "crypto"; const DASHBOARD_UUID = "795caeab-3f39-4031-a1ed-631d3b127fb4"; const COLLECTION_NAME = "tngl_page_views"; // create function to generate a uuidv4 function generateUUIDv4() { return ([1e7] + -1e3 + -4e3 + -8e3 + -1e11).replace(/[018]/g, (c) => (c ^ ((crypto.randomBytes(1)[0] & 15) >> (c / 4))).toString(16) ); } // preset that applies to any user or role const PANELS = [ { name: "Top 10 Sources", icon: null, color: null, show_header: true, note: null, type: "metric-list", position_x: 57, position_y: 29, width: 32, height: 22, options: JSON.stringify({ limit: 10, filter: { _and: [ { date_created: { _gt: "$NOW(-{{ time_range }})", }, }, { environment: { _eq: "Production", }, }, { source: { _ncontains: process.env.SITE_BASE_URL, }, } ], }, collection: COLLECTION_NAME, groupByField: "source", aggregateField: "source", aggregateFunction: "count", }), }, { name: "Top 10 Visited Pages", icon: null, color: null, show_header: true, note: null, type: "metric-list", position_x: 57, position_y: 7, width: 32, height: 22, options: JSON.stringify({ limit: 10, filter: { _and: [ { date_created: { _gt: "$NOW(-{{ time_range }})", }, }, { environment: { _eq: "Production", }, }, ], }, collection: COLLECTION_NAME, groupByField: "endpoint", aggregateField: "endpoint", aggregateFunction: "count", }), }, { name: "Total Unique Visitors", icon: null, color: null, show_header: true, note: null, type: "metric", position_x: 1, position_y: 40, width: 14, height: 11, options: JSON.stringify({ fn: "count", max: 100, field: "ip_address", filter: { _and: [ { date_created: { _gt: "$NOW(-{{ time_range }})", }, }, { environment: { _eq: "Production", }, }, ], }, suffix: null, fontSize: "48px", function: "countDistinct", notation: "compact", sortField: "ip_address", collection: COLLECTION_NAME, maximumFractionDigits: 1, minimumFractionDigits: 1, }), }, { name: "Unique Visitors", icon: "today", color: null, show_header: true, note: null, type: "time-series", position_x: 15, position_y: 29, width: 42, height: 22, options: JSON.stringify({ max: null, min: 0, color: "#6644FF", range: "{{ time_range }}", filter: { _and: [ { environment: { _eq: "Production", }, }, ], }, function: "countDistinct", dateField: "date_created", precision: "day", collection: COLLECTION_NAME, valueField: "ip_address", }), }, { name: "Top Locations Viewed", icon: null, color: null, show_header: false, note: null, type: "choropleth-map-panel", position_x: 1, position_y: 51, width: 56, height: 44, options: JSON.stringify({ filter: { _and: [ { date_created: { _gt: "$NOW(-{{ time_range }})", }, }, { environment: { _eq: "Production", }, }, ], }, collection: COLLECTION_NAME, countryField: "country_code", aggregateField: "ip_address", aggregateFunction: "count", }), }, { name: "Top 10 Countries", icon: null, color: null, show_header: true, note: null, type: "metric-list", position_x: 57, position_y: 51, width: 32, height: 22, options: JSON.stringify({ limit: 10, filter: { _and: [ { date_created: { _gt: "$NOW(-{{ time_range }})", }, }, { environment: { _eq: "Production", }, }, ], }, collection: COLLECTION_NAME, groupByField: "country_name", aggregateField: "country_code", aggregateFunction: "count", }), }, { name: "Time Range", icon: null, color: null, show_header: true, note: null, type: "variable", position_x: 1, position_y: 1, width: 88, height: 6, options: JSON.stringify({ type: "string", field: "time_range", inter: "select-dropdown", options: { choices: [ { text: "Past Year", value: "12 months", }, { text: "Past 6 Months", value: "6 months", }, { text: "Past 3 Months", value: "3 months", }, { text: "Past 2 Weeks", value: "2 weeks", }, { text: "Past Month", value: "1 month", }, { text: "Past Week", value: "1 week", }, { text: "Today", value: "1 day", }, ], placeholder: "Select Filter", }, defaultValue: "1 month", }), }, { name: "Device Usage", icon: null, color: null, show_header: true, note: null, type: "pie-chart", position_x: 1, position_y: 29, width: 14, height: 11, options: JSON.stringify({ fn: "count", max: 100, field: "ip_address", column: "device", filter: { _and: [ { date_created: { _gt: "$NOW(-{{ time_range }})", }, }, { environment: { _eq: "Production", }, }, ], }, legend: "right", suffix: null, fontSize: "48px", function: "count", notation: "compact", sortField: "device", collection: COLLECTION_NAME, showLabels: true, maximumFractionDigits: 1, minimumFractionDigits: 1, }), }, { name: "Distinct Pages Viewed", icon: null, color: null, show_header: true, note: null, type: "metric", position_x: 1, position_y: 18, width: 14, height: 11, options: JSON.stringify({ fn: "count", field: "endpoint", filter: { _and: [ { date_created: { _gt: "$NOW(-{{ time_range }})", }, }, { environment: { _eq: "Production", }, }, ], }, suffix: null, fontSize: "48px", function: "countDistinct", notation: "compact", sortField: "endpoint", collection: COLLECTION_NAME, showPercentage: false, maximumFractionDigits: 1, minimumFractionDigits: 1, }), }, { name: "Total Pages Viewed", icon: null, color: null, show_header: true, note: null, type: "metric", position_x: 1, position_y: 7, width: 14, height: 11, options: JSON.stringify({ field: "endpoint", filter: { _and: [ { date_created: { _gt: "$NOW(-{{ time_range }})", }, }, { environment: { _eq: "Production", }, }, ], }, suffix: null, fontSize: "48px", function: "count", notation: "compact", sortField: "endpoint", collection: COLLECTION_NAME, maximumFractionDigits: 1, minimumFractionDigits: 1, }), }, { name: "Page Views", icon: "today", color: null, show_header: true, note: null, type: "time-series", position_x: 15, position_y: 7, width: 42, height: 22, options: JSON.stringify({ max: null, min: 0, color: "#6644FF", range: "{{ time_range }}", filter: { _and: [ { environment: { _eq: "Production", }, }, ], }, function: "count", dateField: "date_created", precision: "day", collection: COLLECTION_NAME, valueField: "ip_address", }), }, { name: "Top 10 Languages", icon: null, color: null, show_header: true, note: null, type: "metric-list", position_x: 57, position_y: 73, width: 32, height: 22, options: JSON.stringify({ limit: 10, filter: { _and: [ { date_created: { _gt: "$NOW(-{{ time_range }})", }, }, { environment: { _eq: "Production", }, }, ], }, collection: COLLECTION_NAME, groupByField: "language_name", aggregateField: "language_name", aggregateFunction: "count", }), }, ]; export async function up(knex) { // addd Website Analytics Dashboard await knex("directus_dashboards").insert({ id: DASHBOARD_UUID, name: "Website Analytics", icon: "assessment", note: "Metrics for Website Analytics", color: null, }); // add Website Analytics panels const newPanels = PANELS.map((panel) => { return knex("directus_panels").insert({ ...panel, dashboard: DASHBOARD_UUID, id: generateUUIDv4(), }); }); await Promise.all(newPanels); } export async function down(knex) { // remove Website Analytics panels await knex("directus_panels") .where({ dashboard: DASHBOARD_UUID, }) .del(); // remove Website Analytics Dashboard await knex("directus_dashboards") .where({ id: DASHBOARD_UUID, }) .del(); }