mirror of
https://github.com/opelly27/WinStudentGoalTracker.git
synced 2026-05-20 02:57:36 +00:00
Added short name to benchmarks
This commit is contained in:
@@ -551,7 +551,7 @@ public class StudentController : BaseController
|
||||
});
|
||||
}
|
||||
|
||||
var updated = await _studentRepository.UpdateBenchmarkAsync(idBenchmark, dto.Benchmark);
|
||||
var updated = await _studentRepository.UpdateBenchmarkAsync(idBenchmark, dto);
|
||||
|
||||
return Ok(new ResponseResult<object>
|
||||
{
|
||||
|
||||
@@ -4,4 +4,5 @@ public class CreateBenchmarkDto
|
||||
{
|
||||
public Guid GoalId { get; set; }
|
||||
public string Benchmark { get; set; } = string.Empty;
|
||||
public string? ShortName { get; set; }
|
||||
}
|
||||
|
||||
@@ -3,4 +3,5 @@ namespace WinStudentGoalTracker.DataAccess;
|
||||
public class UpdateBenchmarkDto
|
||||
{
|
||||
public string Benchmark { get; set; } = string.Empty;
|
||||
public string? ShortName { get; set; }
|
||||
}
|
||||
|
||||
@@ -7,6 +7,7 @@ public class dbStudentBenchmarkRow
|
||||
public required Guid GoalId { get; set; }
|
||||
public string? GoalCategory { get; set; }
|
||||
public string? Benchmark { get; set; }
|
||||
public string? ShortName { get; set; }
|
||||
public string? CreatedByName { get; set; }
|
||||
public DateTime CreatedAt { get; set; }
|
||||
public DateTime? UpdatedAt { get; set; }
|
||||
|
||||
@@ -256,6 +256,7 @@ public class StudentRepository
|
||||
GoalId = r.GoalId,
|
||||
GoalCategory = r.GoalCategory,
|
||||
Benchmark = r.Benchmark,
|
||||
ShortName = r.ShortName,
|
||||
CreatedByName = r.CreatedByName,
|
||||
CreatedAt = r.CreatedAt,
|
||||
UpdatedAt = r.UpdatedAt
|
||||
@@ -277,7 +278,8 @@ public class StudentRepository
|
||||
p_id_benchmark = newId.ToString(),
|
||||
p_id_goal = goalId.ToString(),
|
||||
p_id_user_created = userId.ToString(),
|
||||
p_benchmark = dto.Benchmark
|
||||
p_benchmark = dto.Benchmark,
|
||||
p_short_name = dto.ShortName
|
||||
},
|
||||
commandType: CommandType.StoredProcedure);
|
||||
|
||||
@@ -288,6 +290,7 @@ public class StudentRepository
|
||||
BenchmarkId = newId,
|
||||
GoalId = goalId,
|
||||
Benchmark = dto.Benchmark,
|
||||
ShortName = dto.ShortName,
|
||||
CreatedAt = DateTime.UtcNow
|
||||
};
|
||||
}
|
||||
@@ -295,7 +298,7 @@ public class StudentRepository
|
||||
// *****************************************************************
|
||||
// Updates a benchmark's text and returns whether rows were affected.
|
||||
// *****************************************************************
|
||||
public async Task<bool> UpdateBenchmarkAsync(Guid benchmarkId, string benchmarkText)
|
||||
public async Task<bool> UpdateBenchmarkAsync(Guid benchmarkId, UpdateBenchmarkDto dto)
|
||||
{
|
||||
using var db = Connection;
|
||||
var rowsAffected = await db.ExecuteScalarAsync<int>(
|
||||
@@ -303,7 +306,8 @@ public class StudentRepository
|
||||
new
|
||||
{
|
||||
p_id_benchmark = benchmarkId.ToString(),
|
||||
p_benchmark = benchmarkText
|
||||
p_benchmark = dto.Benchmark,
|
||||
p_short_name = dto.ShortName
|
||||
},
|
||||
commandType: CommandType.StoredProcedure);
|
||||
return rowsAffected > 0;
|
||||
|
||||
@@ -6,6 +6,7 @@ public class StudentBenchmarkItem
|
||||
public Guid GoalId { get; set; }
|
||||
public string? GoalCategory { get; set; }
|
||||
public string? Benchmark { get; set; }
|
||||
public string? ShortName { get; set; }
|
||||
public string? CreatedByName { get; set; }
|
||||
public DateTime CreatedAt { get; set; }
|
||||
public DateTime? UpdatedAt { get; set; }
|
||||
|
||||
@@ -0,0 +1,94 @@
|
||||
-- =====================================================================
|
||||
-- Migration: Add short_name column to benchmark table and update
|
||||
-- all benchmark stored procedures to support it.
|
||||
-- Run in TablePlus against MySQL.
|
||||
-- =====================================================================
|
||||
|
||||
-- 1. Add the column
|
||||
ALTER TABLE `benchmark`
|
||||
ADD COLUMN `short_name` VARCHAR(50) DEFAULT NULL AFTER `benchmark`;
|
||||
|
||||
|
||||
-- 2. Recreate sp_Benchmark_GetByStudentId
|
||||
DROP PROCEDURE IF EXISTS `sp_Benchmark_GetByStudentId`;
|
||||
CREATE PROCEDURE `sp_Benchmark_GetByStudentId`(IN p_id_student CHAR(36))
|
||||
BEGIN
|
||||
SELECT
|
||||
s.`identifier` AS `studentIdentifier`,
|
||||
b.`id_benchmark` AS `benchmarkId`,
|
||||
b.`id_goal` AS `goalId`,
|
||||
g.`category` AS `goalCategory`,
|
||||
b.`benchmark` AS `benchmark`,
|
||||
b.`short_name` AS `shortName`,
|
||||
u.`name` AS `createdByName`,
|
||||
b.`created_at` AS `createdAt`,
|
||||
b.`updated_at` AS `updatedAt`
|
||||
FROM `benchmark` b
|
||||
INNER JOIN `goal` g ON g.`id_goal` = b.`id_goal`
|
||||
INNER JOIN `student` s ON s.`id_student` = g.`id_student`
|
||||
LEFT JOIN `user` u ON u.`id_user` = b.`id_user_created`
|
||||
WHERE g.`id_student` = p_id_student
|
||||
ORDER BY b.`created_at` DESC;
|
||||
END;
|
||||
|
||||
|
||||
-- 3. Recreate sp_Benchmark_Insert
|
||||
DROP PROCEDURE IF EXISTS `sp_Benchmark_Insert`;
|
||||
CREATE PROCEDURE `sp_Benchmark_Insert`(
|
||||
IN p_id_benchmark CHAR(36),
|
||||
IN p_id_goal CHAR(36),
|
||||
IN p_id_user_created CHAR(36),
|
||||
IN p_benchmark TEXT,
|
||||
IN p_short_name VARCHAR(50)
|
||||
)
|
||||
BEGIN
|
||||
INSERT INTO benchmark
|
||||
(
|
||||
id_benchmark,
|
||||
id_goal,
|
||||
id_user_created,
|
||||
benchmark,
|
||||
short_name,
|
||||
created_at,
|
||||
updated_at
|
||||
)
|
||||
VALUES
|
||||
(
|
||||
p_id_benchmark,
|
||||
p_id_goal,
|
||||
p_id_user_created,
|
||||
p_benchmark,
|
||||
p_short_name,
|
||||
UTC_TIMESTAMP(),
|
||||
NULL
|
||||
);
|
||||
SELECT
|
||||
id_benchmark,
|
||||
id_goal,
|
||||
id_user_created,
|
||||
benchmark,
|
||||
short_name,
|
||||
created_at,
|
||||
updated_at
|
||||
FROM benchmark
|
||||
WHERE id_benchmark = p_id_benchmark
|
||||
LIMIT 1;
|
||||
END;
|
||||
|
||||
|
||||
-- 4. Recreate sp_Benchmark_Update
|
||||
DROP PROCEDURE IF EXISTS `sp_Benchmark_Update`;
|
||||
CREATE PROCEDURE `sp_Benchmark_Update`(
|
||||
IN p_id_benchmark CHAR(36),
|
||||
IN p_benchmark TEXT,
|
||||
IN p_short_name VARCHAR(50)
|
||||
)
|
||||
BEGIN
|
||||
UPDATE benchmark
|
||||
SET
|
||||
benchmark = p_benchmark,
|
||||
short_name = p_short_name,
|
||||
updated_at = UTC_TIMESTAMP()
|
||||
WHERE id_benchmark = p_id_benchmark;
|
||||
SELECT ROW_COUNT() AS rowsAffected;
|
||||
END;
|
||||
@@ -7,6 +7,7 @@ BEGIN
|
||||
b.`id_goal` AS `goalId`,
|
||||
g.`category` AS `goalCategory`,
|
||||
b.`benchmark` AS `benchmark`,
|
||||
b.`short_name` AS `shortName`,
|
||||
u.`name` AS `createdByName`,
|
||||
b.`created_at` AS `createdAt`,
|
||||
b.`updated_at` AS `updatedAt`
|
||||
|
||||
@@ -3,7 +3,8 @@ CREATE DEFINER=`root`@`%` PROCEDURE `sp_Benchmark_Insert`(
|
||||
IN p_id_benchmark CHAR(36),
|
||||
IN p_id_goal CHAR(36),
|
||||
IN p_id_user_created CHAR(36),
|
||||
IN p_benchmark TEXT
|
||||
IN p_benchmark TEXT,
|
||||
IN p_short_name VARCHAR(50)
|
||||
)
|
||||
BEGIN
|
||||
INSERT INTO benchmark
|
||||
@@ -12,6 +13,7 @@ BEGIN
|
||||
id_goal,
|
||||
id_user_created,
|
||||
benchmark,
|
||||
short_name,
|
||||
created_at,
|
||||
updated_at
|
||||
)
|
||||
@@ -21,6 +23,7 @@ BEGIN
|
||||
p_id_goal,
|
||||
p_id_user_created,
|
||||
p_benchmark,
|
||||
p_short_name,
|
||||
UTC_TIMESTAMP(),
|
||||
NULL
|
||||
);
|
||||
@@ -29,6 +32,7 @@ BEGIN
|
||||
id_goal,
|
||||
id_user_created,
|
||||
benchmark,
|
||||
short_name,
|
||||
created_at,
|
||||
updated_at
|
||||
FROM benchmark
|
||||
|
||||
@@ -1,12 +1,14 @@
|
||||
DELIMITER ;;
|
||||
CREATE DEFINER=`root`@`%` PROCEDURE `sp_Benchmark_Update`(
|
||||
IN p_id_benchmark CHAR(36),
|
||||
IN p_benchmark TEXT
|
||||
IN p_benchmark TEXT,
|
||||
IN p_short_name VARCHAR(50)
|
||||
)
|
||||
BEGIN
|
||||
UPDATE benchmark
|
||||
SET
|
||||
benchmark = p_benchmark,
|
||||
short_name = p_short_name,
|
||||
updated_at = UTC_TIMESTAMP()
|
||||
WHERE id_benchmark = p_id_benchmark;
|
||||
SELECT ROW_COUNT() AS rowsAffected;
|
||||
|
||||
@@ -3,6 +3,7 @@ CREATE TABLE `benchmark` (
|
||||
`id_goal` char(36) NOT NULL,
|
||||
`id_user_created` char(36) NOT NULL,
|
||||
`benchmark` text NOT NULL,
|
||||
`short_name` varchar(50) DEFAULT NULL,
|
||||
`created_at` datetime NOT NULL,
|
||||
`updated_at` datetime DEFAULT NULL,
|
||||
PRIMARY KEY (`id_benchmark`)
|
||||
|
||||
@@ -1,7 +1,9 @@
|
||||
CREATE ALGORITHM=UNDEFINED DEFINER=`root`@`%` SQL SECURITY DEFINER VIEW `winstudentgoaltracker`.`v_student_card` AS
|
||||
select `s`.`id_student` AS `studentId`,`s`.`identifier` AS `identifier`,`s`.`next_iep_date` AS `nextIepDate`,max(`pe`.`created_at`) AS `lastEntryDate`,count(distinct `g`.`id_goal`) AS `goalCount`,count(distinct `pe`.`id_progress_event`) AS `progressEventCount`
|
||||
from ((`winstudentgoaltracker`.`student` `s`
|
||||
select `s`.`id_student` AS `studentId`,`s`.`identifier` AS `identifier`,`s`.`next_iep_date` AS `nextIepDate`,max(`pe`.`created_at`) AS `lastEntryDate`,count(distinct `g`.`id_goal`) AS `goalCount`,count(distinct `pe`.`id_progress_event`) AS `progressEventCount`,count(distinct `b`.`id_benchmark`) AS `benchmarkCount`
|
||||
from (((`winstudentgoaltracker`.`student` `s`
|
||||
left
|
||||
join `winstudentgoaltracker`.`goal` `g` on((`g`.`id_student` = `s`.`id_student`)))
|
||||
left
|
||||
join `winstudentgoaltracker`.`progress_event` `pe` on((`pe`.`id_goal` = `g`.`id_goal`))) group by `s`.`id_student`,`s`.`identifier`,`s`.`next_iep_date`;
|
||||
join `winstudentgoaltracker`.`progress_event` `pe` on((`pe`.`id_goal` = `g`.`id_goal`)))
|
||||
left
|
||||
join `winstudentgoaltracker`.`benchmark` `b` on((`b`.`id_goal` = `g`.`id_goal`))) group by `s`.`id_student`,`s`.`identifier`,`s`.`next_iep_date`;
|
||||
|
||||
+6
-2
@@ -15,14 +15,18 @@
|
||||
@if (loaded()) {
|
||||
<div class="detail-card">
|
||||
<div class="field">
|
||||
<span class="field-label">Goal</span>
|
||||
<span class="field-value">{{ goalCategory }}</span>
|
||||
<span class="field-label">Goal: {{ goalCategory }}</span>
|
||||
</div>
|
||||
<div class="field">
|
||||
<label class="field-label" for="benchmarkText">Benchmark</label>
|
||||
<textarea id="benchmarkText" class="field-input field-textarea" [(ngModel)]="benchmarkText" rows="4"
|
||||
placeholder="Enter benchmark text..."></textarea>
|
||||
</div>
|
||||
<div class="field">
|
||||
<label class="field-label" for="shortName">Short Name</label>
|
||||
<input id="shortName" class="field-input" type="text" [(ngModel)]="shortName" maxlength="50"
|
||||
placeholder="Optional" />
|
||||
</div>
|
||||
@if (!isNew()) {
|
||||
<div class="metadata">
|
||||
@if (createdByName) {
|
||||
|
||||
+22
-4
@@ -42,9 +42,11 @@ export class BenchmarkCardFull implements OnDestroy {
|
||||
protected readonly successMessage = signal<string | null>(null);
|
||||
protected readonly saving = signal(false);
|
||||
|
||||
// Form field
|
||||
// Form fields
|
||||
protected benchmarkText = '';
|
||||
protected shortName = '';
|
||||
private savedBenchmarkText = '';
|
||||
private savedShortName = '';
|
||||
|
||||
// Read-only metadata
|
||||
protected goalCategory = '';
|
||||
@@ -58,7 +60,8 @@ export class BenchmarkCardFull implements OnDestroy {
|
||||
// Returns true if the benchmark text has unsaved changes.
|
||||
// *****************************************************************
|
||||
hasChanges(): boolean {
|
||||
return this.benchmarkText !== this.savedBenchmarkText;
|
||||
return this.benchmarkText !== this.savedBenchmarkText
|
||||
|| this.shortName !== this.savedShortName;
|
||||
}
|
||||
|
||||
// ************************ Public Methods *************************
|
||||
@@ -77,11 +80,13 @@ export class BenchmarkCardFull implements OnDestroy {
|
||||
const result = await this.studentService.createBenchmark(this.studentId, {
|
||||
goalId: this.goalId,
|
||||
benchmark: this.benchmarkText,
|
||||
shortName: this.shortName || undefined,
|
||||
});
|
||||
this.saving.set(false);
|
||||
if (result.success) {
|
||||
this.successMessage.set('Benchmark created.');
|
||||
this.savedBenchmarkText = this.benchmarkText;
|
||||
this.savedShortName = this.shortName;
|
||||
this.studentService.notifyDataChanged();
|
||||
if (result.payload?.benchmarkId) {
|
||||
this.router.navigate(['/students', this.studentId, 'goals', this.goalId, 'benchmarks', result.payload.benchmarkId]);
|
||||
@@ -90,11 +95,19 @@ export class BenchmarkCardFull implements OnDestroy {
|
||||
this.errorMessage.set(result.message);
|
||||
}
|
||||
} else {
|
||||
const result = await this.studentService.updateBenchmark(this.studentId, this.benchmarkId!, this.benchmarkText);
|
||||
const shortNameChanged = this.shortName !== this.savedShortName;
|
||||
const result = await this.studentService.updateBenchmark(this.studentId, this.benchmarkId!, this.benchmarkText, this.shortName || undefined);
|
||||
this.saving.set(false);
|
||||
if (result.success) {
|
||||
this.savedBenchmarkText = this.benchmarkText;
|
||||
this.savedShortName = this.shortName;
|
||||
this.successMessage.set('Changes saved.');
|
||||
if (shortNameChanged) {
|
||||
this.studentService.updateSidebarLabel(
|
||||
['/students', this.studentId, 'goals', this.goalId, 'benchmarks', this.benchmarkId!],
|
||||
this.shortName || this.benchmarkText
|
||||
);
|
||||
}
|
||||
} else {
|
||||
this.errorMessage.set(result.message);
|
||||
}
|
||||
@@ -106,12 +119,13 @@ export class BenchmarkCardFull implements OnDestroy {
|
||||
// *****************************************************************
|
||||
onCancel() {
|
||||
this.benchmarkText = this.savedBenchmarkText;
|
||||
this.shortName = this.savedShortName;
|
||||
this.errorMessage.set(null);
|
||||
this.successMessage.set(null);
|
||||
}
|
||||
|
||||
onBack() {
|
||||
this.router.navigate(['/students', this.studentId, 'benchmarks']);
|
||||
this.router.navigate(['/students', this.studentId, 'goals', this.goalId, 'benchmarks']);
|
||||
}
|
||||
|
||||
ngOnDestroy() {
|
||||
@@ -127,7 +141,9 @@ export class BenchmarkCardFull implements OnDestroy {
|
||||
if (!this.benchmarkId) {
|
||||
this.isNew.set(true);
|
||||
this.benchmarkText = '';
|
||||
this.shortName = '';
|
||||
this.savedBenchmarkText = '';
|
||||
this.savedShortName = '';
|
||||
this.loadGoalCategory();
|
||||
this.loaded.set(true);
|
||||
return;
|
||||
@@ -147,7 +163,9 @@ export class BenchmarkCardFull implements OnDestroy {
|
||||
}
|
||||
|
||||
this.benchmarkText = bm.benchmark;
|
||||
this.shortName = bm.shortName ?? '';
|
||||
this.savedBenchmarkText = bm.benchmark;
|
||||
this.savedShortName = bm.shortName ?? '';
|
||||
this.goalCategory = bm.goalCategory;
|
||||
this.createdByName = bm.createdByName;
|
||||
this.createdAt = bm.createdAt;
|
||||
|
||||
@@ -0,0 +1 @@
|
||||
<p>progress-edit works!</p>
|
||||
+23
@@ -0,0 +1,23 @@
|
||||
import { ComponentFixture, TestBed } from '@angular/core/testing';
|
||||
|
||||
import { ProgressEdit } from './progress-edit';
|
||||
|
||||
describe('ProgressEdit', () => {
|
||||
let component: ProgressEdit;
|
||||
let fixture: ComponentFixture<ProgressEdit>;
|
||||
|
||||
beforeEach(async () => {
|
||||
await TestBed.configureTestingModule({
|
||||
imports: [ProgressEdit]
|
||||
})
|
||||
.compileComponents();
|
||||
|
||||
fixture = TestBed.createComponent(ProgressEdit);
|
||||
component = fixture.componentInstance;
|
||||
fixture.detectChanges();
|
||||
});
|
||||
|
||||
it('should create', () => {
|
||||
expect(component).toBeTruthy();
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,11 @@
|
||||
import { Component } from '@angular/core';
|
||||
|
||||
@Component({
|
||||
selector: 'app-progress-edit',
|
||||
imports: [],
|
||||
templateUrl: './progress-edit.html',
|
||||
styleUrl: './progress-edit.scss',
|
||||
})
|
||||
export class ProgressEdit {
|
||||
|
||||
}
|
||||
@@ -37,6 +37,11 @@ export class Home implements OnDestroy {
|
||||
).subscribe(() => {
|
||||
this.expandToRoute(this.router.url);
|
||||
});
|
||||
|
||||
// Patch individual sidebar node labels without a full rebuild.
|
||||
this.labelSub = this.studentService.sidebarLabelUpdate$.subscribe(update => {
|
||||
this.patchNodeLabel(this.sidebarTree(), update.routerLink, update.label);
|
||||
});
|
||||
}
|
||||
|
||||
// ************************** Declarations *************************
|
||||
@@ -45,6 +50,7 @@ export class Home implements OnDestroy {
|
||||
private readonly router = inject(Router);
|
||||
private readonly studentService = inject(StudentService);
|
||||
private readonly routeSub: Subscription;
|
||||
private readonly labelSub: Subscription;
|
||||
protected readonly sidebarExpanded = signal(true);
|
||||
protected readonly sidebarTree = signal<SidebarNode[]>([]);
|
||||
|
||||
@@ -68,10 +74,28 @@ export class Home implements OnDestroy {
|
||||
|
||||
ngOnDestroy() {
|
||||
this.routeSub.unsubscribe();
|
||||
this.labelSub.unsubscribe();
|
||||
}
|
||||
|
||||
// ********************** Support Procedures ***********************
|
||||
|
||||
// *****************************************************************
|
||||
// Recursively walks the sidebar tree to find a node whose
|
||||
// routerLink matches the given link, and updates its label.
|
||||
// *****************************************************************
|
||||
private patchNodeLabel(nodes: SidebarNode[], routerLink: string[], label: string): boolean {
|
||||
for (const node of nodes) {
|
||||
if (node.routerLink && node.routerLink.join('/') === routerLink.join('/')) {
|
||||
node.label = label;
|
||||
return true;
|
||||
}
|
||||
if (node.children && this.patchNodeLabel(node.children, routerLink, label)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
// *****************************************************************
|
||||
// Loads student list, sorts by identifier, and builds the sidebar
|
||||
// tree with lazy-loading callbacks for goals and benchmarks.
|
||||
@@ -125,9 +149,8 @@ export class Home implements OnDestroy {
|
||||
childCount: 2,
|
||||
children: [
|
||||
{
|
||||
label: 'Progress Events',
|
||||
label: goal.progressEventCount > 0 ? `Progress Events (${goal.progressEventCount})` : 'Progress Events',
|
||||
routerLink: ['/students', studentId, 'goals', goal.goalId, 'progress'],
|
||||
childCount: goal.progressEventCount,
|
||||
},
|
||||
{
|
||||
label: 'Benchmarks',
|
||||
@@ -152,7 +175,7 @@ export class Home implements OnDestroy {
|
||||
return result.payload.benchmarks
|
||||
.filter(b => b.goalId === goalId)
|
||||
.map(b => ({
|
||||
label: b.benchmark,
|
||||
label: b.shortName || b.benchmark,
|
||||
routerLink: ['/students', studentId, 'goals', goalId, 'benchmarks', b.benchmarkId],
|
||||
}));
|
||||
}
|
||||
|
||||
@@ -8,6 +8,7 @@ export interface BenchmarkDto {
|
||||
goalId: string;
|
||||
goalCategory: string;
|
||||
benchmark: string;
|
||||
shortName?: string;
|
||||
createdByName: string;
|
||||
createdAt: Date;
|
||||
updatedAt: Date | null;
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { HttpClient, HttpErrorResponse } from '@angular/common/http';
|
||||
import { inject, Injectable, signal } from '@angular/core';
|
||||
import { firstValueFrom } from 'rxjs';
|
||||
import { firstValueFrom, Subject } from 'rxjs';
|
||||
import { environment } from '../../../environments/environment';
|
||||
import { ApiResult } from '../classes/api-result';
|
||||
import { ResponseResult } from '../classes/auth.models';
|
||||
@@ -27,6 +27,10 @@ export class StudentService {
|
||||
// Incremented after any data mutation so subscribers can refresh.
|
||||
readonly dataVersion = signal(0);
|
||||
|
||||
// Emits targeted label updates for sidebar nodes without a full rebuild.
|
||||
private readonly _sidebarLabelUpdate = new Subject<{ routerLink: string[]; label: string }>();
|
||||
readonly sidebarLabelUpdate$ = this._sidebarLabelUpdate.asObservable();
|
||||
|
||||
// ************************** Properties ***************************
|
||||
|
||||
// ************************ Public Methods *************************
|
||||
@@ -38,6 +42,14 @@ export class StudentService {
|
||||
this.dataVersion.update(v => v + 1);
|
||||
}
|
||||
|
||||
// *****************************************************************
|
||||
// Emits a targeted sidebar label update for a specific node,
|
||||
// avoiding the full tree rebuild that notifyDataChanged triggers.
|
||||
// *****************************************************************
|
||||
updateSidebarLabel(routerLink: string[], label: string) {
|
||||
this._sidebarLabelUpdate.next({ routerLink, label });
|
||||
}
|
||||
|
||||
// *****************************************************************
|
||||
// Returns student card summaries for the authenticated user.
|
||||
// *****************************************************************
|
||||
@@ -186,7 +198,7 @@ export class StudentService {
|
||||
// *****************************************************************
|
||||
// Creates a new benchmark for a student.
|
||||
// *****************************************************************
|
||||
async createBenchmark(studentId: string, data: { goalId: string; benchmark: string }): Promise<ApiResult<any>> {
|
||||
async createBenchmark(studentId: string, data: { goalId: string; benchmark: string; shortName?: string }): Promise<ApiResult<any>> {
|
||||
try {
|
||||
const result = await firstValueFrom(
|
||||
this.http.post<ResponseResult<any>>(`${this.base}/api/Student/${studentId}/benchmarks`, data)
|
||||
@@ -202,10 +214,10 @@ export class StudentService {
|
||||
// *****************************************************************
|
||||
// Updates a benchmark's text.
|
||||
// *****************************************************************
|
||||
async updateBenchmark(studentId: string, benchmarkId: string, benchmarkText: string): Promise<ApiResult<any>> {
|
||||
async updateBenchmark(studentId: string, benchmarkId: string, benchmarkText: string, shortName?: string): Promise<ApiResult<any>> {
|
||||
try {
|
||||
const result = await firstValueFrom(
|
||||
this.http.put<ResponseResult<any>>(`${this.base}/api/Student/${studentId}/benchmarks/${benchmarkId}`, { benchmark: benchmarkText })
|
||||
this.http.put<ResponseResult<any>>(`${this.base}/api/Student/${studentId}/benchmarks/${benchmarkId}`, { benchmark: benchmarkText, shortName })
|
||||
);
|
||||
return result.success
|
||||
? ApiResult.ok(result.data)
|
||||
|
||||
Reference in New Issue
Block a user