diff --git a/backend/i18n/frontend_en.json b/backend/i18n/frontend_en.json index 4caac7885..91eb3b609 100644 --- a/backend/i18n/frontend_en.json +++ b/backend/i18n/frontend_en.json @@ -251,6 +251,7 @@ "common.disabled": "Disabled", "common.displayName": "Display Name", "common.documentation": "Documentation", + "common.download": "Download", "common.edit": "Edit", "common.editing": "Editing", "common.editInNewTab": "Open in new tab", diff --git a/backend/i18n/frontend_fr.json b/backend/i18n/frontend_fr.json index b477ad81c..33bb11ad2 100644 --- a/backend/i18n/frontend_fr.json +++ b/backend/i18n/frontend_fr.json @@ -251,6 +251,7 @@ "common.disabled": "Désactivé", "common.displayName": "Afficher un nom", "common.documentation": "Documentation", + "common.download": "Download", "common.edit": "Modifier", "common.editing": "Édition", "common.editInNewTab": "Open in new tab", diff --git a/backend/i18n/frontend_it.json b/backend/i18n/frontend_it.json index a63f23382..21aaa134e 100644 --- a/backend/i18n/frontend_it.json +++ b/backend/i18n/frontend_it.json @@ -251,6 +251,7 @@ "common.disabled": "Disabled", "common.displayName": "Nome visualizzato", "common.documentation": "Documentation", + "common.download": "Download", "common.edit": "Modifica", "common.editing": "Editing", "common.editInNewTab": "Open in new tab", diff --git a/backend/i18n/frontend_nl.json b/backend/i18n/frontend_nl.json index f32f93344..8853edbef 100644 --- a/backend/i18n/frontend_nl.json +++ b/backend/i18n/frontend_nl.json @@ -251,6 +251,7 @@ "common.disabled": "Uitgezet", "common.displayName": "Weergavenaam", "common.documentation": "Documentation", + "common.download": "Download", "common.edit": "Bewerken", "common.editing": "Bewerken", "common.editInNewTab": "Open in new tab", diff --git a/backend/i18n/frontend_pt.json b/backend/i18n/frontend_pt.json index 1c0c73a18..dd30dfe80 100644 --- a/backend/i18n/frontend_pt.json +++ b/backend/i18n/frontend_pt.json @@ -251,6 +251,7 @@ "common.disabled": "Deficientes", "common.displayName": "Nome do visor", "common.documentation": "Documentação", + "common.download": "Download", "common.edit": "Editar", "common.editing": "Edição", "common.editInNewTab": "Open in new tab", diff --git a/backend/i18n/frontend_zh.json b/backend/i18n/frontend_zh.json index a168e9630..4616278a9 100644 --- a/backend/i18n/frontend_zh.json +++ b/backend/i18n/frontend_zh.json @@ -251,6 +251,7 @@ "common.disabled": "已禁用", "common.displayName": "显示名称", "common.documentation": "Documentation", + "common.download": "Download", "common.edit": "编辑", "common.editing": "Editing", "common.editInNewTab": "Open in new tab", diff --git a/backend/i18n/source/frontend_en.json b/backend/i18n/source/frontend_en.json index 4caac7885..91eb3b609 100644 --- a/backend/i18n/source/frontend_en.json +++ b/backend/i18n/source/frontend_en.json @@ -251,6 +251,7 @@ "common.disabled": "Disabled", "common.displayName": "Display Name", "common.documentation": "Documentation", + "common.download": "Download", "common.edit": "Edit", "common.editing": "Editing", "common.editInNewTab": "Open in new tab", diff --git a/backend/src/Squidex.Domain.Apps.Core.Model/Assets/Asset.cs b/backend/src/Squidex.Domain.Apps.Core.Model/Assets/Asset.cs index 7a4f69a70..772833fb1 100644 --- a/backend/src/Squidex.Domain.Apps.Core.Model/Assets/Asset.cs +++ b/backend/src/Squidex.Domain.Apps.Core.Model/Assets/Asset.cs @@ -53,27 +53,27 @@ public record Asset : AssetItem if (fileName != null && !string.Equals(FileName, fileName, StringComparison.OrdinalIgnoreCase)) { - result = this with { FileName = fileName }; + result = result with { FileName = fileName }; } if (slug != null && !string.Equals(Slug, slug, StringComparison.OrdinalIgnoreCase)) { - result = this with { Slug = slug }; + result = result with { Slug = slug }; } if (isProtected != null && IsProtected != isProtected.Value) { - result = this with { IsProtected = isProtected.Value }; + result = result with { IsProtected = isProtected.Value }; } if (tags != null && !Tags.SetEquals(tags)) { - result = this with { Tags = tags }; + result = result with { Tags = tags }; } if (metadata != null && !Metadata.EqualsDictionary(metadata)) { - result = this with { Metadata = metadata }; + result = result with { Metadata = metadata }; } return result; diff --git a/backend/src/Squidex.Domain.Apps.Entities/Assets/SvgAssetMetadataSource.cs b/backend/src/Squidex.Domain.Apps.Entities/Assets/SvgAssetMetadataSource.cs index eb1237126..5fe104d9f 100644 --- a/backend/src/Squidex.Domain.Apps.Entities/Assets/SvgAssetMetadataSource.cs +++ b/backend/src/Squidex.Domain.Apps.Entities/Assets/SvgAssetMetadataSource.cs @@ -52,11 +52,28 @@ public sealed class SvgAssetMetadataSource : IAssetMetadataSource if (!string.IsNullOrWhiteSpace(width) && !string.IsNullOrWhiteSpace(height)) { - command.Metadata[KnownMetadataKeys.SvgWidth] = width; - command.Metadata[KnownMetadataKeys.SvgHeight] = height; + var hasNumericWidth = TryParseInt(width, out var w); + var hasNumericHeight = TryParseInt(height, out var h); - if (int.TryParse(width, NumberStyles.Integer, CultureInfo.InvariantCulture, out var w) && - int.TryParse(height, NumberStyles.Integer, CultureInfo.InvariantCulture, out var h)) + if (hasNumericWidth) + { + command.Metadata[KnownMetadataKeys.SvgWidth] = w; + } + else + { + command.Metadata[KnownMetadataKeys.SvgWidth] = width; + } + + if (hasNumericWidth) + { + command.Metadata[KnownMetadataKeys.SvgHeight] = h; + } + else + { + command.Metadata[KnownMetadataKeys.SvgHeight] = height; + } + + if (hasNumericWidth && hasNumericHeight) { command.Metadata[KnownMetadataKeys.PixelWidth] = w; command.Metadata[KnownMetadataKeys.PixelHeight] = h; @@ -79,6 +96,11 @@ public sealed class SvgAssetMetadataSource : IAssetMetadataSource } } + private static bool TryParseInt(string value, out int result) + { + return int.TryParse(value, NumberStyles.Integer, CultureInfo.InvariantCulture, out result); + } + public IEnumerable Format(Asset asset) { var isSvg = @@ -90,8 +112,8 @@ public sealed class SvgAssetMetadataSource : IAssetMetadataSource yield break; } - if (asset.Metadata.TryGetString(KnownMetadataKeys.SvgWidth, out var w) && - asset.Metadata.TryGetString(KnownMetadataKeys.SvgHeight, out var h)) + if (asset.Metadata.TryGetValue(KnownMetadataKeys.SvgWidth, out var w) && + asset.Metadata.TryGetValue(KnownMetadataKeys.SvgHeight, out var h)) { yield return $"{w}x{h}"; } diff --git a/backend/tests/Squidex.Domain.Apps.Core.Tests/Model/Assets/AssetTests.cs b/backend/tests/Squidex.Domain.Apps.Core.Tests/Model/Assets/AssetTests.cs index af94e0052..23271719f 100644 --- a/backend/tests/Squidex.Domain.Apps.Core.Tests/Model/Assets/AssetTests.cs +++ b/backend/tests/Squidex.Domain.Apps.Core.Tests/Model/Assets/AssetTests.cs @@ -143,6 +143,23 @@ public class AssetTests Assert.Same(asset_1, asset_2); } + [Fact] + public void Should_annotate_with_multiple_properties() + { + var newSlug = "my-file.png"; + var newFile = "My File"; + + var asset_1 = asset_0.Annotate(fileName: newFile, slug: newSlug); + var asset_2 = asset_1.Annotate(fileName: newFile, slug: newSlug); + + Assert.NotSame(asset_0, asset_1); + Assert.Equal(newSlug, asset_1.Slug); + Assert.Equal(newSlug, asset_2.Slug); + Assert.Equal(newFile, asset_1.FileName); + Assert.Equal(newFile, asset_2.FileName); + Assert.Same(asset_1, asset_2); + } + [Fact] public void Should_deserialize_state() { diff --git a/backend/tests/Squidex.Domain.Apps.Entities.Tests/Assets/SvgAssetMetadataSourceTests.cs b/backend/tests/Squidex.Domain.Apps.Entities.Tests/Assets/SvgAssetMetadataSourceTests.cs index bd0ab7074..a4c24b55c 100644 --- a/backend/tests/Squidex.Domain.Apps.Entities.Tests/Assets/SvgAssetMetadataSourceTests.cs +++ b/backend/tests/Squidex.Domain.Apps.Entities.Tests/Assets/SvgAssetMetadataSourceTests.cs @@ -66,8 +66,24 @@ public class SvgAssetMetadataSourceTests : GivenContext Assert.Equal(20, command.Metadata[KnownMetadataKeys.PixelWidth].AsNumber); Assert.Equal(30, command.Metadata[KnownMetadataKeys.PixelHeight].AsNumber); - Assert.Equal("20", command.Metadata[KnownMetadataKeys.SvgWidth].AsString); - Assert.Equal("30", command.Metadata[KnownMetadataKeys.SvgHeight].AsString); + Assert.Equal(20, command.Metadata[KnownMetadataKeys.SvgWidth].AsNumber); + Assert.Equal(30, command.Metadata[KnownMetadataKeys.SvgHeight].AsNumber); + + Assert.Equal("0 0 100 100", command.Metadata[KnownMetadataKeys.SvgViewBox].AsString); + } + + [Fact] + public async Task Should_annote_with_non_numeric_dimensions() + { + var command = Command("SvgValidNonNumberSizes.svg"); + + await sut.EnhanceAsync(command, default); + + Assert.DoesNotContain(KnownMetadataKeys.PixelWidth, command.Metadata); + Assert.DoesNotContain(KnownMetadataKeys.PixelHeight, command.Metadata); + + Assert.Equal("20%", command.Metadata[KnownMetadataKeys.SvgWidth].AsString); + Assert.Equal("30%", command.Metadata[KnownMetadataKeys.SvgHeight].AsString); Assert.Equal("0 0 100 100", command.Metadata[KnownMetadataKeys.SvgViewBox].AsString); } @@ -103,7 +119,25 @@ public class SvgAssetMetadataSourceTests : GivenContext var formatted = sut.Format(source); - Assert.Equal(new[] { "128x55" }, formatted); + Assert.Equal(["128x55"], formatted); + } + + [Fact] + public void Should_describe_metadata_with_number() + { + var source = CreateAsset() with + { + Metadata = new AssetMetadata + { + [KnownMetadataKeys.SvgWidth] = 128, + [KnownMetadataKeys.SvgHeight] = 55 + }, + MimeType = "image/svg+xml" + }; + + var formatted = sut.Format(source); + + Assert.Equal(["128x55"], formatted); } private static UploadAssetCommand Command(string path) diff --git a/backend/tests/Squidex.Domain.Apps.Entities.Tests/Assets/TestFiles/SvgValidNonNumberSizes.svg b/backend/tests/Squidex.Domain.Apps.Entities.Tests/Assets/TestFiles/SvgValidNonNumberSizes.svg new file mode 100644 index 000000000..37568290f --- /dev/null +++ b/backend/tests/Squidex.Domain.Apps.Entities.Tests/Assets/TestFiles/SvgValidNonNumberSizes.svg @@ -0,0 +1,6 @@ + + + + 410 + + \ No newline at end of file diff --git a/backend/tests/Squidex.Domain.Apps.Entities.Tests/Squidex.Domain.Apps.Entities.Tests.csproj b/backend/tests/Squidex.Domain.Apps.Entities.Tests/Squidex.Domain.Apps.Entities.Tests.csproj index 1b71069b8..b5212d3d9 100644 --- a/backend/tests/Squidex.Domain.Apps.Entities.Tests/Squidex.Domain.Apps.Entities.Tests.csproj +++ b/backend/tests/Squidex.Domain.Apps.Entities.Tests/Squidex.Domain.Apps.Entities.Tests.csproj @@ -70,6 +70,9 @@ PreserveNewest + + PreserveNewest + PreserveNewest diff --git a/frontend/.storybook/main.js b/frontend/.storybook/main.js index 479553f12..adf217b4e 100644 --- a/frontend/.storybook/main.js +++ b/frontend/.storybook/main.js @@ -24,9 +24,11 @@ module.exports = { */ config.plugins.push(new CopyPlugin({ patterns: [ - { from: './node_modules/ace-builds/src-min/', to: 'dependencies/ace/' }, + { from: './node_modules/ace-builds/src-min/', to: './dependencies/ace/' }, ] })); + + config.resolve?.extensions?.push('.d.ts'); return config; }, docs: { diff --git a/frontend/.storybook/tsconfig.json b/frontend/.storybook/tsconfig.json index b17c798fe..737aed524 100644 --- a/frontend/.storybook/tsconfig.json +++ b/frontend/.storybook/tsconfig.json @@ -1,9 +1,6 @@ { "extends": "../tsconfig.app.json", "compilerOptions": { - "types": [ - "node" - ], "allowSyntheticDefaultImports": true }, "exclude": [ diff --git a/frontend/angular.json b/frontend/angular.json index 45ff39f66..78335cae9 100644 --- a/frontend/angular.json +++ b/frontend/angular.json @@ -127,7 +127,7 @@ "inlineCritical": false }, "fonts": true - }, + } }, "development": { "extractLicenses": false, diff --git a/frontend/package.json b/frontend/package.json index 481c61477..8481e96ce 100644 --- a/frontend/package.json +++ b/frontend/package.json @@ -33,7 +33,6 @@ "@lithiumjs/angular": "^8.0.0", "@lithiumjs/ngx-virtual-scroll": "^0.3.2", "@marker.io/browser": "^0.19.0", - "@types/ace": "^0.0.52", "ace-builds": "^1.34.2", "angular-gridster2": "18.0.1", "angular-mentions": "1.5.0", @@ -95,6 +94,7 @@ "@storybook/addon-links": "^8.1.5", "@storybook/angular": "^8.1.5", "@storybook/testing-library": "^0.2.2", + "@types/ace": "^0.0.52", "@types/codemirror": "5.60.15", "@types/core-js": "2.5.8", "@types/jasmine": "5.1.4", diff --git a/frontend/src/app/features/content/pages/content/content-page.component.ts b/frontend/src/app/features/content/pages/content/content-page.component.ts index 0c03b2752..54632ee5f 100644 --- a/frontend/src/app/features/content/pages/content/content-page.component.ts +++ b/frontend/src/app/features/content/pages/content/content-page.component.ts @@ -280,17 +280,23 @@ export class ContentPageComponent implements CanComponentDeactivate, OnInit { this.contentsState.create(value, publish, this.contentId) .subscribe({ next: content => { - if (navigationMode == 'Edit') { - this.contentForm.submitCompleted({ noReset: true }); - this.contentForm.load(content.data, true); + switch (navigationMode) { + case 'Add': + this.contentForm = new EditContentForm(this.languages, this.schema, this.schemasState.schemaMap, this.formContext); + break; - this.router.navigate([content.id, 'history'], { relativeTo: this.route.parent! }); - } else if (navigationMode === 'Close') { - this.autoSaveIgnore = true; + case 'Edit': + this.contentForm.submitCompleted({ noReset: true }); + this.contentForm.load(content.data, true); - this.router.navigate(['./'], { relativeTo: this.route.parent! }); - } else { - this.contentForm = new EditContentForm(this.languages, this.schema, this.schemasState.schemaMap, this.formContext); + this.router.navigate([content.id, 'history'], { relativeTo: this.route.parent! }); + break; + + case 'Close': + this.autoSaveIgnore = true; + + this.router.navigate(['./'], { relativeTo: this.route.parent! }); + break; } }, error: error => { diff --git a/frontend/src/app/features/schemas/pages/schema/fields/field-wizard.component.html b/frontend/src/app/features/schemas/pages/schema/fields/field-wizard.component.html index a83928b9a..1526d47a4 100644 --- a/frontend/src/app/features/schemas/pages/schema/fields/field-wizard.component.html +++ b/frontend/src/app/features/schemas/pages/schema/fields/field-wizard.component.html @@ -9,7 +9,7 @@ @if (editForm) { -
+
} @else { -
+
@@ -88,8 +88,8 @@ @if (!editForm) {
-
-
diff --git a/frontend/src/app/features/schemas/pages/schema/fields/field-wizard.component.ts b/frontend/src/app/features/schemas/pages/schema/fields/field-wizard.component.ts index c3b7e2768..bc97bcfd4 100644 --- a/frontend/src/app/features/schemas/pages/schema/fields/field-wizard.component.ts +++ b/frontend/src/app/features/schemas/pages/schema/fields/field-wizard.component.ts @@ -11,7 +11,8 @@ import { FormsModule, ReactiveFormsModule } from '@angular/forms'; import { AddFieldForm, AppSettingsDto, ControlErrorsComponent, createProperties, DropdownMenuComponent, EditFieldForm, FieldDto, fieldTypes, FocusOnInitDirective, FormAlertComponent, FormErrorComponent, FormHintComponent, LanguagesState, ModalDialogComponent, ModalDirective, ModalModel, ModalPlacementDirective, RootFieldDto, SchemaDto, SchemasState, TooltipDirective, TranslatePipe, Types } from '@app/shared'; import { FieldFormComponent } from './forms/field-form.component'; -const DEFAULT_FIELD = { name: '', partitioning: 'invariant', properties: createProperties('String') }; + +type SaveNavigationMode = 'Close' | 'Add' | 'Edit'; @Component({ standalone: true, @@ -80,60 +81,73 @@ export class FieldWizardComponent implements OnInit { this.dialogClose.emit(); } - public addField(addNew: boolean, edit = false) { + public addField(navigationMode: SaveNavigationMode) { const value = this.addFieldForm.submit(); - if (value) { - this.schemasState.addField(this.schema, value, this.parent) - .subscribe({ - next: dto => { - this.field = dto; + if (!value) { + return; + } - this.addFieldForm.submitCompleted({ newValue: { ...DEFAULT_FIELD } }); + this.schemasState.addField(this.schema, value, this.parent) + .subscribe({ + next: dto => { + switch (navigationMode) { + case 'Add': + this.addFieldForm.submitCompleted({ newValue: { ...DEFAULT_FIELD } }); - if (addNew) { if (Types.isFunction(this.nameInput.nativeElement.focus)) { this.nameInput.nativeElement.focus(); } - } else if (edit) { + + break; + + case 'Edit': + this.field = dto; + this.editForm = new EditFieldForm(this.field.properties); this.editForm.load(this.field.properties); - } else { + break; + + case 'Close': this.emitClose(); - } - }, - error: error => { - this.addFieldForm.submitFailed(error); - }, - }); - } + } + }, + error: error => { + this.addFieldForm.submitFailed(error); + }, + }); } - public save(addNew = false) { + public save(navigationMode: SaveNavigationMode) { if (!this.editForm) { return; } const value = this.editForm.submit(); - if (value) { - const properties = createProperties(this.field.properties.fieldType, value); + if (!value) { + return; + } - this.schemasState.updateField(this.schema, this.field as RootFieldDto, { properties }) - .subscribe({ - next: () => { - this.editForm!.submitCompleted(); + const properties = createProperties(this.field.properties.fieldType, value); - if (addNew) { + this.schemasState.updateField(this.schema, this.field as RootFieldDto, { properties }) + .subscribe({ + next: () => { + switch (navigationMode) { + case 'Add': this.editForm = undefined; - } else { + break; + case 'Close': { this.emitClose(); } - }, - error: error => { - this.editForm!.submitFailed(error); - }, - }); - } + } + }, + error: error => { + this.editForm!.submitFailed(error); + }, + }); } } + +const DEFAULT_FIELD = { name: '', partitioning: 'invariant', properties: createProperties('String') }; \ No newline at end of file diff --git a/frontend/src/app/features/schemas/pages/schema/fields/sortable-field-list.component.html b/frontend/src/app/features/schemas/pages/schema/fields/sortable-field-list.component.html index cc195a29b..9eff5a55e 100644 --- a/frontend/src/app/features/schemas/pages/schema/fields/sortable-field-list.component.html +++ b/frontend/src/app/features/schemas/pages/schema/fields/sortable-field-list.component.html @@ -4,7 +4,7 @@ [cdkDropListDisabled]="!sortable" (cdkDropListDropped)="sortGroups($event)" cdkDropListGroup> - @for (group of fieldGroups; track group) { + @for (group of fieldGroups; track group.id) {
({ props: args, @@ -26,7 +30,7 @@ export default { @@ -37,6 +41,7 @@ export default { decorators: [ moduleMetadata({ imports: [ + FormsModule, ], }), ], diff --git a/frontend/src/app/framework/angular/forms/editors/code-editor.component.ts b/frontend/src/app/framework/angular/forms/editors/code-editor.component.ts index e396da14b..775f4d1af 100644 --- a/frontend/src/app/framework/angular/forms/editors/code-editor.component.ts +++ b/frontend/src/app/framework/angular/forms/editors/code-editor.component.ts @@ -143,7 +143,7 @@ export class CodeEditorComponent extends StatefulControlComponent<{}, any> imple } public async ngAfterViewInit() { - this.valueChanged.pipe(debounceTime(500)) + this.valueChanged.pipe(debounceTime(100)) .subscribe(() => { this.changeValue(); }); diff --git a/frontend/src/app/framework/angular/forms/editors/code-editor.stories.ts b/frontend/src/app/framework/angular/forms/editors/code-editor.stories.ts index 7815986fa..d54fdc3f4 100644 --- a/frontend/src/app/framework/angular/forms/editors/code-editor.stories.ts +++ b/frontend/src/app/framework/angular/forms/editors/code-editor.stories.ts @@ -5,6 +5,8 @@ * Copyright (c) Squidex UG (haftungsbeschränkt). All rights reserved. */ +import { FormsModule } from '@angular/forms'; +import { action } from '@storybook/addon-actions'; import { Meta, moduleMetadata, StoryObj } from '@storybook/angular'; import { CodeEditorComponent, ScriptCompletions } from '@app/framework'; @@ -18,6 +20,12 @@ export default { dropdownFullWidth: { control: 'boolean', }, + singleLine: { + control: false, + }, + change: { + action: 'ngModelChange', + }, }, render: args => ({ props: args, @@ -28,6 +36,8 @@ export default { [disabled]="disabled" [height]="height" [maxLines]="maxLines" + (ngModelChange)="change($event)" + [ngModel]="ngModel" [singleLine]="singleLine" [valueFile]="valueFile" [valueMode]="valueMode" @@ -39,6 +49,7 @@ export default { decorators: [ moduleMetadata({ imports: [ + FormsModule, ], }), ], @@ -63,11 +74,13 @@ type Story = StoryObj; export const Default: Story = { args: { height: 'auto', - }, + ngModel: 'Value', + } as any, }; export const Completions: Story = { args: { + height: 200, completion: COMPLETIONS, }, }; @@ -84,6 +97,8 @@ export const SingleLine: Story = { [disabled]="disabled" [height]="height" [maxLines]="maxLines" + (ngModelChange)="ngModelChange" + [ngModel]="ngModel" [singleLine]="singleLine" [valueFile]="valueFile" [valueMode]="valueMode" @@ -98,5 +113,6 @@ export const SingleLine: Story = { }), args: { singleLine: true, - }, + ngModelChange: action('ngModelChange'), + } as any, }; \ No newline at end of file diff --git a/frontend/src/app/framework/angular/forms/editors/dropdown.component.html b/frontend/src/app/framework/angular/forms/editors/dropdown.component.html index 0bbfa0cc8..47d9a5a8b 100644 --- a/frontend/src/app/framework/angular/forms/editors/dropdown.component.html +++ b/frontend/src/app/framework/angular/forms/editors/dropdown.component.html @@ -29,7 +29,6 @@ adjustHeight="false" [adjustWidth]="dropdownFullWidth" [position]="dropdownPosition" - r scrollX="false" scrollY="true" [sqxAnchoredTo]="input" diff --git a/frontend/src/app/framework/angular/forms/editors/dropdown.stories.ts b/frontend/src/app/framework/angular/forms/editors/dropdown.stories.ts index 8f6cef3a2..7b4372c5e 100644 --- a/frontend/src/app/framework/angular/forms/editors/dropdown.stories.ts +++ b/frontend/src/app/framework/angular/forms/editors/dropdown.stories.ts @@ -6,6 +6,8 @@ */ import { Component } from '@angular/core'; +import { FormsModule } from '@angular/forms'; +import { BrowserAnimationsModule } from '@angular/platform-browser/animations'; import { Meta, moduleMetadata, StoryObj } from '@storybook/angular'; import { DropdownComponent, LocalizerService, RootViewComponent } from '@app/framework'; @@ -52,6 +54,19 @@ export default { dropdownFullWidth: { control: 'boolean', }, + change: { + action:'ngModelChange', + }, + position: { + control: 'radio', + options: [ + 'bottom-start', + 'bottom-end', + ], + }, + }, + args: { + position: 'bottom-start', }, render: args => ({ props: args, @@ -59,10 +74,11 @@ export default { @@ -74,6 +90,8 @@ export default { TestComponent, ], imports: [ + BrowserAnimationsModule, + FormsModule, RootViewComponent, ], providers: [ @@ -146,7 +164,7 @@ export const ComplexValues: Story = { ({ props: args, @@ -26,7 +30,7 @@ export default { @@ -37,6 +41,7 @@ export default { decorators: [ moduleMetadata({ imports: [ + FormsModule, ], }), ], diff --git a/frontend/src/app/framework/angular/forms/editors/tag-editor.stories.ts b/frontend/src/app/framework/angular/forms/editors/tag-editor.stories.ts index fea72a6c6..17ef63f45 100644 --- a/frontend/src/app/framework/angular/forms/editors/tag-editor.stories.ts +++ b/frontend/src/app/framework/angular/forms/editors/tag-editor.stories.ts @@ -6,6 +6,7 @@ */ import { Component } from '@angular/core'; +import { FormsModule } from '@angular/forms'; import { Meta, moduleMetadata, StoryObj } from '@storybook/angular'; import { LocalizerService, RootViewComponent, TagEditorComponent } from '@app/framework'; @@ -52,6 +53,9 @@ export default { disabled: { control: 'boolean', }, + change: { + action:'ngModelChange', + }, }, render: args => ({ props: args, @@ -62,6 +66,7 @@ export default { [disabled]="disabled" [itemsSource]="itemsSource" [itemsSourceLoading]="itemsSourceLoading" + (ngModelChange)="change($event)" [ngModel]="model" [styleScrollable]="styleScrollable" [styleBlank]="styleBlank" @@ -76,6 +81,7 @@ export default { TestComponent, ], imports: [ + FormsModule, RootViewComponent, ], providers: [ diff --git a/frontend/src/app/framework/angular/modals/modal-dialog.component.html b/frontend/src/app/framework/angular/modals/modal-dialog.component.html index 806ada5e1..9788267b1 100644 --- a/frontend/src/app/framework/angular/modals/modal-dialog.component.html +++ b/frontend/src/app/framework/angular/modals/modal-dialog.component.html @@ -7,7 +7,7 @@ - +
} diff --git a/frontend/src/app/framework/angular/modals/modal-dialog.component.ts b/frontend/src/app/framework/angular/modals/modal-dialog.component.ts index 5203053fd..8c8a28c87 100644 --- a/frontend/src/app/framework/angular/modals/modal-dialog.component.ts +++ b/frontend/src/app/framework/angular/modals/modal-dialog.component.ts @@ -8,6 +8,7 @@ import { AfterViewInit, booleanAttribute, ChangeDetectionStrategy, Component, ElementRef, EventEmitter, Input, Output, Renderer2, ViewChild } from '@angular/core'; import { fadeAnimation } from '@app/framework/internal'; +import { TranslatePipe } from '../pipes/translate.pipe'; import { ShortcutComponent } from '../shortcut.component'; import { TourStepDirective } from './tour-step.directive'; @@ -22,6 +23,7 @@ import { TourStepDirective } from './tour-step.directive'; changeDetection: ChangeDetectionStrategy.Default, imports: [ ShortcutComponent, + TranslatePipe, TourStepDirective, ], }) diff --git a/frontend/src/app/shared/components/assets/asset.component.html b/frontend/src/app/shared/components/assets/asset.component.html index a6d221fbb..497306de2 100644 --- a/frontend/src/app/shared/components/assets/asset.component.html +++ b/frontend/src/app/shared/components/assets/asset.component.html @@ -31,13 +31,14 @@
@if (!isDisabled) { - + } @@ -53,6 +54,7 @@ @if (!isDisabled && !removeMode && asset.canDelete) {