Skip to content

Commit

Permalink
scripts for generating component config stats (#11551)
Browse files Browse the repository at this point in the history
* scripts for generating component config stats

* some updates to the workflow

* cleanup packages.json

* skip docker build on changes to stats folder
  • Loading branch information
nkylstad authored Nov 16, 2023
1 parent 43a85d7 commit c5be695
Show file tree
Hide file tree
Showing 12 changed files with 3,491 additions and 0 deletions.
1 change: 1 addition & 0 deletions .github/workflows/build-image-on-pr.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ on:
types: [opened, synchronize, reopened]
paths:
- 'frontend/**'
- '!frontend/stats/**'
- 'backend/**'
- '.github/workflows/build-image-on-pr.yaml'
workflow_dispatch:
Expand Down
28 changes: 28 additions & 0 deletions .github/workflows/frontend-config-coverage.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
name: Configuration coverage stats

on:
push:
paths:
- 'frontend/app-development/**'
- 'frontend/packages/ux-editor/**'
- '.github/workflows/frontend-config-coverage.yml'

jobs:
stats:
name: 'Generate stats on configuration coverage'
runs-on: ubuntu-latest
permissions:
actions: read
contents: read
security-events: write
steps:
- name: 'Checking Out Code'
uses: actions/checkout@v4
with:
fetch-depth: 0

- name: 'Installing Dependencies'
run: cd frontend/stats && yarn --immutable

- name: 'Running stats generation'
run: cd frontend/stats && yarn run generate-config-coverage-stats
1 change: 1 addition & 0 deletions frontend/.gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

/.pnp.*
/.yarn/*
stats/.yarn/*
language/old/*
!/.yarn/patches
!/.yarn/plugins
Expand Down
29 changes: 29 additions & 0 deletions frontend/stats/configurationStats/Application.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
import { ConfigFile } from './ConfigFile';
import { ConfigurableItem } from './ConfigurableItem';
import { unsupportedApplicationMetadataProperties } from './unsupported';

/**
* Class representing the application metadata configuration file stats
*/
export class Application extends ConfigFile {
constructor(schema: any, unsupportedItems?: string[]) {
super(schema, unsupportedItems);
this.items = [new ApplicationItem('ApplicationMetadata', schema)];
}
}

class ApplicationItem extends ConfigurableItem {
constructor(name: string, schema: any) {
super(name, schema, unsupportedApplicationMetadataProperties);
this.properties = this.getProperties(schema);
}

/**
* Application metadata properties are on the root of the schema
* @param schema
* @returns An array of the application metadata property names
*/
getProperties = (schema: any) => {
return Object.keys(schema.properties);
};
}
38 changes: 38 additions & 0 deletions frontend/stats/configurationStats/ConfigFile.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
import { JsonSchema } from 'app-shared/types/JsonSchema';
import { ConfigurableItem } from './ConfigurableItem';

export interface IConfigFile {
schema: any;
items: ConfigurableItem[];
unsupportedItems: string[];
calculateMeanPercentageSupportedProperties: () => number;
}

export abstract class ConfigFile implements IConfigFile {
schema: JsonSchema;
items: ConfigurableItem[];
unsupportedItems: string[];

constructor(schema: JsonSchema, unsupportedItems?: string[]) {
this.schema = schema;
this.unsupportedItems = unsupportedItems || [];
}

public calculateMeanPercentageSupportedProperties() {
const itemCount = this.items.length;
const totalPercentageSupportedProperties = this.items.reduce(
(total: number, item: ConfigurableItem) => {
item.setPercentageSupportedProperties();
console.log(
`${item.name}`,
'supported property percentage:',
item.getPercentageSupportedProperties(),
'%',
);
return total + item.getPercentageSupportedProperties();
},
0,
);
return Math.round(totalPercentageSupportedProperties / itemCount);
}
}
46 changes: 46 additions & 0 deletions frontend/stats/configurationStats/ConfigurableItem.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
import { JsonSchema } from 'app-shared/types/JsonSchema';

/**
* Represents a configurable item in a configuration file.
*/
export abstract class ConfigurableItem {
schema: JsonSchema;
name: string;
properties: string[];
unsupportedProperties: string[];
private _percentageSupportedProperties: number;
isUnsupported: boolean;

constructor(
name: string,
schema: JsonSchema,
unsupportedProperties: string[],
unsupported: boolean = false,
) {
this.name = name;
this.schema = schema;
this.unsupportedProperties = unsupportedProperties;
this.isUnsupported = unsupported;
}

public setPercentageSupportedProperties = () => {
if (this.isUnsupported) {
this._percentageSupportedProperties = 0;
return;
}

const propertyCount = this.properties.length;
const unsupportedPropertyCount = this.properties.filter((property: string) =>
this.unsupportedProperties.includes(property),
).length;
this._percentageSupportedProperties = Math.round(
((propertyCount - unsupportedPropertyCount) / propertyCount) * 100,
);
};

public getPercentageSupportedProperties = () => {
return this._percentageSupportedProperties;
};

abstract getProperties(schema: JsonSchema): string[];
}
47 changes: 47 additions & 0 deletions frontend/stats/configurationStats/Layout.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
import { ConfigFile } from './ConfigFile';
import { unsupportedLayoutComponents } from './unsupported';
import { ConfigurableItem } from './ConfigurableItem';
import { unsupportedComponentProperties } from './unsupported';

/**
* Class representing layout configuration file stats
*/
export class Layout extends ConfigFile {
constructor(layoutSchema: any) {
super(layoutSchema, unsupportedLayoutComponents);
this.items = this.getAllComponentNames(layoutSchema).map((name: string) => {
return new Component(name, layoutSchema, this.unsupportedItems.includes(name));
});
}

private getAllComponentNames = (schema: any) => {
const componentsFromSchema: string[] = schema.definitions.AnyComponent.properties.type.enum;
const additionalComponents = [
'GroupRepeating',
'GroupNonRepeating',
'GroupNonRepeatingPanel',
'GroupRepeatingLikert',
];
componentsFromSchema.splice(componentsFromSchema.indexOf('Group'), 1, ...additionalComponents);
return componentsFromSchema;
};
}

export class Component extends ConfigurableItem {
constructor(name: string, layoutSchema: any, unsupported: boolean = false) {
const schema = layoutSchema.definitions[`Comp${name.replace('Component', '')}`];
super(name, schema, unsupportedComponentProperties, unsupported);
this.properties = this.getProperties(schema);
}

/**
* Exploiting the fact that the last entry in the allOf array from the layout
* component schema contains all of the component properties.
* @param componentSchema
* @returns An array of the component property names
*/
getProperties = (componentSchema: any) => {
const allOfLength = componentSchema.allOf.length;
return Object.keys(componentSchema.allOf[allOfLength - 1].properties);
};
}
31 changes: 31 additions & 0 deletions frontend/stats/configurationStats/LayoutSettings.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
import { ConfigFile } from './ConfigFile';
import { ConfigurableItem } from './ConfigurableItem';
import { unsupportedLayoutSettingsProperties } from './unsupported';

/**
* Class representing layout settings configuration file stats
*/
export class LayoutSettings extends ConfigFile {
constructor(schema: any, unsupportedItems?: string[]) {
super(schema, unsupportedItems);
this.items = Object.keys(schema.properties).map((name: string) => {
return new SettingsItem(name, schema);
});
}
}

class SettingsItem extends ConfigurableItem {
constructor(name: string, schema: any) {
super(name, schema, unsupportedLayoutSettingsProperties);
this.properties = this.getProperties(schema);
}

/**
* Properties for layoutSettings are defined in the definitions object
* @param schema
* @returns
*/
getProperties = (schema: any) => {
return Object.keys(schema.definitions[this.name].properties);
};
}
92 changes: 92 additions & 0 deletions frontend/stats/configurationStats/run.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,92 @@
import { Layout } from './Layout';
import { LayoutSettings } from './LayoutSettings';
import { ConfigFile } from './ConfigFile';
import { Application } from './Application';
import axios from 'axios';

const calculateAndWriteToConsole = (
configFileInstance: ConfigFile,
name: string,
statsByString: 'property' | 'component' = 'property',
) => {
console.log('');
console.log('**********************************************************');
console.log(`${name} config support by ${statsByString}`);
console.log('**********************************************************');
return configFileInstance.calculateMeanPercentageSupportedProperties();
};

const generateLayoutFilesStats = async () => {
const layoutSchemaResult = await axios.get(
'https://altinncdn.no/schemas/json/layout/layout.schema.v1.json',
);
const layout = new Layout(layoutSchemaResult.data);
const meanSupportedComponentPropertyPercentage = calculateAndWriteToConsole(
layout,
'Layout files',
'component',
);

const layoutSettingsSchemaResult = await axios.get(
'https://altinncdn.no/schemas/json/layout/layoutSettings.schema.v1.json',
);
const layoutSettings = new LayoutSettings(layoutSettingsSchemaResult.data);
const meanSupportedLayoutSettingsSupport = calculateAndWriteToConsole(
layoutSettings,
'LayoutSettings',
);

// Only the 'sets' property exists in the layout-sets schema, and it is not supported
const meanSupportedLayoutSetsSuport = 0;

console.log('');
console.log('**********************************************************');
console.log('Mean results');
console.log('**********************************************************');

console.log(
'Mean supported layout component property config:',
meanSupportedComponentPropertyPercentage,
'%',
);
console.log('Mean supported layout settings config:', meanSupportedLayoutSettingsSupport, '%');
console.log('Mean supported layout sets config', meanSupportedLayoutSetsSuport, '%');
console.log('-----------------------------------------------------');
console.log(
'Mean support layout files total: ',
Math.round(
(meanSupportedComponentPropertyPercentage +
meanSupportedLayoutSettingsSupport +
meanSupportedLayoutSetsSuport) /
3,
),
'%',
);
};

const generateApplicationFilesStats = async () => {
const result = await axios.get(
'https://altinncdn.no/schemas/json/application/application-metadata.schema.v1.json',
);
const application = new Application(result.data);
calculateAndWriteToConsole(application, 'Application files');
};

const generateStats = async () => {
console.log('LAYOUT FILES');
await generateLayoutFilesStats();
console.log('');
console.log('APPLICATION METADATA');
await generateApplicationFilesStats();
};

generateStats()
.catch((error: any) => {
console.log('-----------------------------------------------------');
console.log('Error generating stats');
console.log(error);
})
.finally(() => {
console.log('-----------------------------------------------------');
console.log('Done generating stats');
});
44 changes: 44 additions & 0 deletions frontend/stats/configurationStats/unsupported.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
export const unsupportedLayoutComponents: string[] = [
'Grid',
'AccordionGroup',
'Accordion',
'ButtonGroup',
];

export const unsupportedComponentProperties: string[] = [
'grid',
'saveWhileTyping',
'excludedChildren',
'pagination',
'rows',
'edit',
'minCount',
'tableColumns',
'hiddenRow',
'rowsBefore',
'rowsAfter',
,
'showGroupingIndicator',
];

export const unsupportedLayoutSettingsProperties: string[] = [
'excludeFromPdf',
'triggers',
'hideCloseButton',
'showLanguageSelector',
'showExpandWidthButton',
'pdfLayoutName',
'showProgress',
'autoSaveBehavior',
];

export const unsupportedApplicationMetadataProperties: string[] = [
'processId',
'eFormidling',
'dataFields',
'presentationFields',
'dataTypes',
'validTo',
'validFrom',
'logo',
];
Loading

0 comments on commit c5be695

Please sign in to comment.