Skip to content

Commit

Permalink
Add Surveys component, update routing, and enhance survey forms
Browse files Browse the repository at this point in the history
  • Loading branch information
austenstone committed Oct 23, 2024
1 parent c441eba commit 2a68272
Show file tree
Hide file tree
Showing 21 changed files with 155 additions and 52 deletions.
2 changes: 1 addition & 1 deletion .github/workflows/backend.yml
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ on:
- main

jobs:
build:
backend-build:
runs-on: ubuntu-latest

steps:
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/docker-compose.yml
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ on:
- main

jobs:
build:
docker-compose-build:
runs-on: ubuntu-latest

steps:
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/frontend.yml
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ on:
- main

jobs:
build:
frontend-build:
runs-on: ubuntu-latest

steps:
Expand Down
35 changes: 9 additions & 26 deletions backend/src/models/survey.model.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,22 +3,11 @@ import sequelize from '../database';

class Survey extends Model {
public id!: number;
public daytime!: Date;
public dateTime!: Date;
public userId!: number;
public usedCopilot!: boolean;
public pctTimesaved!: number;
public percentTimeSaved!: number;
public timeUsedFor!: string;

// Virtual field for time saved
public get timeSaved(): string {
return `${this.pctTimesaved}% saved for ${this.timeUsedFor}`;
}

public set timeSaved(value: string) {
const [pct, ...rest] = value.split(' ');
this.pctTimesaved = parseInt(pct.replace('%', ''), 10);
this.timeUsedFor = rest.join(' ').replace('saved for ', '');
}
}

