Skip to content

Instantly share code, notes, and snippets.

@julrich
Created April 11, 2022 17:41
Show Gist options
  • Save julrich/608167749eb2716d6107a3bc8446e7a3 to your computer and use it in GitHub Desktop.
Save julrich/608167749eb2716d6107a3bc8446e7a3 to your computer and use it in GitHub Desktop.
Rudimentary Component (props) Analytics in InfluxDB
const { InfluxDB, Point, HttpError } = require('@influxdata/influxdb-client');
const url = process.env['GATSBY_INFLUX_URL'] || 'http://localhost:8086';
const token = process.env['GATSBY_INFLUX_TOKEN'] || 'my-token';
const org = process.env['GATSBY_INFLUX_ORG'] || 'my-org';
const bucket = process.env['GATSBY_INFLUX_BUCKET'] || 'my-bucket';
const db = new InfluxDB({ url, token });
const isObject = (obj) =>
Object.prototype.toString.call(obj) === '[object Object]';
const pack = (obj) =>
Object.entries(obj).reduce((prev, [key, value]) => {
if (isObject(value) || Array.isArray(value)) {
Object.entries(pack(value)).forEach(([key2, value2]) => {
prev[`${key}.${key2}`] = value2;
});
} else {
prev[key] = value;
}
return prev;
}, {});
const componentStatistics = async (key, slug, componentName, componentProps, timestamp) => {
const packedProps = pack(componentProps);
const writeApi = db.getWriteApi(org, bucket, 'ns');
writeApi.useDefaultTags({ location: 'kickstartDS' });
const componentStats = new Point('components')
.tag('componentName', componentName)
.tag('id', key)
.tag('slug', slug)
.timestamp(timestamp);
Object.keys(packedProps).forEach((packedPropName) => {
switch (typeof packedProps[packedPropName]) {
case 'boolean':
componentStats.booleanField(packedPropName, packedProps[packedPropName]);
break;
case 'string':
componentStats.stringField(packedPropName, packedProps[packedPropName] || '');
break;
case 'number':
componentStats.intField(packedPropName, packedProps[packedPropName] || 0);
break;
}
});
writeApi.writePoint(componentStats);
await writeApi.close();
};
const timestamp = new Date();
const componentCounter = [];
const analyzeComponent = async (slug, element, isSection = false) => {
const componentType = isSection ? 'section' : element['type'];
componentCounter[componentType] = componentCounter[componentType]+1 || 1;
const key = componentType+'-'+componentCounter[componentType];
if (isSection) {
const contentKey = Object.keys(element).find(
(key) => key.includes("content__") || key.includes("content"),
);
const { [contentKey]: content, ...clonedElement } = element;
const cleanedElement = cleanObjectKeys(clonedElement);
cleanedElement['headline'].type = 'headline';
await componentStatistics(key, slug, componentType, cleanedElement, timestamp);
await analyzeContent(slug, content);
}
const cleanedElement = cleanObjectKeys(element);
const { typeProp, type, ...restElement } = cleanedElement;
await componentStatistics(key, slug, componentType, restElement, timestamp);
};
const analyzeContent = async (slug, content, sections = false) => {
if (content && content.length > 0) {
await Promise.all(content.map(async (element) => await analyzeComponent(slug, element, sections)));
}
};
exports.analyzeContent = analyzeContent;
@julrich
Copy link
Author

julrich commented Apr 11, 2022

This gets called for all of our dynamic content, which itself consists of JSON Schema-defined, structured JSON. In parallel that data gets passed down the respective component templates, with those props, to render the actual resulting interface! 🚀

The same JSON Schema definitions are also used to infer data for the visualization, later on (e.g.: which values exist in a dropdown choice like variant, even if they were never actually used... or which defaults always apply):
grafik

(:superhero_man: they also generate TypeScript types for IDE completion, validation for APIs, CMS configuration for headless CMS solutions like Sanity or Storyblok, or the Controls documentation in our Storybook: https://www.kickstartds.com/storybook/?path=/story/content-visual--box-light)

Learn more about what we are building:
https://www.kickstartDS.com/

@julrich
Copy link
Author

julrich commented Apr 11, 2022

Example for JSON Schema from our Storybook:
grafik

https://www.kickstartds.com/storybook/?path=/story/content-visual--box-light (on the JSON Schema Tab)

Corresponding generated Storybook Controls / documentation:
grafik

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment