Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions projects/ngx-coding-components/src/lib/translations/de.json
Original file line number Diff line number Diff line change
Expand Up @@ -253,6 +253,12 @@
"TAKE_EMPTY_AS_VALID": "Leerer Antwortwert ist gültig",
"SORT": "Sortiere Werte",
"SOLVER_EXPRESSION": "Ausdruck für Solver",
"solver-source-warning": {
"unselected-sources": "Warnung: Im Solver-Ausdruck referenzierte Variable(n) sind nicht als Quell-Variable(n) ausgewählt"
},
"solver-insert-source": {
"label": "Quellvariable einfügen"
},
"solver-test": {
"title": "Solver-Test",
"action": "Testen",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,8 @@ <h1 mat-dialog-title>{{ (newVariableMode ? 'varList.add' : 'derive-processing.pr

@if (data.sourceType !== 'BASE') {
<mat-form-field>
<mat-select placeholder="Quell-Variablen" [formControl]="selectedSources" multiple (closed)="updateDeriveSources()">
<mat-select placeholder="Quell-Variablen" [formControl]="selectedSources" multiple
(selectionChange)="updateDeriveSources()" (closed)="updateDeriveSources()">
<button (click)="toggleAllSelection()" style="margin: 10px" mat-stroked-button>Alle auswählen</button>
<mat-select-trigger>
Quell-Variablen
Expand Down Expand Up @@ -46,36 +47,38 @@ <h1 mat-dialog-title>{{ (newVariableMode ? 'varList.add' : 'derive-processing.pr
@if (data.sourceType === 'SOLVER') {
<mat-form-field class="solver-expression-field">
<mat-label>{{ 'derive-processing.SOLVER_EXPRESSION' | translate }}</mat-label>
<input matInput [(ngModel)]="data.sourceParameters.solverExpression"
<input #solverExpressionInput matInput [(ngModel)]="data.sourceParameters.solverExpression"
(ngModelChange)="clearSolverTestResult()">
<button mat-icon-button matSuffix type="button"
[matMenuTriggerFor]="solverSourceMenu"
[disabled]="selectedSolverSources.length < 1"
[attr.aria-label]="'derive-processing.solver-insert-source.label' | translate"
[matTooltip]="'derive-processing.solver-insert-source.label' | translate">
<mat-icon>data_object</mat-icon>
</button>
</mat-form-field>

<div class="solver-expression-help" role="note" aria-labelledby="solver-expression-help-title">
<div class="solver-expression-help__header">
<mat-icon class="solver-expression-help__icon" aria-hidden="true">info</mat-icon>
<span id="solver-expression-help-title">
{{ 'derive-processing.solver-help.title' | translate }}
</span>
<mat-menu #solverSourceMenu="matMenu">
@for (source of selectedSolverSources; track source.id) {
<button class="solver-source-menu__item"
mat-menu-item
type="button"
(click)="insertSolverSourceReference(source, solverExpressionInput)">
<mat-icon>input</mat-icon>
<span>{{ source.label }}</span>
<code class="solver-source-menu__reference">
{{ getSolverSourceReference(source) }}
</code>
</button>
}
</mat-menu>

@if (solverSourceWarning; as warning) {
<div class="solver-source-warning" role="alert">
<mat-icon aria-hidden="true">warning</mat-icon>
<span>{{ warning }}</span>
</div>
<p>{{ 'derive-processing.solver-help.description' | translate }}</p>
<div>{{ 'derive-processing.solver-help.examples-title' | translate }}</div>
<ul>
@for (example of solverExpressionExamples; track example.expression) {
<li>
<code>{{ example.expression }}</code>
-
{{ example.descriptionKey | translate }}
</li>
}
</ul>
<a class="solver-expression-help__link"
[href]="solverExpressionDocsUrl"
target="_blank"
rel="noopener noreferrer">
{{ 'derive-processing.solver-help.docs-link' | translate }}
<mat-icon aria-hidden="true">open_in_new</mat-icon>
</a>
</div>
}

<section class="solver-test-area">
<div class="solver-test-header">
Expand Down Expand Up @@ -112,6 +115,33 @@ <h1 mat-dialog-title>{{ (newVariableMode ? 'varList.add' : 'derive-processing.pr
</div>
}
</section>

<div class="solver-expression-help" role="note" aria-labelledby="solver-expression-help-title">
<div class="solver-expression-help__header">
<mat-icon class="solver-expression-help__icon" aria-hidden="true">info</mat-icon>
<span id="solver-expression-help-title">
{{ 'derive-processing.solver-help.title' | translate }}
</span>
</div>
<p>{{ 'derive-processing.solver-help.description' | translate }}</p>
<div>{{ 'derive-processing.solver-help.examples-title' | translate }}</div>
<ul>
@for (example of solverExpressionExamples; track example.expression) {
<li>
<code>{{ example.expression }}</code>
-
{{ example.descriptionKey | translate }}
</li>
}
</ul>
<a class="solver-expression-help__link"
[href]="solverExpressionDocsUrl"
target="_blank"
rel="noopener noreferrer">
{{ 'derive-processing.solver-help.docs-link' | translate }}
<mat-icon aria-hidden="true">open_in_new</mat-icon>
</a>
</div>
}
</div>
</mat-dialog-content>
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { SourceType, VariableSourceParameters, SourceProcessingType } from
'@iqbspecs/coding-scheme/coding-scheme.interface';
import { TranslateService } from '@ngx-translate/core';
import { fakeAsync, tick } from '@angular/core/testing';
import { EditSourceParametersDialog, EditSourceParametersDialogData } from './edit-source-parameters-dialog.component';
import { SchemerService } from '../../services/schemer.service';

Expand All @@ -13,7 +14,9 @@ describe('EditSourceParametersDialog', () => {
'derive-processing.solver-test.error-sources-missing': 'Bitte mindestens eine Quellvariable auswählen.',
'derive-processing.solver-test.error-unselected-source': 'Der Ausdruck verweist auf nicht ausgewählte Quelle(n)',
'derive-processing.solver-test.error-invalid-value': 'Bitte numerischen Testwert prüfen',
'derive-processing.solver-test.error-evaluation': 'Der Ausdruck konnte nicht ausgewertet werden.'
'derive-processing.solver-test.error-evaluation': 'Der Ausdruck konnte nicht ausgewertet werden.',
'derive-processing.solver-source-warning.unselected-sources':
'Warnung: Im Solver-Ausdruck referenzierte Variable(n) sind nicht als Quell-Variable(n) ausgewählt'
};

const createDialog = (options: {
Expand Down Expand Up @@ -187,6 +190,98 @@ describe('EditSourceParametersDialog', () => {
expect(dialog.solverTestResult?.message).toContain('V2');
});

it('solverSourceWarning should show referenced variables that are not selected as sources', () => {
const dialog = createDialog({
selfAlias: 'D',
sourceType: 'SOLVER',
sourceParameters: {
solverExpression: `${solverRef('V1')} + ${solverRef('V2')}`
},
deriveSources: ['v1']
});

expect(dialog.solverSourceWarning).toContain(
'Warnung: Im Solver-Ausdruck referenzierte Variable(n)'
);
expect(dialog.solverSourceWarning).toContain('V2');
});

it('solverSourceWarning should update when expression or source selection changes', () => {
const dialog = createDialog({
selfAlias: 'D',
sourceType: 'SOLVER',
sourceParameters: { solverExpression: `${solverRef('V2')}` },
deriveSources: ['v1']
});

expect(dialog.solverSourceWarning).toContain('V2');

dialog.selectedSources.setValue(['v1', 'v2']);
dialog.updateDeriveSources();
expect(dialog.solverSourceWarning).toBeNull();

dialog.data.sourceParameters.solverExpression = `${solverRef('V1')}`;
dialog.selectedSources.setValue(['v2']);
dialog.updateDeriveSources();
expect(dialog.solverSourceWarning).toContain('V1');

dialog.data.sourceParameters.solverExpression = '';
expect(dialog.solverSourceWarning).toBeNull();
});

it('insertSolverSourceReference should insert the selected source at the cursor', fakeAsync(() => {
const dialog = createDialog({
selfAlias: 'D',
sourceType: 'SOLVER',
sourceParameters: { solverExpression: 'round( + 1)' },
deriveSources: ['v1']
});
const input = document.createElement('input');
input.value = dialog.data.sourceParameters.solverExpression || '';
input.setSelectionRange(6, 6);

dialog.insertSolverSourceReference({ id: 'v1', label: 'V1' }, input);
tick();

expect(dialog.data.sourceParameters.solverExpression).toBe(
`round(${solverRef('V1')} + 1)`
);
expect(input.selectionStart).toBe(11);
expect(input.selectionEnd).toBe(11);
}));

it('insertSolverSourceReference should replace the selected expression range', fakeAsync(() => {
const dialog = createDialog({
selfAlias: 'D',
sourceType: 'SOLVER',
sourceParameters: { solverExpression: '1 + placeholder' },
deriveSources: ['v2']
});
const input = document.createElement('input');
input.value = dialog.data.sourceParameters.solverExpression || '';
input.setSelectionRange(4, 15);

dialog.insertSolverSourceReference({ id: 'v2', label: 'V2' }, input);
tick();

expect(dialog.data.sourceParameters.solverExpression).toBe(
`1 + ${solverRef('V2')}`
);
expect(dialog.solverTestResult).toBeNull();
}));

it('getSolverSourceReference should expose the inserted reference syntax', () => {
const dialog = createDialog({
selfAlias: 'D',
sourceType: 'SOLVER',
deriveSources: ['v1']
});

expect(dialog.getSolverSourceReference({ id: 'v1', label: 'V1' })).toBe(
solverRef('V1')
);
});

it('runSolverTest should report non-numeric test values', () => {
const dialog = createDialog({
selfAlias: 'D',
Expand Down
Loading
Loading