Survey.init({
Expand All @@ -27,7 +16,7 @@ Survey.init({
autoIncrement: true,
primaryKey: true,
},
daytime: {
dateTime: {
type: DataTypes.DATE,
allowNull: false,
},
Expand All @@ -39,25 +28,19 @@ Survey.init({
type: DataTypes.BOOLEAN,
allowNull: false,
},
pctTimesaved: {
percentTimeSaved: {
type: DataTypes.INTEGER,
allowNull: false,
},
reason: {
type: DataTypes.STRING,
allowNull: true,
},
timeUsedFor: {
type: DataTypes.STRING,
allowNull: false,
},
timeSaved: {
type: DataTypes.VIRTUAL,
get() {
return `${this.getDataValue('pctTimesaved')}% saved for ${this.getDataValue('timeUsedFor')}`;
},
set(value: string) {
const [pct, ...rest] = value.split(' ');
this.setDataValue('pctTimesaved', parseInt(pct.replace('%', ''), 10));
this.setDataValue('timeUsedFor', rest.join(' ').replace('saved for ', ''));
},
},

}, {
sequelize,
modelName: 'Survey',
Expand Down
15 changes: 15 additions & 0 deletions frontend/src/app/app.component.html
Original file line number Diff line number Diff line change
@@ -1 +1,16 @@
<mat-toolbar color="primary">
<a mat-button routerLink="/" routerLinkActive="active-route" [routerLinkActiveOptions]="{exact:
true}">
<mat-icon style="width:24px; height:24px;" svgIcon="github"></mat-icon>
<span>GitHub Value</span>
</a>
<a mat-button routerLink="/surveys" routerLinkActive="active-route">
<mat-icon>assignment</mat-icon>
<span>Surveys</span>
</a>
<span class="example-spacer"></span>
<a mat-icon-button routerLink="/settings" routerLinkActive="active-route">
<mat-icon>settings</mat-icon>
</a>
</mat-toolbar>
<router-outlet />
7 changes: 7 additions & 0 deletions frontend/src/app/app.component.scss
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
.example-spacer {
flex: 1 1 auto;
}

.active-route {
background: #005cbb1a !important;
}
32 changes: 28 additions & 4 deletions frontend/src/app/app.component.ts
Original file line number Diff line number Diff line change
@@ -1,13 +1,37 @@
import { Component } from '@angular/core';
import { RouterOutlet } from '@angular/router';
import { Component, inject } from '@angular/core';
import { RouterLink, RouterModule, RouterOutlet } from '@angular/router';
import { MaterialModule } from './material.module';
import { MatIconRegistry } from '@angular/material/icon';
import { DomSanitizer } from '@angular/platform-browser';
import { AppModule } from './app.module';

const GITHUB_MARK = `
<svg viewBox="0 0 100 100" width="24px" height="24px" xmlns="http://www.w3.org/2000/svg">
<path fill-rule="evenodd" clip-rule="evenodd"
d="M48.854 0C21.839 0 0 22 0 49.217c0 21.756 13.993 40.172 33.405 46.69 2.427.49 3.316-1.059 3.316-2.362 0-1.141-.08-5.052-.08-9.127-13.59 2.934-16.42-5.867-16.42-5.867-2.184-5.704-5.42-7.17-5.42-7.17-4.448-3.015.324-3.015.324-3.015 4.934.326 7.523 5.052 7.523 5.052 4.367 7.496 11.404 5.378 14.235 4.074.404-3.178 1.699-5.378 3.074-6.6-10.839-1.141-22.243-5.378-22.243-24.283 0-5.378 1.94-9.778 5.014-13.2-.485-1.222-2.184-6.275.486-13.038 0 0 4.125-1.304 13.426 5.052a46.97 46.97 0 0 1 12.214-1.63c4.125 0 8.33.571 12.213 1.63 9.302-6.356 13.427-5.052 13.427-5.052 2.67 6.763.97 11.816.485 13.038 3.155 3.422 5.015 7.822 5.015 13.2 0 18.905-11.404 23.06-22.324 24.283 1.78 1.548 3.316 4.481 3.316 9.126 0 6.6-.08 11.897-.08 13.526 0 1.304.89 2.853 3.316 2.364 19.412-6.52 33.405-24.935 33.405-46.691C97.707 22 75.788 0 48.854 0z"
fill="#24292f" />
</svg>
`;

@Component({
selector: 'app-root',
standalone: true,
imports: [RouterOutlet],
imports: [
AppModule,
MaterialModule
],
templateUrl: './app.component.html',
styleUrl: './app.component.scss'
})
export class AppComponent {
title = 'github-value';
title = 'GitHub Value';
iconRegistry: MatIconRegistry;
sanitizer: DomSanitizer;

constructor() {
this.iconRegistry = inject(MatIconRegistry);
this.sanitizer = inject(DomSanitizer);

this.iconRegistry.addSvgIconLiteral('github', this.sanitizer.bypassSecurityTrustHtml(GITHUB_MARK));
}
}
11 changes: 11 additions & 0 deletions frontend/src/app/app.module.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,20 @@
import { NgModule } from '@angular/core';
import { ReactiveFormsModule } from '@angular/forms';
import { MaterialModule } from './material.module';
import { RouterLink, RouterModule, RouterOutlet } from '@angular/router';

@NgModule({
imports: [
RouterOutlet,
RouterLink,
RouterModule,
ReactiveFormsModule,
MaterialModule
],
exports: [
RouterOutlet,
RouterLink,
RouterModule,
ReactiveFormsModule,
MaterialModule
]
Expand Down
4 changes: 3 additions & 1 deletion frontend/src/app/app.routes.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,11 @@
import { Routes } from '@angular/router';
import { CopilotSurveyComponent } from './copilot-survey/copilot-survey.component';
import { CopilotDashboardComponent } from './copilot-dashboard/copilot-dashboard.component';
import { SurveysComponent } from './surveys/surveys.component';

export const routes: Routes = [
{ path: '', component: CopilotDashboardComponent },
{ path: 'copilot-survey', component: CopilotSurveyComponent },
{ path: 'surveys/new', component: CopilotSurveyComponent },
{ path: 'surveys', component: SurveysComponent },
{ path: '**', component: CopilotDashboardComponent }
];
6 changes: 3 additions & 3 deletions frontend/src/app/copilot-survery.service.spec.ts
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
import { TestBed } from '@angular/core/testing';

import { CopilotSurveryService } from './copilot-survery.service';
import { CopilotSurveyService } from './copilot-survery.service';

describe('CopilotSurveryService', () => {
let service: CopilotSurveryService;
let service: CopilotSurveyService;

beforeEach(() => {
TestBed.configureTestingModule({});
service = TestBed.inject(CopilotSurveryService);
service = TestBed.inject(CopilotSurveyService);
});

it('should be created', () => {
Expand Down
4 changes: 2 additions & 2 deletions frontend/src/app/copilot-survery.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import { Survey } from './models/survey';
@Injectable({
providedIn: 'root'
})
export class CopilotSurveryService {
export class CopilotSurveyService {
private apiUrl = `http://${window.location.hostname}:3000/api`; // Adjust the URL based on your backend setup 🌐

constructor(private http: HttpClient) { }
Expand All @@ -15,7 +15,7 @@ export class CopilotSurveryService {
return this.http.post(`${this.apiUrl}/create-survey`, survey);
}

getAllSurveys(): Observable<any[]> {
getAllSurveys(): Observable<Survey[]> {
return this.http.get<any[]>(`${this.apiUrl}/get-survey`);
}

Expand Down
6 changes: 3 additions & 3 deletions frontend/src/app/copilot-survey/copilot-survey.component.html
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
<h1>Copilot Developer Survey</h1>
<h2>Copilot Developer Survey</h2>
<form [formGroup]="surveyForm" (ngSubmit)="onSubmit()">
<label id="example-radio-group-label">Did you use Copilot for this PR?</label>
<mat-radio-group formControlName="usedCopilot" aria-labelledby="example-radio-group-label" class="example-radio-group">
Expand All @@ -8,14 +8,14 @@ <h1>Copilot Developer Survey</h1>
<label id="example-radio-group-label">How much less time did the actual coding take with Copilot?</label>
<p>
<mat-slider class="example-mat-slider" [max]="100" [min]="0" [step]="10" discrete="true" tickInterval="10">
<input matSliderThumb formControlName="pctTimesaved">
<input matSliderThumb formControlName="percentTimeSaved">
</mat-slider>
</p>
<label id="example-radio-group-label">Describe your thought process for calculating (or estimating) the time
saved</label>
<mat-form-field class="example-form-field">
<mat-label>I chose {{surveyForm.get('timeSavingPercentage')?.value}}% because Copilot enabled me to...</mat-label>
<textarea formControlName="timeUsedFor" matInput></textarea>
<textarea formControlName="reason" matInput></textarea>
</mat-form-field>
<label id="example-radio-group-label">Did you use Copilot for this PR?</label>
<mat-radio-group formControlName="timeUsedFor" aria-labelledby="example-radio-group-label" class="example-radio-group">
Expand Down
4 changes: 4 additions & 0 deletions frontend/src/app/copilot-survey/copilot-survey.component.scss
Original file line number Diff line number Diff line change
Expand Up @@ -20,4 +20,8 @@

.example-mat-slider {
width:100%;
}

form {
max-width: 1250px;
}
11 changes: 5 additions & 6 deletions frontend/src/app/copilot-survey/copilot-survey.component.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { Component, forwardRef } from '@angular/core';
import { AppModule } from '../app.module';
import { FormBuilder, FormGroup, NG_VALUE_ACCESSOR } from '@angular/forms';
import { CopilotSurveryService } from '../copilot-survery.service';
import { CopilotSurveyService } from '../copilot-survery.service';
import { provideHttpClient } from '@angular/common/http';

@Component({
Expand All @@ -25,20 +25,19 @@ export class CopilotSurveyComponent {

constructor(
private fb: FormBuilder,
private copilotSurveyService: CopilotSurveryService
private copilotSurveyService: CopilotSurveyService
) {
this.surveyForm = this.fb.group({
usedCopilot: [true],
pctTimesaved: [30],
timeUsedFor: ['writing code'],
timeSaved: ['30 minutes'],
percentTimeSaved: [30],
reason: [''],
timeUsedFor: ['writing code']
});
}

onSubmit() {
console.log(this.surveyForm.value);
this.copilotSurveyService.createSurvey({
id: 0,
daytime: new Date(),
userId: 1,
...this.surveyForm.value
Expand Down
5 changes: 4 additions & 1 deletion frontend/src/app/material.module.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ import { MatTooltipModule } from '@angular/material/tooltip';
import { MatSliderModule } from '@angular/material/slider';
import { MatCardModule } from '@angular/material/card';
import { MatRadioModule } from '@angular/material/radio';
import { MatToolbarModule } from '@angular/material/toolbar';

@NgModule({
exports: [
Expand Down Expand Up @@ -54,7 +55,9 @@ import { MatRadioModule } from '@angular/material/radio';
MatInputModule,
FormsModule,
MatCardModule,
MatRadioModule
MatRadioModule,
MatIconModule,
MatToolbarModule
]
})
export class MaterialModule { }
Expand Down
4 changes: 2 additions & 2 deletions frontend/src/app/models/survey.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ export interface Survey {
daytime: Date;
userId: number;
usedCopilot: boolean;
pctTimesaved: number;
percentTimeSaved: number;
reason: string;
timeUsedFor: string;
timeSaved: string;
}
2 changes: 2 additions & 0 deletions frontend/src/app/surveys/surveys.component.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
<a mat-raised-button color="primary" routerLink="/surveys/new">New Survey</a>

Empty file.
23 changes: 23 additions & 0 deletions frontend/src/app/surveys/surveys.component.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
import { ComponentFixture, TestBed } from '@angular/core/testing';

import { SurveysComponent } from './surveys.component';

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

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

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

it('should create', () => {
expect(component).toBeTruthy();
});
});
30 changes: 30 additions & 0 deletions frontend/src/app/surveys/surveys.component.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
import { Component } from '@angular/core';
import { MaterialModule } from '../material.module';
import { AppModule } from '../app.module';
import { CopilotSurveyService as CopilotSurveyService } from '../copilot-survery.service';
import { Survey } from '../models/survey';

@Component({
selector: 'app-surveys',
standalone: true,
imports: [
AppModule,
MaterialModule
],
templateUrl: './surveys.component.html',
styleUrl: './surveys.component.scss'
})
export class SurveysComponent {
surveys: Survey[] = [];

constructor(
private copilotSurveyService: CopilotSurveyService
) { }

ngOnInit() {
this.copilotSurveyService.getAllSurveys().subscribe((surveys) => {
console.log(surveys);
this.surveys = surveys;
});
}
}
2 changes: 1 addition & 1 deletion frontend/src/styles.scss
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ $github-value-theme: mat.define-theme((

// Comment out the line below if you want to use the pre-defined typography utility classes.
// For more information: https://material.angular.io/guide/typography#using-typography-styles-in-your-application.
// @include mat.typography-hierarchy($github-value-theme);
@include mat.typography-hierarchy($github-value-theme);

// Comment out the line below if you want to use the deprecated `color` inputs.
// @include mat.color-variants-backwards-compatibility($github-value-theme);
Expand Down

0 comments on commit 2a68272

Please sign in to comment.