Skip to content

Commit

Permalink
Update UI layout and add new components
Browse files Browse the repository at this point in the history
  • Loading branch information
austenstone committed Jan 19, 2024
1 parent 48926eb commit af10f85
Show file tree
Hide file tree
Showing 20 changed files with 254 additions and 32 deletions.
18 changes: 15 additions & 3 deletions src/app/app.component.html
Original file line number Diff line number Diff line change
@@ -1,3 +1,15 @@
<h1>GitHub Usage Report</h1>
<p>This is an entirely client side application. Your usage report never leaves your computer.</p>
<app-usage></app-usage>
<div class="container">
<div class="header">
<div class="logo">
<img src="assets/github-mark.svg">
</div>
<h1 class=" mat-headline-1">
Github Usage Report
</h1>
</div>
<div class="flex-center">
<h2>Visualize your Github usage</h2>
<p>This is an entirely client side application. Your usage report never leaves your computer.</p>
<app-usage></app-usage>
</div>
</div>
8 changes: 5 additions & 3 deletions src/app/app.module.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,9 @@ import { BrowserAnimationsModule } from '@angular/platform-browser/animations';
import { UsageComponent } from './usage/usage.component';
import { UsageTableComponent } from './usage-table/usage-table.component';
import { FileUploadComponent } from './file-upload/file-upload.component';
import { ChartPieOwnerComponent } from './chart-pie-owner/chart-pie-owner.component';
import { ChartPieUserComponent } from './chart-pie-user/chart-pie-user.component';
import { ChartLineUsageTimeComponent } from './chart-line-usage-time/chart-line-usage-time.component';
import { TableWorkflowUsageComponent } from './table-workflow-usage/table-workflow-usage.component';

import { HighchartsChartModule } from 'highcharts-angular';

