chore(back-end and front-end): refractor and improvements calculator
This commit is contained in:
@@ -63,11 +63,11 @@
|
||||
<span class="file-details">
|
||||
{{ item.unitTime / 3600 | number: "1.1-1" }}h |
|
||||
{{ item.unitWeight | number: "1.0-0" }}g |
|
||||
materiale: {{ item.material || "N/D" }}
|
||||
@if (getItemDifferenceLabel(item.fileName)) {
|
||||
<span class="material-chip">{{ item.material || "N/D" }}</span>
|
||||
@if (getItemDifferenceLabel(item.fileName, item.material)) {
|
||||
|
|
||||
<small class="item-settings-diff">
|
||||
{{ getItemDifferenceLabel(item.fileName) }}
|
||||
{{ getItemDifferenceLabel(item.fileName, item.material) }}
|
||||
</small>
|
||||
}
|
||||
</span>
|
||||
@@ -110,7 +110,7 @@
|
||||
|
||||
<div class="actions">
|
||||
<div class="actions-left">
|
||||
<app-button variant="outline" (click)="consult.emit()">
|
||||
<app-button variant="secondary" (click)="consult.emit()">
|
||||
{{ "QUOTE.CONSULT" | translate }}
|
||||
</app-button>
|
||||
</div>
|
||||
|
||||
@@ -20,10 +20,11 @@
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
padding: var(--space-3);
|
||||
background: var(--color-neutral-50);
|
||||
padding: var(--space-3) var(--space-4);
|
||||
background: var(--color-bg-card);
|
||||
border-radius: var(--radius-md);
|
||||
border: 1px solid var(--color-border);
|
||||
box-shadow: 0 2px 6px rgba(10, 20, 30, 0.04);
|
||||
}
|
||||
|
||||
.item-info {
|
||||
@@ -54,6 +55,19 @@
|
||||
color: var(--color-text-muted);
|
||||
}
|
||||
|
||||
.material-chip {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
padding: 2px 8px;
|
||||
border-radius: 999px;
|
||||
border: 1px solid #d9d4bd;
|
||||
background: #fbf7e9;
|
||||
color: #6d5b1d;
|
||||
font-size: 0.72rem;
|
||||
font-weight: 700;
|
||||
letter-spacing: 0.2px;
|
||||
}
|
||||
|
||||
.item-controls {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
@@ -149,6 +163,7 @@
|
||||
.actions-right {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: var(--space-2);
|
||||
}
|
||||
|
||||
.actions-right {
|
||||
|
||||
@@ -189,14 +189,30 @@ export class QuoteResultComponent implements OnDestroy {
|
||||
this.quantityTimers.clear();
|
||||
}
|
||||
|
||||
getItemDifferenceLabel(fileName: string): string {
|
||||
getItemDifferenceLabel(fileName: string, materialCode?: string): string {
|
||||
const differences =
|
||||
this.itemSettingsDiffByFileName()[fileName]?.differences || [];
|
||||
if (differences.length === 0) return '';
|
||||
|
||||
const materialOnly = differences.find(
|
||||
const normalizedMaterial = String(materialCode || '')
|
||||
.trim()
|
||||
.toLowerCase();
|
||||
|
||||
const filtered = differences.filter((entry) => {
|
||||
const normalized = String(entry || '')
|
||||
.trim()
|
||||
.toLowerCase();
|
||||
const isMaterialOnly = !normalized.includes(':');
|
||||
return !(isMaterialOnly && normalized === normalizedMaterial);
|
||||
});
|
||||
|
||||
if (filtered.length === 0) {
|
||||
return '';
|
||||
}
|
||||
|
||||
const materialOnly = filtered.find(
|
||||
(entry) => !entry.includes(':') && entry.trim().length > 0,
|
||||
);
|
||||
return materialOnly || differences.join(' | ');
|
||||
return materialOnly || filtered.join(' | ');
|
||||
}
|
||||
}
|
||||
|
||||
@@ -13,11 +13,9 @@
|
||||
>
|
||||
</app-stl-viewer>
|
||||
}
|
||||
<!-- Close button removed as requested -->
|
||||
</div>
|
||||
}
|
||||
|
||||
<!-- Initial Dropzone (Visible only when no files) -->
|
||||
@if (items().length === 0) {
|
||||
<app-dropzone
|
||||
[label]="'CALC.UPLOAD_LABEL'"
|
||||
@@ -29,7 +27,6 @@
|
||||
</app-dropzone>
|
||||
}
|
||||
|
||||
<!-- New File List with Details -->
|
||||
@if (items().length > 0) {
|
||||
<div class="items-grid">
|
||||
@for (item of items(); track item.file.name; let i = $index) {
|
||||
@@ -83,7 +80,6 @@
|
||||
}
|
||||
</div>
|
||||
|
||||
<!-- "Add Files" Button (Visible only when files exist) -->
|
||||
<div class="add-more-container">
|
||||
<input
|
||||
#additionalInput
|
||||
@@ -111,39 +107,38 @@
|
||||
>.
|
||||
</p>
|
||||
|
||||
<label class="item-settings-checkbox item-settings-checkbox--top">
|
||||
<input
|
||||
type="checkbox"
|
||||
[checked]="sameSettingsForAll()"
|
||||
(change)="onSameSettingsToggle($any($event.target).checked)"
|
||||
/>
|
||||
<span>Tutti i file uguali (applica impostazioni a tutti)</span>
|
||||
</label>
|
||||
@if (mode() === "advanced") {
|
||||
<div class="sync-settings">
|
||||
<label class="sync-settings-toggle">
|
||||
<input
|
||||
type="checkbox"
|
||||
[checked]="sameSettingsForAll()"
|
||||
[disabled]="lockedSettings()"
|
||||
(change)="onSameSettingsToggle($any($event.target).checked)"
|
||||
/>
|
||||
<span class="sync-settings-copy">
|
||||
<span class="sync-settings-title">
|
||||
Stesse impostazioni per tutti i file
|
||||
</span>
|
||||
<span class="sync-settings-subtitle">Colore escluso</span>
|
||||
</span>
|
||||
</label>
|
||||
</div>
|
||||
|
||||
@if (sameSettingsForAll()) {
|
||||
<div class="item-settings-panel">
|
||||
<h4 class="item-settings-title">Impostazioni globali</h4>
|
||||
@if (sameSettingsForAll()) {
|
||||
<div class="item-settings-panel">
|
||||
<h4 class="item-settings-title">Impostazioni globali</h4>
|
||||
|
||||
<div class="item-settings-grid">
|
||||
<label>
|
||||
{{ "CALC.MATERIAL" | translate }}
|
||||
<select formControlName="material">
|
||||
@for (mat of materials(); track mat.value) {
|
||||
<option [value]="mat.value">{{ mat.label }}</option>
|
||||
}
|
||||
</select>
|
||||
</label>
|
||||
|
||||
@if (mode() === "easy") {
|
||||
<div class="item-settings-grid">
|
||||
<label>
|
||||
{{ "CALC.QUALITY" | translate }}
|
||||
<select formControlName="quality">
|
||||
@for (quality of qualities(); track quality.value) {
|
||||
<option [value]="quality.value">{{ quality.label }}</option>
|
||||
{{ "CALC.MATERIAL" | translate }}
|
||||
<select formControlName="material">
|
||||
@for (mat of materials(); track mat.value) {
|
||||
<option [value]="mat.value">{{ mat.label }}</option>
|
||||
}
|
||||
</select>
|
||||
</label>
|
||||
} @else {
|
||||
|
||||
<label>
|
||||
{{ "CALC.NOZZLE" | translate }}
|
||||
<select formControlName="nozzleDiameter">
|
||||
@@ -152,10 +147,8 @@
|
||||
}
|
||||
</select>
|
||||
</label>
|
||||
}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@if (mode() === "advanced") {
|
||||
<div class="item-settings-grid">
|
||||
<label>
|
||||
{{ "CALC.PATTERN" | translate }}
|
||||
@@ -179,7 +172,12 @@
|
||||
<div class="item-settings-grid">
|
||||
<label>
|
||||
{{ "CALC.INFILL" | translate }}
|
||||
<input type="number" min="0" max="100" formControlName="infillDensity" />
|
||||
<input
|
||||
type="number"
|
||||
min="0"
|
||||
max="100"
|
||||
formControlName="infillDensity"
|
||||
/>
|
||||
</label>
|
||||
|
||||
<label class="item-settings-checkbox">
|
||||
@@ -187,161 +185,72 @@
|
||||
<span>{{ "CALC.SUPPORT" | translate }}</span>
|
||||
</label>
|
||||
</div>
|
||||
}
|
||||
</div>
|
||||
} @else {
|
||||
@if (getSelectedItem(); as selectedItem) {
|
||||
<div class="item-settings-panel">
|
||||
<h4 class="item-settings-title">
|
||||
Impostazioni file: {{ selectedItem.file.name }}
|
||||
</h4>
|
||||
|
||||
<div class="item-settings-grid">
|
||||
<label>
|
||||
{{ "CALC.MATERIAL" | translate }}
|
||||
<select
|
||||
[value]="selectedItem.material || form.get('material')?.value"
|
||||
(change)="
|
||||
updateItemMaterial(getSelectedItemIndex(), $any($event.target).value)
|
||||
"
|
||||
>
|
||||
@for (mat of materials(); track mat.value) {
|
||||
<option [value]="mat.value">{{ mat.label }}</option>
|
||||
}
|
||||
</select>
|
||||
</label>
|
||||
|
||||
@if (mode() === "easy") {
|
||||
<label>
|
||||
{{ "CALC.QUALITY" | translate }}
|
||||
<select
|
||||
[value]="selectedItem.quality || form.get('quality')?.value"
|
||||
(change)="
|
||||
updateSelectedItemStringField(
|
||||
'quality',
|
||||
$any($event.target).value
|
||||
)
|
||||
"
|
||||
>
|
||||
@for (quality of qualities(); track quality.value) {
|
||||
<option [value]="quality.value">{{ quality.label }}</option>
|
||||
}
|
||||
</select>
|
||||
</label>
|
||||
} @else {
|
||||
<label>
|
||||
{{ "CALC.NOZZLE" | translate }}
|
||||
<select
|
||||
[value]="
|
||||
selectedItem.nozzleDiameter ?? form.get('nozzleDiameter')?.value
|
||||
"
|
||||
(change)="
|
||||
updateSelectedItemNumberField(
|
||||
'nozzleDiameter',
|
||||
+$any($event.target).value
|
||||
)
|
||||
"
|
||||
>
|
||||
@for (n of nozzleDiameters(); track n.value) {
|
||||
<option [value]="n.value">{{ n.label }}</option>
|
||||
}
|
||||
</select>
|
||||
</label>
|
||||
}
|
||||
</div>
|
||||
@if (mode() === "easy") {
|
||||
<app-select
|
||||
formControlName="quality"
|
||||
[label]="'CALC.QUALITY' | translate"
|
||||
[options]="qualities()"
|
||||
></app-select>
|
||||
} @else {
|
||||
<app-select
|
||||
formControlName="nozzleDiameter"
|
||||
[label]="'CALC.NOZZLE' | translate"
|
||||
[options]="nozzleDiameters()"
|
||||
></app-select>
|
||||
}
|
||||
</div>
|
||||
} @else {
|
||||
@if (getSelectedItem(); as selectedItem) {
|
||||
<div class="item-settings-panel">
|
||||
<h4 class="item-settings-title">
|
||||
Impostazioni file: {{ selectedItem.file.name }}
|
||||
</h4>
|
||||
|
||||
@if (items().length > 1) {
|
||||
<div class="checkbox-row sync-all-row">
|
||||
<input type="checkbox" formControlName="syncAllItems" id="syncAllItems" />
|
||||
<label for="syncAllItems">
|
||||
Uguale per tutti i pezzi
|
||||
</label>
|
||||
</div>
|
||||
}
|
||||
<div class="item-settings-grid">
|
||||
<label>
|
||||
{{ "CALC.MATERIAL" | translate }}
|
||||
<select formControlName="material">
|
||||
@for (mat of materials(); track mat.value) {
|
||||
<option [value]="mat.value">{{ mat.label }}</option>
|
||||
}
|
||||
</select>
|
||||
</label>
|
||||
|
||||
@if (mode() === "advanced") {
|
||||
<div class="item-settings-grid">
|
||||
<label>
|
||||
{{ "CALC.PATTERN" | translate }}
|
||||
<select
|
||||
[value]="selectedItem.infillPattern || form.get('infillPattern')?.value"
|
||||
(change)="
|
||||
updateSelectedItemStringField(
|
||||
'infillPattern',
|
||||
$any($event.target).value
|
||||
)
|
||||
"
|
||||
>
|
||||
@for (p of infillPatterns(); track p.value) {
|
||||
<option [value]="p.value">{{ p.label }}</option>
|
||||
}
|
||||
</select>
|
||||
</label>
|
||||
<label>
|
||||
{{ "CALC.NOZZLE" | translate }}
|
||||
<select formControlName="nozzleDiameter">
|
||||
@for (n of nozzleDiameters(); track n.value) {
|
||||
<option [value]="n.value">{{ n.label }}</option>
|
||||
}
|
||||
</select>
|
||||
</label>
|
||||
</div>
|
||||
|
||||
<label>
|
||||
{{ "CALC.LAYER_HEIGHT" | translate }}
|
||||
<select
|
||||
[value]="selectedItem.layerHeight ?? form.get('layerHeight')?.value"
|
||||
(change)="
|
||||
updateSelectedItemNumberField(
|
||||
'layerHeight',
|
||||
+$any($event.target).value
|
||||
)
|
||||
"
|
||||
>
|
||||
@for (l of layerHeights(); track l.value) {
|
||||
<option [value]="l.value">{{ l.label }}</option>
|
||||
}
|
||||
</select>
|
||||
</label>
|
||||
</div>
|
||||
<div class="item-settings-grid">
|
||||
<label>
|
||||
{{ "CALC.PATTERN" | translate }}
|
||||
<select formControlName="infillPattern">
|
||||
@for (p of infillPatterns(); track p.value) {
|
||||
<option [value]="p.value">{{ p.label }}</option>
|
||||
}
|
||||
</select>
|
||||
</label>
|
||||
|
||||
<div class="item-settings-grid">
|
||||
<label>
|
||||
{{ "CALC.INFILL" | translate }}
|
||||
<input
|
||||
type="number"
|
||||
min="0"
|
||||
max="100"
|
||||
[value]="
|
||||
selectedItem.infillDensity ?? form.get('infillDensity')?.value
|
||||
"
|
||||
(change)="
|
||||
updateSelectedItemNumberField(
|
||||
'infillDensity',
|
||||
+$any($event.target).value
|
||||
)
|
||||
"
|
||||
/>
|
||||
</label>
|
||||
<label>
|
||||
{{ "CALC.LAYER_HEIGHT" | translate }}
|
||||
<select formControlName="layerHeight">
|
||||
@for (l of getLayerHeightOptionsForNozzle(form.get('nozzleDiameter')?.value); track l.value) {
|
||||
<option [value]="l.value">{{ l.label }}</option>
|
||||
}
|
||||
</select>
|
||||
</label>
|
||||
</div>
|
||||
|
||||
<label class="item-settings-checkbox">
|
||||
<input
|
||||
type="checkbox"
|
||||
[checked]="
|
||||
selectedItem.supportEnabled ?? form.get('supportEnabled')?.value
|
||||
"
|
||||
(change)="updateSelectedItemSupport($any($event.target).checked)"
|
||||
/>
|
||||
<span>{{ "CALC.SUPPORT" | translate }}</span>
|
||||
</label>
|
||||
<div class="item-settings-grid">
|
||||
<label>
|
||||
{{ "CALC.INFILL" | translate }}
|
||||
<input
|
||||
type="number"
|
||||
min="0"
|
||||
max="100"
|
||||
formControlName="infillDensity"
|
||||
/>
|
||||
</label>
|
||||
|
||||
<label class="item-settings-checkbox">
|
||||
<input type="checkbox" formControlName="supportEnabled" />
|
||||
<span>{{ "CALC.SUPPORT" | translate }}</span>
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
}
|
||||
</div>
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -349,7 +258,6 @@
|
||||
@if (items().length === 0 && form.get("itemsTouched")?.value) {
|
||||
<div class="error-msg">{{ "CALC.ERR_FILE_REQUIRED" | translate }}</div>
|
||||
}
|
||||
|
||||
</div>
|
||||
|
||||
<app-input
|
||||
@@ -359,7 +267,6 @@
|
||||
></app-input>
|
||||
|
||||
<div class="actions">
|
||||
<!-- Progress Bar (Only when uploading i.e. progress < 100) -->
|
||||
@if (loading() && uploadProgress() < 100) {
|
||||
<div class="progress-container">
|
||||
<div class="progress-bar">
|
||||
|
||||
@@ -2,8 +2,8 @@
|
||||
margin-bottom: var(--space-6);
|
||||
}
|
||||
.upload-privacy-note {
|
||||
margin-top: var(--space-6);
|
||||
margin-bottom: 0;
|
||||
margin-top: var(--space-4);
|
||||
margin-bottom: var(--space-1);
|
||||
font-size: 0.8rem;
|
||||
color: var(--color-text-muted);
|
||||
text-align: left;
|
||||
@@ -35,48 +35,50 @@
|
||||
/* Grid Layout for Files */
|
||||
.items-grid {
|
||||
display: grid;
|
||||
grid-template-columns: 1fr 1fr; /* Force 2 columns on mobile */
|
||||
gap: var(--space-2); /* Tighten gap for mobile */
|
||||
grid-template-columns: 1fr;
|
||||
gap: var(--space-3);
|
||||
margin-top: var(--space-4);
|
||||
margin-bottom: var(--space-4);
|
||||
|
||||
@media (min-width: 640px) {
|
||||
grid-template-columns: 1fr 1fr;
|
||||
gap: var(--space-3);
|
||||
}
|
||||
}
|
||||
|
||||
.file-card {
|
||||
padding: var(--space-2); /* Reduced from space-3 */
|
||||
background: var(--color-neutral-100);
|
||||
padding: var(--space-3);
|
||||
background: var(--color-bg-card);
|
||||
border: 1px solid var(--color-border);
|
||||
border-radius: var(--radius-md);
|
||||
transition: all 0.2s;
|
||||
cursor: pointer;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 4px; /* Reduced gap */
|
||||
position: relative; /* For absolute positioning of remove btn */
|
||||
min-width: 0; /* Allow flex item to shrink below content size if needed */
|
||||
gap: var(--space-2);
|
||||
position: relative;
|
||||
min-width: 0;
|
||||
|
||||
&:hover {
|
||||
border-color: var(--color-neutral-300);
|
||||
box-shadow: 0 4px 10px rgba(10, 20, 30, 0.07);
|
||||
}
|
||||
&.active {
|
||||
border-color: var(--color-brand);
|
||||
background: rgba(250, 207, 10, 0.05);
|
||||
background: rgba(250, 207, 10, 0.08);
|
||||
box-shadow: 0 0 0 1px var(--color-brand);
|
||||
}
|
||||
}
|
||||
|
||||
.card-header {
|
||||
overflow: hidden;
|
||||
padding-right: 25px; /* Adjusted */
|
||||
margin-bottom: 2px;
|
||||
padding-right: 28px;
|
||||
margin-bottom: 0;
|
||||
}
|
||||
|
||||
.file-name {
|
||||
font-weight: 500;
|
||||
font-size: 0.8rem; /* Smaller font */
|
||||
font-weight: 600;
|
||||
font-size: 0.92rem;
|
||||
color: var(--color-text);
|
||||
display: block;
|
||||
white-space: nowrap;
|
||||
@@ -92,47 +94,46 @@
|
||||
|
||||
.card-controls {
|
||||
display: flex;
|
||||
align-items: flex-end; /* Align bottom of input and color circle */
|
||||
gap: 16px; /* Space between Qty and Color */
|
||||
align-items: flex-end;
|
||||
gap: var(--space-4);
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.qty-group,
|
||||
.color-group {
|
||||
display: flex;
|
||||
flex-direction: column; /* Stack label and input */
|
||||
flex-direction: column;
|
||||
align-items: flex-start;
|
||||
gap: 0px;
|
||||
gap: 2px;
|
||||
|
||||
label {
|
||||
font-size: 0.6rem;
|
||||
font-size: 0.72rem;
|
||||
color: var(--color-text-muted);
|
||||
text-transform: uppercase;
|
||||
letter-spacing: 0.5px;
|
||||
letter-spacing: 0.3px;
|
||||
font-weight: 600;
|
||||
margin-bottom: 2px;
|
||||
margin-bottom: 0;
|
||||
}
|
||||
}
|
||||
|
||||
.color-group {
|
||||
align-items: flex-start; /* Align label left */
|
||||
/* margin-right removed */
|
||||
align-items: flex-start;
|
||||
|
||||
/* Override margin in selector for this context */
|
||||
::ng-deep .color-selector-container {
|
||||
margin-left: 0;
|
||||
}
|
||||
}
|
||||
|
||||
.qty-input {
|
||||
width: 36px; /* Slightly smaller */
|
||||
padding: 1px 2px;
|
||||
width: 54px;
|
||||
padding: 4px 6px;
|
||||
border: 1px solid var(--color-border);
|
||||
border-radius: var(--radius-sm);
|
||||
text-align: center;
|
||||
font-size: 0.85rem;
|
||||
font-size: 0.95rem;
|
||||
font-weight: 600;
|
||||
background: white;
|
||||
height: 24px; /* Explicit height to match color circle somewhat */
|
||||
height: 34px;
|
||||
&:focus {
|
||||
outline: none;
|
||||
border-color: var(--color-brand);
|
||||
@@ -141,10 +142,10 @@
|
||||
|
||||
.btn-remove {
|
||||
position: absolute;
|
||||
top: 4px;
|
||||
right: 4px;
|
||||
width: 18px;
|
||||
height: 18px;
|
||||
top: 6px;
|
||||
right: 6px;
|
||||
width: 20px;
|
||||
height: 20px;
|
||||
border-radius: 4px;
|
||||
border: none;
|
||||
background: transparent;
|
||||
@@ -155,7 +156,7 @@
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
transition: all 0.2s;
|
||||
font-size: 0.8rem;
|
||||
font-size: 0.9rem;
|
||||
|
||||
&:hover {
|
||||
background: var(--color-danger-100);
|
||||
@@ -170,7 +171,7 @@
|
||||
|
||||
.btn-add-more {
|
||||
width: 100%;
|
||||
padding: var(--space-3);
|
||||
padding: 0.75rem var(--space-3);
|
||||
background: var(--color-neutral-800);
|
||||
color: white;
|
||||
border: none;
|
||||
@@ -193,6 +194,50 @@
|
||||
}
|
||||
}
|
||||
|
||||
.sync-settings {
|
||||
margin-top: var(--space-4);
|
||||
margin-bottom: var(--space-4);
|
||||
border: 1px solid var(--color-border);
|
||||
border-radius: var(--radius-md);
|
||||
background: var(--color-neutral-50);
|
||||
padding: var(--space-3);
|
||||
}
|
||||
|
||||
.sync-settings-toggle {
|
||||
display: flex;
|
||||
align-items: flex-start;
|
||||
gap: var(--space-3);
|
||||
cursor: pointer;
|
||||
|
||||
input[type="checkbox"] {
|
||||
width: 20px;
|
||||
height: 20px;
|
||||
margin-top: 2px;
|
||||
accent-color: var(--color-brand);
|
||||
flex-shrink: 0;
|
||||
}
|
||||
}
|
||||
|
||||
.sync-settings-copy {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 2px;
|
||||
}
|
||||
|
||||
.sync-settings-title {
|
||||
font-size: 0.95rem;
|
||||
font-weight: 700;
|
||||
color: var(--color-text);
|
||||
line-height: 1.2;
|
||||
}
|
||||
|
||||
.sync-settings-subtitle {
|
||||
font-size: 0.8rem;
|
||||
font-weight: 500;
|
||||
color: var(--color-text-muted);
|
||||
line-height: 1.35;
|
||||
}
|
||||
|
||||
.checkbox-row {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user