From 422d3e11b7a6da527cf447f2b01c9904f7f31314 Mon Sep 17 00:00:00 2001 From: Scott Berg <saberg3@wisc.edu> Date: Mon, 19 Aug 2019 13:41:08 -0500 Subject: [PATCH] Add audit symbol component. --- .../audit-legend/audit-legend.component.html | 68 ++------- .../audit-legend/audit-legend.component.scss | 8 ++ .../audit-legend/audit-legend.component.ts | 134 ++++++++---------- .../audit-symbol/audit-symbol.component.html | 8 ++ .../audit-symbol/audit-symbol.component.scss | 15 ++ .../audit-symbol/audit-symbol.component.ts | 18 +++ src/app/dars/audit/audit.component.html | 20 ++- src/app/dars/audit/audit.component.scss | 16 +-- src/app/dars/dars.module.ts | 2 + src/app/dars/models/audit-symbols.ts | 22 +-- .../dars/pipes/requirement-symbols.pipe.ts | 16 +-- 11 files changed, 157 insertions(+), 170 deletions(-) create mode 100644 src/app/dars/audit-symbol/audit-symbol.component.html create mode 100644 src/app/dars/audit-symbol/audit-symbol.component.scss create mode 100644 src/app/dars/audit-symbol/audit-symbol.component.ts diff --git a/src/app/dars/audit-legend/audit-legend.component.html b/src/app/dars/audit-legend/audit-legend.component.html index fcd5820..9108b59 100644 --- a/src/app/dars/audit-legend/audit-legend.component.html +++ b/src/app/dars/audit-legend/audit-legend.component.html @@ -1,69 +1,19 @@ <section id="audit-legend"> - <!-- COURSE SYMBOLS TABLE --> - <table mat-table [dataSource]="auditCourseSymbols"> - <caption>Course Symbols</caption> - <tr mat-header-row *matHeaderRowDef="auditCourseColumns"></tr> - <tr mat-row *matRowDef="let row; columns: auditCourseColumns;"></tr> - - <ng-container matColumnDef="symbol"> - <th mat-header-cell *matHeaderCellDef scope="col">Symbol</th> - <td mat-cell *matCellDef="let legend">{{ legend.symbol }}</td> - </ng-container> - - <ng-container matColumnDef="description"> - <th mat-header-cell *matHeaderCellDef scope="col">Description</th> - <td mat-cell *matCellDef="let legend">{{ legend.description }}</td> - </ng-container> - </table> - - <!-- GRADE SYMBOLS TABLE --> - <table mat-table [dataSource]="auditGradeSymbols"> - <caption>Grade Symbols</caption> - <tr mat-header-row *matHeaderRowDef="auditCourseColumns"></tr> - <tr mat-row *matRowDef="let row; columns: auditCourseColumns;"></tr> - - <ng-container matColumnDef="symbol"> - <th mat-header-cell *matHeaderCellDef scope="col">Symbol</th> - <td mat-cell *matCellDef="let legend">{{ legend.symbol }}</td> - </ng-container> - - <ng-container matColumnDef="description"> - <th mat-header-cell *matHeaderCellDef scope="col">Description</th> - <td mat-cell *matCellDef="let legend">{{ legend.description }}</td> - </ng-container> - </table> - - <!-- REQUIREMENT INFO TABLE --> - <table mat-table [dataSource]="auditReqInformation"> - <caption>Requirement / Sub-requirement Information</caption> - <tr mat-header-row *matHeaderRowDef="auditCourseColumns"></tr> - <tr mat-row *matRowDef="let row; columns: auditCourseColumns;"></tr> - - <ng-container matColumnDef="symbol"> - <th mat-header-cell *matHeaderCellDef scope="col">Symbol</th> - <td mat-cell *matCellDef="let legend">{{ legend.symbol }}</td> - </ng-container> - - <ng-container matColumnDef="description"> - <th mat-header-cell *matHeaderCellDef scope="col">Description</th> - <td mat-cell *matCellDef="let legend">{{ legend.description }}</td> - </ng-container> - </table> - - <!-- Audit Exception SYMBOLS TABLE --> - <table mat-table [dataSource]="auditExceptionSymbols"> - <caption>Exception Symbols</caption> + <table *ngFor="let legend of legends" mat-table [dataSource]="legend.symbols"> + <caption>{{legend.title}}</caption> <tr mat-header-row *matHeaderRowDef="auditCourseColumns"></tr> <tr mat-row *matRowDef="let row; columns: auditCourseColumns;"></tr> - + <ng-container matColumnDef="symbol"> <th mat-header-cell *matHeaderCellDef scope="col">Symbol</th> - <td mat-cell *matCellDef="let legend">{{ legend.symbol }}</td> + <td mat-cell *matCellDef="let symbol"> + <cse-audit-symbol [symbol]="symbol" [disableTooltip]="true" class="{{symbol.slug}}"></cse-audit-symbol> + </td> </ng-container> - + <ng-container matColumnDef="description"> <th mat-header-cell *matHeaderCellDef scope="col">Description</th> - <td mat-cell *matCellDef="let legend">{{ legend.description }}</td> + <td mat-cell *matCellDef="let symbol">{{ symbol.tooltip }}</td> </ng-container> - </table> + </table> </section> \ No newline at end of file diff --git a/src/app/dars/audit-legend/audit-legend.component.scss b/src/app/dars/audit-legend/audit-legend.component.scss index d74aaaa..fad893b 100644 --- a/src/app/dars/audit-legend/audit-legend.component.scss +++ b/src/app/dars/audit-legend/audit-legend.component.scss @@ -4,3 +4,11 @@ margin-bottom: 2em; } } + +.complete-sub { + color: #2e7d32; +} + +.not-complete-sub { + color: #c5050c; +} diff --git a/src/app/dars/audit-legend/audit-legend.component.ts b/src/app/dars/audit-legend/audit-legend.component.ts index 4b2a10f..6a20ee7 100644 --- a/src/app/dars/audit-legend/audit-legend.component.ts +++ b/src/app/dars/audit-legend/audit-legend.component.ts @@ -1,4 +1,5 @@ import { Component } from '@angular/core'; +import { AuditSymbol } from '../models/audit-symbols'; @Component({ selector: 'cse-audit-legend', @@ -7,88 +8,69 @@ import { Component } from '@angular/core'; }) export class AuditLegendComponent { public auditCourseColumns: string[] = ['symbol', 'description']; - public auditCourseSymbols: { symbol: string; description: string }[] = [ - { symbol: '>D', description: 'Duplicate course - retains GPA effect' }, - { symbol: '>R', description: 'Repeatable course' }, - { symbol: '>S', description: 'Credit split between requirements' }, + public legends: { title: string, symbols: AuditSymbol[] }[] = [ { - symbol: '>X', - description: 'Repeated course - no course credit or GPA effect', - }, - { symbol: '(R)', description: 'Required course' }, - { symbol: '(X)', description: 'Original course value' }, - ]; - - public auditGradeSymbols: { symbol: string; description: string }[] = [ - { symbol: 'EIP', description: 'Extended incomplete' }, - { symbol: 'CR', description: 'Credit (credit/no credit courses)' }, - { symbol: 'HS', description: 'High school unit' }, - { symbol: 'IN', description: 'Incomplete (credit/no credit courses)' }, - { symbol: 'INP', description: 'In-progress course (current term)' }, - { symbol: 'IP', description: 'Incomplete' }, - { symbol: 'N', description: 'No credit (credit/no credit courses)' }, - { symbol: 'NR', description: 'Not reported' }, - { symbol: 'NW', description: 'No work' }, - { symbol: 'PL', description: 'Planned course' }, - { symbol: 'PP', description: 'Progress' }, - { symbol: 'PS', description: 'Mock/pseudo course' }, - { symbol: 'Q', description: 'Question on credits or honors' }, - { symbol: 'S', description: 'Satisfactory (pass/fail and audit courses)' }, - { symbol: 'T', description: 'Transfer/test/advanced standing course' }, - { symbol: 'U', description: 'Unsatisfactory (pass/fail courses)' }, - ]; - - public auditReqInformation: { symbol: string; description: string }[] = [ - { symbol: 'OK', description: 'Requirement complete' }, - { symbol: 'NO', description: 'Requirement not complete' }, - { - symbol: 'IP', - description: 'Requirement uses in-progress credit/courses', - }, - { - symbol: 'IN-P', - description: 'Sub-requirement uses in progress credit/courses', + title: 'Course Symbols', + symbols: [ + { type: 'text', text: '>D', tooltip: 'Duplicate course - retains GPA effect' }, + { type: 'text', text: '>R', tooltip: 'Repeatable course' }, + { type: 'text', text: '>S', tooltip: 'Credit split between requirements' }, + { type: 'text', text: '>R', tooltip: 'Repeatable course' }, + { type: 'text', text: '(R)', tooltip: 'Required course' }, + { type: 'text', text: '(X)', tooltip: 'Original course value' }, + ] }, { - symbol: 'PL', - description: 'Requirement/sub-requirement uses planned course', + title: 'Grade Symbols', + symbols: [ + { type: 'text', text: 'EIP', tooltip: 'Extended incomplete' }, + { type: 'text', text: 'CR', tooltip: 'Credit (credit/no credit courses)' }, + { type: 'text', text: 'HS', tooltip: 'High school unit' }, + { type: 'text', text: 'IN', tooltip: 'Incomplete (credit/no credit courses)' }, + { type: 'text', text: 'INP', tooltip: 'In-progress course (current term)' }, + { type: 'text', text: 'IP', tooltip: 'Incomplete' }, + { type: 'text', text: 'N', tooltip: 'No credit (credit/no credit courses)' }, + { type: 'text', text: 'NR', tooltip: 'Not reported' }, + { type: 'text', text: 'NW', tooltip: 'No work' }, + { type: 'text', text: 'PL', tooltip: 'Planned course' }, + { type: 'text', text: 'PP', tooltip: 'Progress' }, + { type: 'text', text: 'PS', tooltip: 'Mock/pseudo course' }, + { type: 'text', text: 'Q', tooltip: 'Question on credits or honors' }, + { type: 'text', text: 'S', tooltip: 'Satisfactory (pass/fail and audit courses)' }, + { type: 'text', text: 'T', tooltip: 'Transfer/test/advanced standing course' }, + { type: 'text', text: 'U', tooltip: 'Unsatisfactory (pass/fail courses)' }, + ] }, - { symbol: 'R', description: 'Required sub-requirement (mandatory)' }, { - symbol: '<>', - description: "Optional/other requirement in OR'd set complete", + title: 'Requirement / Sub-requirement Information', + symbols: [ + { type: 'text', text: 'OK', tooltip: 'Requirement complete' }, + { type: 'text', text: 'NO', tooltip: 'Requirement not complete' }, + { type: 'text', text: 'IP', tooltip: 'Requirement uses in-progress credit/courses' }, + { type: 'text', text: 'IN-P', tooltip: 'Sub-requirement uses in progress credit/courses' }, + { type: 'text', text: 'PL', tooltip: 'Requirement/sub-requirement uses planned course' }, + { type: 'text', text: 'R', tooltip: 'Required sub-requirement (mandatory)' }, + { type: 'text', text: '<>', tooltip: 'Optional/other requirement in OR\'d set complete' }, + { type: 'icon', text: '+', icon: 'check', tooltip: 'Sub-requirement complete', slug: 'complete-sub' }, + { type: 'icon', text: '-', icon: 'close', tooltip: 'Sub-requirement not complete', slug: 'not-complete-sub' }, + { type: 'text', text: '*', tooltip: 'Optional sub-requirement, courses assigned' }, + { type: 'text', text: ' ', tooltip: 'Optional sub-requirement, no courses assigned' }, + ] }, - { symbol: '+', description: 'Sub-requirement complete' }, - { symbol: '-', description: 'Sub-requirement not complete' }, - { symbol: '*', description: 'Optional sub-requirement, courses assigned' }, { - symbol: ' ', - description: 'Optional sub-requirement, no courses assigned', - }, - ]; - - public auditExceptionSymbols: { symbol: string; description: string }[] = [ - { - symbol: 'AC', - description: 'Course approved for requirement/sub-requirement', - }, - { - symbol: 'IC', - description: 'Course inserted into requirement/sub-requirement', - }, - { symbol: 'EC', description: 'Course exchanged for specified course' }, - { - symbol: 'FC', - description: 'Course forced into requirement/sub-requirement', - }, - { symbol: 'CM', description: 'Course modified' }, - { symbol: 'CY', description: 'Catalog year modified' }, - { - symbol: 'DC', - description: 'Course deleted from requirement/sub-requirement', - }, - { symbol: 'RM', description: 'Requirement modified' }, - { symbol: 'WC', description: 'Waive course' }, - { symbol: 'WP', description: 'Waive mock/pseudo course' }, + title: 'Exception Symbols', + symbols: [ + { type: 'text', text: 'AC', tooltip: 'Course approved for requirement/sub-requirement', }, + { type: 'text', text: 'IC', tooltip: 'Course inserted into requirement/sub-requirement', }, + { type: 'text', text: 'EC', tooltip: 'Course exchanged for specified course' }, + { type: 'text', text: 'FC', tooltip: 'Course forced into requirement/sub-requirement', }, + { type: 'text', text: 'CM', tooltip: 'Course modified' }, + { type: 'text', text: 'CY', tooltip: 'Catalog year modified' }, + { type: 'text', text: 'DC', tooltip: 'Course deleted from requirement/sub-requirement', }, + { type: 'text', text: 'RM', tooltip: 'Requirement modified' }, + { type: 'text', text: 'WC', tooltip: 'Waive course' }, + { type: 'text', text: 'WP', tooltip: 'Waive mock/pseudo course' }, + ] + } ]; } diff --git a/src/app/dars/audit-symbol/audit-symbol.component.html b/src/app/dars/audit-symbol/audit-symbol.component.html new file mode 100644 index 0000000..7929e70 --- /dev/null +++ b/src/app/dars/audit-symbol/audit-symbol.component.html @@ -0,0 +1,8 @@ +<div + class="audit-symbol-wrapper" + [matTooltip]="symbol.tooltip" + matTooltipPosition="above" + [matTooltipDisabled]="!symbol.tooltip || disableTooltip"> + <span *ngIf="symbol.type === 'text'">{{symbol.text}}</span> + <mat-icon *ngIf="symbol.type === 'icon'" class="material-icons audit-symbol audit-symbol-{{asIcon(symbol).icon}}">{{asIcon(symbol).icon}}</mat-icon> +</div> \ No newline at end of file diff --git a/src/app/dars/audit-symbol/audit-symbol.component.scss b/src/app/dars/audit-symbol/audit-symbol.component.scss new file mode 100644 index 0000000..30519ff --- /dev/null +++ b/src/app/dars/audit-symbol/audit-symbol.component.scss @@ -0,0 +1,15 @@ +.audit-symbol-wrapper { + display: inline-block; +} + +span { + position: relative; + display: block; + padding-right: 5px; + color: inherit; +} + +mat-icon { + margin-top: 4px; + color: inherit; +} diff --git a/src/app/dars/audit-symbol/audit-symbol.component.ts b/src/app/dars/audit-symbol/audit-symbol.component.ts new file mode 100644 index 0000000..96c1445 --- /dev/null +++ b/src/app/dars/audit-symbol/audit-symbol.component.ts @@ -0,0 +1,18 @@ +import { Component, Input, OnInit, ViewChild } from '@angular/core'; +import { AuditSymbol, AuditIconSymbol } from '../models/audit-symbols'; + +@Component({ + selector: 'cse-audit-symbol', + templateUrl: './audit-symbol.component.html', + styleUrls: ['./audit-symbol.component.scss'] +}) +export class AuditSymbolComponent { + @Input() symbol: AuditSymbol; + @Input() disableTooltip?: boolean; + + // Used to typecast because ng-switch is dumb + asIcon(symbol: AuditSymbol): AuditIconSymbol { + return symbol as AuditIconSymbol; + } + +} diff --git a/src/app/dars/audit/audit.component.html b/src/app/dars/audit/audit.component.html index 1268515..8a0e912 100644 --- a/src/app/dars/audit/audit.component.html +++ b/src/app/dars/audit/audit.component.html @@ -194,14 +194,11 @@ <div class="subrequirement-status-wrapper"> <p *ngIf="reqBody.contentType === 'okSubrequirementTLine' || reqBody.contentType === 'noSubrequirementTLine'"> - <ng-container *ngFor="let symbol of asLineBody(reqBody).lines | requirementSymbols"> - <ng-container [ngSwitch]="symbol.type"> - <span *ngSwitchCase="'text'" [matTooltip]="symbol.tooltip" matTooltipPosition="above">{{symbol.text}}</span> - <span *ngSwitchCase="'icon'" class="{{symbol.icon}}"> - <mat-icon [matTooltip]="symbol.tooltip" matTooltipPosition="above">{{symbol.icon}}</mat-icon> - </span> - </ng-container> - </ng-container> + <cse-audit-symbol + *ngFor="let symbol of asLineBody(reqBody).lines | requirementSymbols" + class="{{symbol.slug}}" + [symbol]="symbol" + ></cse-audit-symbol> </p> </div> @@ -241,9 +238,10 @@ <ng-container matColumnDef="note"> <th mat-header-cell *matHeaderCellDef scope="col">Course Note</th> <td mat-cell *matCellDef="let course"> - <span *ngFor="let note of course.courseNote | courseNote" [matTooltip]="note.tooltip" matTooltipPosition="above"> - {{note.text}} - </span> + <cse-audit-symbol + *ngFor="let symbol of course.courseNote | courseNote" + [symbol]="symbol" + ></cse-audit-symbol> </td> </ng-container> </table> diff --git a/src/app/dars/audit/audit.component.scss b/src/app/dars/audit/audit.component.scss index 6843d0f..60a5efa 100644 --- a/src/app/dars/audit/audit.component.scss +++ b/src/app/dars/audit/audit.component.scss @@ -202,19 +202,19 @@ $black: #000000; position: relative; display: block; padding-right: 5px; - - &.close { - color: $red; - } - - &.check { - color: $green; - } } mat-icon { margin-top: 3px; } + + .complete-sub { + color: $green; + } + + .not-complete-sub { + color: $red; + } } .subrequirement-content-wrapper { diff --git a/src/app/dars/dars.module.ts b/src/app/dars/dars.module.ts index c4fe778..328732d 100644 --- a/src/app/dars/dars.module.ts +++ b/src/app/dars/dars.module.ts @@ -22,6 +22,7 @@ import { NewDegreeAuditDialogComponent } from './new-degree-audit-dialog/new-deg import { NewWhatIfAuditDialogComponent } from './new-what-if-audit-dialog/new-what-if-audit-dialog.component'; import { AuditViewComponent } from './dars-audit-view/dars-audit-view.component'; import { RouterModule } from '@angular/router'; +import { AuditSymbolComponent } from './audit-symbol/audit-symbol.component'; @NgModule({ imports: [ @@ -48,6 +49,7 @@ import { RouterModule } from '@angular/router'; AuditLegendComponent, DarsMetadataTableComponent, MetadataMobileViewComponent, + AuditSymbolComponent, ], entryComponents: [ NewDegreeAuditDialogComponent, diff --git a/src/app/dars/models/audit-symbols.ts b/src/app/dars/models/audit-symbols.ts index b5d98e2..2fb5c9d 100644 --- a/src/app/dars/models/audit-symbols.ts +++ b/src/app/dars/models/audit-symbols.ts @@ -1,14 +1,20 @@ export type AuditSymbol = AuditIconSymbol | AuditTextSymbol; -interface AuditIconSymbol { - type: 'icon'; +/** + * type: If the symbol should be plain text or a mat-icon. + * text: The original text of the symbol, will be used for find / replaces. + * icon: (type "icon" only) the text of the mat-icon. + * tooltip: The text to be displayed as the tooltip. + * slug: Text based identifier for the symbol. Used for createing class names. + */ +export interface AuditTextSymbol { + type: 'text' | 'icon'; text: string; - tooltip: string; - icon: string; + tooltip?: string; + slug?: string; } -interface AuditTextSymbol { - type: 'text'; - text: string; - tooltip: string; +export interface AuditIconSymbol extends AuditTextSymbol { + type: 'icon'; + icon: string; } diff --git a/src/app/dars/pipes/requirement-symbols.pipe.ts b/src/app/dars/pipes/requirement-symbols.pipe.ts index b0248c5..e52ba61 100644 --- a/src/app/dars/pipes/requirement-symbols.pipe.ts +++ b/src/app/dars/pipes/requirement-symbols.pipe.ts @@ -7,14 +7,14 @@ export class RequirementSymbolsPipe implements PipeTransform { const singleLine = lines.join(' ').trim(); const matches = singleLine.match(/^((IP)|(IN-P)|(PL)|(R)|(<>)|\+|\-|\*)+/g); const symbols: AuditSymbol[] = [ - { type: 'text', text: 'IP', tooltip: 'Requirement uses in-progress credit/courses' }, - { type: 'text', text: 'IN-P', tooltip: 'Sub-requirement uses in progress credit/courses' }, - { type: 'text', text: 'PL', tooltip: 'Requirement/sub-requirement uses planned course' }, - { type: 'text', text: 'R', tooltip: 'Required sub-requirement (mandatory)' }, - { type: 'text', text: '<>', tooltip: 'Optional/other requirement in OR\'d set complete' }, - { type: 'text', text: '*', tooltip: 'Optional sub-requirement, courses assigned' }, - { type: 'icon', text: '+', icon: 'check', tooltip: 'Sub-requirement complete' }, - { type: 'icon', text: '-', icon: 'close', tooltip: 'Sub-requirement not complete' } + { type: 'text', text: 'IP', tooltip: 'Requirement uses in-progress credit/courses', slug: 'in-progress' }, + { type: 'text', text: 'IN-P', tooltip: 'Sub-requirement uses in progress credit/courses', slug: 'in-progress-sub' }, + { type: 'text', text: 'PL', tooltip: 'Requirement/sub-requirement uses planned course', slug: 'planned' }, + { type: 'text', text: 'R', tooltip: 'Required sub-requirement (mandatory)', slug: 'required' }, + { type: 'text', text: '<>', tooltip: 'Optional/other requirement in OR\'d set complete', slug: 'optional' }, + { type: 'text', text: '*', tooltip: 'Optional sub-requirement, courses assigned', slug: 'optional-sub' }, + { type: 'icon', text: '+', icon: 'check', tooltip: 'Sub-requirement complete', slug: 'complete-sub' }, + { type: 'icon', text: '-', icon: 'close', tooltip: 'Sub-requirement not complete', slug: 'not-complete-sub' } ]; if (matches && matches.length > 0) { -- GitLab