Expand All @@ -18,8 +19,9 @@ import { HighchartsChartModule } from 'highcharts-angular';
UsageComponent,
UsageTableComponent,
FileUploadComponent,
ChartPieOwnerComponent,
ChartLineUsageTimeComponent
ChartPieUserComponent,
ChartLineUsageTimeComponent,
TableWorkflowUsageComponent
],
imports: [
BrowserModule,
Expand Down
Original file line number Diff line number Diff line change
@@ -1,18 +1,18 @@
import { ComponentFixture, TestBed } from '@angular/core/testing';

import { ChartPieOwnerComponent } from './chart-pie-owner.component';
import { ChartPieUserComponent } from './chart-pie-user.component';

describe('ChartPieOwnerComponent', () => {
let component: ChartPieOwnerComponent;
let fixture: ComponentFixture<ChartPieOwnerComponent>;
let component: ChartPieUserComponent;
let fixture: ComponentFixture<ChartPieUserComponent>;

beforeEach(async () => {
await TestBed.configureTestingModule({
declarations: [ ChartPieOwnerComponent ]
declarations: [ ChartPieUserComponent ]
})
.compileComponents();

fixture = TestBed.createComponent(ChartPieOwnerComponent);
fixture = TestBed.createComponent(ChartPieUserComponent);
component = fixture.componentInstance;
fixture.detectChanges();
});
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,19 +3,19 @@ import { UsageReportLine } from 'github-usage-report/types';
import * as Highcharts from 'highcharts';

@Component({
selector: 'app-chart-pie-owner',
templateUrl: './chart-pie-owner.component.html',
styleUrls: ['./chart-pie-owner.component.scss']
selector: 'app-chart-pie-user',
templateUrl: './chart-pie-user.component.html',
styleUrls: ['./chart-pie-user.component.scss']
})
export class ChartPieOwnerComponent {
export class ChartPieUserComponent {
@Input() data!: UsageReportLine[];
Highcharts: typeof Highcharts = Highcharts;
options: Highcharts.Options = {
chart: {
type: 'pie'
},
title: {
text: 'Usage by Owner'
text: 'Usage by username'
},
tooltip: {
pointFormat: '{series.name}: <b>{point.percentage:.1f}%</b>'
Expand All @@ -38,9 +38,9 @@ export class ChartPieOwnerComponent {
type: 'pie', // Add the type property
name: 'Usage',
data: this.data.reduce((acc, line) => {
const index = acc.findIndex((item) => item[0] === line.owner);
const index = acc.findIndex((item) => item[0] === line.username);
if (index === -1) {
acc.push([line.owner, line.quantity]);
acc.push([line.username, line.quantity]);
} else {
acc[index][1] += line.quantity;
}
Expand Down
7 changes: 5 additions & 2 deletions src/app/file-upload/file-upload.component.html
Original file line number Diff line number Diff line change
@@ -1,2 +1,5 @@
<input type="file" #fileInput name="fileUpload" (change)="onFileSelected($event)" style="display: none;">
<button mat-button color="primary" (click)="fileInput.click()">Browse</button>
<input type="file" #fileInput name="fileUpload" (change)="onFileSelected($event)" style="display: none;">
<button mat-fab extended (click)="fileInput.click()">
<mat-icon>upload_file</mat-icon>
Choose File
</button>
21 changes: 21 additions & 0 deletions src/app/table-workflow-usage/table-workflow-usage.component.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
<h1>Workflow Usage</h1>

<div class="mat-elevation-z8">
<table mat-table [dataSource]="dataSource" class="mat-elevation-z8 demo-table" matSort>
@for (column of columns; track column) {
<ng-container [matColumnDef]="column.columnDef">
<th mat-header-cell *matHeaderCellDef mat-sort-header>
{{column.header}}
</th>
<td mat-cell *matCellDef="let row">
{{column.cell(row)}}
</td>
</ng-container>
}

<tr mat-header-row *matHeaderRowDef="displayedColumns"></tr>
<tr mat-row *matRowDef="let row; columns: displayedColumns;"></tr>
</table>

<mat-paginator [pageSizeOptions]="[10, 25, 100]" aria-label="Select page of users"></mat-paginator>
</div>
Empty file.
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
import { ComponentFixture, TestBed } from '@angular/core/testing';

import { TableWorkflowUsageComponent } from './table-workflow-usage.component';

describe('TableWorkflowUsageComponent', () => {
let component: TableWorkflowUsageComponent;
let fixture: ComponentFixture<TableWorkflowUsageComponent>;

beforeEach(async () => {
await TestBed.configureTestingModule({
imports: [TableWorkflowUsageComponent]
})
.compileComponents();

fixture = TestBed.createComponent(TableWorkflowUsageComponent);
component = fixture.componentInstance;
fixture.detectChanges();
});

it('should create', () => {
expect(component).toBeTruthy();
});
});
77 changes: 77 additions & 0 deletions src/app/table-workflow-usage/table-workflow-usage.component.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
import { Component, Input, ViewChild } from '@angular/core';
import { UsageReport, UsageReportLine } from 'github-usage-report/types';
import { MatPaginator, MatPaginatorModule } from '@angular/material/paginator';
import { MatTableDataSource, MatTableModule } from '@angular/material/table';
import { MatSort } from '@angular/material/sort';

@Component({
selector: 'app-table-workflow-usage',
templateUrl: './table-workflow-usage.component.html',
styleUrl: './table-workflow-usage.component.scss'
})
export class TableWorkflowUsageComponent {
columns = [
{
columnDef: 'workflow',
header: 'Workflow',
cell: (workflowItem: any) => `${workflowItem.workflow}`,
},
{
columnDef: 'total',
header: 'Total',
cell: (workflowItem: any) => `${workflowItem.total}`,
}
];
displayedColumns = this.columns.map(c => c.columnDef);
@Input() data!: UsageReport;
dataSource: MatTableDataSource<UsageReportLine> = new MatTableDataSource<any>(); // Initialize the dataSource property

@ViewChild(MatPaginator) paginator!: MatPaginator;
@ViewChild(MatSort) sort!: MatSort;

ngOnInit() {
const workflowUsage = this.data.lines.filter(a => a.actionsWorkflow).reduce((acc, line) => {
const workflowEntry = acc.find(a => a.workflow === line.actionsWorkflow);
const date = new Date(line.date);
const month: string = date.toLocaleString('default', { month: 'long' });
if (workflowEntry) {
if (workflowEntry[month]) {
workflowEntry[month] += line.quantity || 0;
} else {
workflowEntry[month] = line.quantity || 0;
}
workflowEntry.total += line.quantity || 0;
if (!this.columns.find(c => c.columnDef === month)) {
this.columns.push({
columnDef: month,
header: month,
cell: (cost: any) => `${cost[month]}`,
});
this.displayedColumns = this.columns.map(c => c.columnDef);
}
} else {
acc.push({
workflow: line.actionsWorkflow,
repo: line.repositorySlug,
total: line.quantity || 0,
[month]: line.quantity || 0
});
}
return acc; // Add this line to return the accumulator
}, [] as any[]);
// fill in undefined months in workflowUsage
workflowUsage.forEach((workflowItem: any) => {
this.columns.forEach((column: any) => {
if (!workflowItem[column.columnDef]) {
workflowItem[column.columnDef] = 0;
}
});
});
this.dataSource = new MatTableDataSource(workflowUsage);
}

ngAfterViewInit() {
this.dataSource.paginator = this.paginator;
this.dataSource.sort = this.sort;
}
}
2 changes: 1 addition & 1 deletion src/app/usage-table/usage-table.component.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import { Input } from '@angular/core';
import {AfterViewInit, Component, ViewChild} from '@angular/core';
import {MatPaginator, MatPaginatorModule} from '@angular/material/paginator';
import {MatTableDataSource, MatTableModule} from '@angular/material/table';
import { UsageReportLine } from 'github-usage-report/types';
import { UsageReport, UsageReportLine } from 'github-usage-report/types';

/**
* @title Table with pagination
Expand Down
7 changes: 4 additions & 3 deletions src/app/usage/usage.component.html
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
<app-file-upload (fileText)="onFileText($event)"></app-file-upload>

<ng-container *ngIf="usage">
<app-chart-pie-owner [data]="usage.lines"></app-chart-pie-owner>
<app-chart-pie-user [data]="usage.lines"></app-chart-pie-user>
<app-chart-line-usage-time [data]="usage"></app-chart-line-usage-time>
<!-- <app-usage-table [data]="usage.lines"></app-usage-table> -->
<app-table-workflow-usage [data]="usage"></app-table-workflow-usage>
</ng-container>

<app-file-upload (fileText)="onFileText($event)"></app-file-upload>

5 changes: 4 additions & 1 deletion src/app/usage/usage.component.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { Component } from '@angular/core';
import { ChangeDetectorRef, Component } from '@angular/core';
import { UsageReport } from 'github-usage-report/types';
import { readGithubUsageReport } from 'github-usage-report/usage-report';

Expand All @@ -10,6 +10,8 @@ import { readGithubUsageReport } from 'github-usage-report/usage-report';
export class UsageComponent {
usage: UsageReport | null = null;

constructor(private cdr: ChangeDetectorRef) { } // inject ChangeDetectorRef

ngOnInit() {
const oldUsage = localStorage.getItem('usage');
this.usage = oldUsage ? JSON.parse(oldUsage) : null;
Expand All @@ -18,5 +20,6 @@ export class UsageComponent {
async onFileText(fileText: string) {
const usage = await readGithubUsageReport(fileText);
this.usage = usage;
this.cdr.detectChanges(); // manually trigger change detection
}
}
1 change: 1 addition & 0 deletions src/assets/github-mark-white.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
1 change: 1 addition & 0 deletions src/assets/github-mark.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
2 changes: 1 addition & 1 deletion src/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
<link href="https://fonts.googleapis.com/css2?family=Roboto:wght@300;400;500&display=swap" rel="stylesheet">
<link href="https://fonts.googleapis.com/icon?family=Material+Icons" rel="stylesheet">
</head>
<body class="mat-typography">
<body class="mat-typography mat-app-background">
<app-root></app-root>
</body>
</html>
4 changes: 3 additions & 1 deletion src/material.module.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import { MatTableModule } from '@angular/material/table';
import { MatInputModule } from '@angular/material/input';
import { MatFormFieldModule } from '@angular/material/form-field';
import { MatButtonModule } from '@angular/material/button';
import { MatIconModule } from '@angular/material/icon';

@NgModule({
exports: [
Expand All @@ -17,7 +18,8 @@ import { MatButtonModule } from '@angular/material/button';
MatButtonModule,
MatTableModule,
MatPaginatorModule,
MatSortModule
MatSortModule,
MatIconModule
]
})
export class MaterialModule { }
Expand Down
34 changes: 34 additions & 0 deletions src/material.theme.scss
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
@use '@angular/material' as mat;

@include mat.core();

// Define a dark theme
$dark-theme: mat.define-dark-theme((
color: (
primary: mat.define-palette(mat.$pink-palette),
accent: mat.define-palette(mat.$blue-grey-palette),
),
// Only include `typography` and `density` in the default dark theme.
typography: mat.define-typography-config(),
density: 0,
));

// Define a light theme
$light-theme: mat.define-light-theme((
color: (
primary: mat.define-palette(mat.$indigo-palette),
accent: mat.define-palette(mat.$pink-palette),
),
));

// Apply the dark theme by default
// @include mat.core-theme($dark-theme);
// @include mat.button-theme($dark-theme);

// Apply the light theme only when the user prefers light themes.
@media (prefers-color-scheme: light) {
// Use the `-color` mixins to only apply color styles without reapplying the same
// typography and density styles.
@include mat.core-color($light-theme);
@include mat.button-color($light-theme);
}
Loading

0 comments on commit af10f85

Please sign in to comment.