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
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,7 @@ import { map, filter, tap } from 'rxjs/operators';
import { LocalStorageService } from '../local-storage/local-storage.service';
import { ENV, Environment } from '../../../environments/environment-types';
import { ExperimentSegmentListRequest } from '../segments/store/segments.model';
import { ConditionWeightUpdate } from '../../features/dashboard/experiments/modals/edit-condition-weights-modal/edit-condition-weights-modal.component';

@Injectable()
export class ExperimentService {
Expand Down Expand Up @@ -314,4 +315,29 @@ export class ExperimentService {
deleteExperimentExclusionPrivateSegmentList(segmentId: string) {
this.store$.dispatch(experimentAction.actionDeleteExperimentExclusionList({ segmentId }));
}

updateExperimentConditionWeights(experiment: ExperimentVM, weightUpdates: ConditionWeightUpdate[]): void {
// Create updated experiment with new condition weights
const updatedExperiment: ExperimentVM = {
...experiment,
conditions: experiment.conditions.map((condition) => {
const weightUpdate = weightUpdates.find((update) => update.conditionId === condition.id);

return weightUpdate
? {
...condition,
assignmentWeight: weightUpdate.assignmentWeight,
}
: condition;
}),
};

// Dispatch the update action
this.store$.dispatch(
experimentAction.actionUpsertExperiment({
experiment: updatedExperiment,
actionType: UpsertExperimentType.UPDATE_EXPERIMENT,
})
);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -80,11 +80,6 @@ export enum NewExperimentPaths {
POST_EXPERIMENT_RULE = 'Post Experiment Rule',
}

export enum ExperimentDesignTypes {
SIMPLE = 'Simple',
FACTORIAL = 'Factorial',
}

export enum OverviewFormWarningStatus {
NO_WARNING = 'no warning',
CONTEXT_CHANGED = 'context changed',
Expand Down Expand Up @@ -343,7 +338,7 @@ export interface ExperimentFormData {
name: string;
description: string;
appContext: string;
experimentType: ExperimentDesignTypes;
experimentType: EXPERIMENT_TYPE;
unitOfAssignment: ASSIGNMENT_UNIT;
consistencyRule: CONSISTENCY_RULE;
conditionOrder?: CONDITION_ORDER;
Expand Down Expand Up @@ -430,7 +425,7 @@ export interface DraftExperimentRequest {
name: string;
description?: string;
context: string[];
type: ExperimentDesignTypes;
type: EXPERIMENT_TYPE;
assignmentUnit: ASSIGNMENT_UNIT;
state: EXPERIMENT_STATE;
filterMode: FILTER_MODE;
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,122 @@
<app-common-dialog
[title]="config.title"
[cancelBtnLabel]="config.cancelBtnLabel"
[primaryActionBtnLabel]="config.primaryActionBtnLabel"
[primaryActionBtnColor]="config.primaryActionBtnColor"
[primaryActionBtnDisabled]="isPrimaryButtonDisabled$ | async"
(primaryActionBtnClicked)="onPrimaryActionBtnClicked()"
>
<form [formGroup]="conditionWeightForm" class="form-standard dense-3">
<div class="weight-method-section dense-1">
<mat-radio-group formControlName="weightingMethod">
<span class="section-label ft-14-600">{{ 'experiments.edit-condition-weights-modal.method-header.text' | translate }}</span>
<mat-radio-button
*ngFor="let method of weightingMethods"
[value]="method.value"
[disabled]="method.disabled"
>
<div class="radio-content">
<span
class="radio-label ft-14-600"
[class.disabled-text]="method.disabled"
>
{{ method.name | titlecase }}
</span>
<span
class="radio-description ft-12-400"
[class.disabled-text]="method.disabled"
>
{{ method.description | translate }}
</span>
</div>
</mat-radio-button>
</mat-radio-group>
</div>

<div class="table-container">
<table
mat-table
[dataSource]="conditions"
class="conditions-table"
[ngClass]="{ 'no-data': !conditions?.length }"
>
<!-- Condition Column -->
<ng-container matColumnDef="condition">
<th mat-header-cell *matHeaderCellDef class="condition-column ft-14-600">
Condition
</th>
<td mat-cell *matCellDef="let condition" class="condition-column ft-14-400">
{{ condition.conditionCode }}
</td>
<!-- Summary row for condition column -->
<td mat-footer-cell *matFooterCellDef class="condition-column ft-14-400 summary-row">
@if (getTotalWeightStatus()?.totalWeightInvalid) {
Comment thread
bcb37 marked this conversation as resolved.
<div class="error-text ft-12-400">
{{ 'experiments.edit-condition-weights-modal.weights-sum-validation.text' | translate }}
</div>
}
@if (getTotalWeightStatus()?.max || getTotalWeightStatus()?.min ) {
<div class="error-text ft-12-400">
{{ 'experiments.edit-condition-weights-modal.weights-range-validation.text' | translate }}
</div>
}
@if (getTotalWeightStatus()?.invalidNumber) {
<div class="error-text ft-12-400">
{{ 'experiments.edit-condition-weights-modal.invalid-number-error.text' | translate }}
</div>
}
@if (getTotalWeightStatus()?.tooManyDecimals) {
<div class="error-text ft-12-400">
{{ 'experiments.edit-condition-weights-modal.weights-decimal-validation.text' | translate }}
</div>
}
</td>
</ng-container>

<!-- Weight Column -->
<ng-container matColumnDef="weight">
<th mat-header-cell *matHeaderCellDef class="weight-column ft-14-600">
Weight (%)
</th>
<td mat-cell *matCellDef="let condition; let i = index" class="weight-column ft-14-400">
<mat-form-field appearance="outline" class="weight-input">
<input
matInput
type="number"
min="0"
max="100"
step="0.01"
[formControl]="getWeightControl(i)"
(input)="onWeightChange()"
placeholder="0.00"
/>


</mat-form-field>
</td>
<!-- Summary row for weight column -->
<td mat-footer-cell *matFooterCellDef class="weight-column ft-14-600 summary-row">
<span class="total-weight">
{{ getCurrentTotal() | number:'1.2-2' }}
</span>
</td>
</ng-container>

<!-- Header and Row Definitions -->
<tr mat-header-row *matHeaderRowDef="displayedColumns; sticky: true"></tr>
<tr mat-row *matRowDef="let row; columns: displayedColumns;"></tr>

<!-- Footer Row for Summary -->
<tr mat-footer-row *matFooterRowDef="displayedColumns" class="summary-footer-row"></tr>

<!-- No Data Row -->
<tr *matNoDataRow>
<td class="ft-14-400" [attr.colspan]="displayedColumns.length">
No conditions available
</td>
</tr>
</table>

</div>
</form>
</app-common-dialog>
Original file line number Diff line number Diff line change
@@ -0,0 +1,161 @@
.weight-input {
width: 90px;

.mat-mdc-form-field-subscript-wrapper {
display: none;
}
}

.table-container {
position: relative;
overflow: auto;
width: 100%;

/* Add gap between header and body when no data exists */
::ng-deep .no-data tbody:before {
display: block;
line-height: 8px;
content: '\200C';
}
.conditions-table {
/* Remove arrows/spinners from input type number */
input[type="number"] {
-webkit-appearance: textfield;
-moz-appearance: textfield;

&::-webkit-outer-spin-button,
&::-webkit-inner-spin-button {
-webkit-appearance: none;
margin: 0;
}
}

::ng-deep thead {
background-color: var(--zircon);

tr.mat-mdc-header-row {
height: 48px;
border: 0;

th {
padding-left: 0;
color: var(--darker-grey);

&:first-child {
border-top-left-radius: 4px;
}

&:last-child {
border-top-right-radius: 4px;
}
}
}
}

::ng-deep tbody {
tr.mat-mdc-row {
height: 56px;

td {
min-width: 96px;
padding-left: 0;
color: var(--black-2);
}
}

tr.mat-mdc-no-data-row {
td {
height: 48px;
text-align: center;
border: 1.5px dashed var(--light-grey-2);
color: var(--dark-grey);
}
}
}

::ng-deep tfoot {
tr.mat-mdc-footer-row.summary-footer-row {
height: 48px;
border-top: 2px solid var(--light-grey-2);
background-color: var(--light-grey-0);

td.summary-row {
min-width: 96px;
padding-left: 0;
font-weight: 600;

&.condition-column {
padding-left: 32px;
}

&.weight-column {
text-align: right;
padding-right: 32px;
}

.total-weight {
margin: 4px;
}

.error-text {
color: #f44336;
font-weight: 500;
}

}
}
}

.condition-column {
width: 65%;
padding-left: 32px;
}

.weight-column {
width: 35%;
text-align: right;
padding-right: 32px;

.weight-input {
width: 90px;
flex-direction: row;

input {
text-align: right;
}


.mat-mdc-form-field-subscript-wrapper {
display: none;
}
}
}
}
}

.weight-method-section {
margin-bottom: 6px;

.section-label {
display: block;
}

mat-radio-group {
display: flex;
flex-direction: column;
gap: 6px;
}

.radio-content {
display: flex;
flex-direction: column;

.radio-description {
color: var(--dark-grey);
}
}

.disabled-text {
opacity: 0.6;
}
}
Loading
Loading