small improvements:
- add colorview component - improve generic action column - improve generic table - improve event-type-table.component.ts - add headerText to admin layout
This commit is contained in:
parent
b047ecc589
commit
008b644bb1
@ -12,7 +12,7 @@
|
|||||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M4 6h16M4 12h16M4 18h16"></path>
|
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M4 6h16M4 12h16M4 18h16"></path>
|
||||||
</svg>
|
</svg>
|
||||||
</label>
|
</label>
|
||||||
<a class="btn btn-ghost text-xl">daisyUI</a>
|
<a class="btn btn-ghost text-xl">{{headerText()}}</a>
|
||||||
</div>
|
</div>
|
||||||
@if (loggedIn()) {
|
@if (loggedIn()) {
|
||||||
<div class="flex-none">
|
<div class="flex-none">
|
||||||
|
|||||||
@ -8,6 +8,7 @@ import { Component, input, output } from '@angular/core';
|
|||||||
})
|
})
|
||||||
export class AdminLayoutRs1 {
|
export class AdminLayoutRs1 {
|
||||||
|
|
||||||
|
headerText = input<string>();
|
||||||
|
|
||||||
readonly loggedIn = input<boolean>(false)
|
readonly loggedIn = input<boolean>(false)
|
||||||
|
|
||||||
|
|||||||
@ -1,4 +1,4 @@
|
|||||||
<rs-daisy-admin-layout-rs1 (clickEvent)="logout()" [loggedIn]="loggedIn()">
|
<rs-daisy-admin-layout-rs1 [headerText]="'Foglalási rendszer'" (clickEvent)="logout()" [loggedIn]="loggedIn()">
|
||||||
|
|
||||||
<app-menu
|
<app-menu
|
||||||
[title]="menuTitle"
|
[title]="menuTitle"
|
||||||
|
|||||||
0
admin/src/app/components/color-view/color-view.css
Normal file
0
admin/src/app/components/color-view/color-view.css
Normal file
8
admin/src/app/components/color-view/color-view.html
Normal file
8
admin/src/app/components/color-view/color-view.html
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
@if (color()) {
|
||||||
|
<div class="flex flex-row gap-1 items-center">
|
||||||
|
<div class='min-w-3 min-h-3 w-3 h-3'
|
||||||
|
[style]="'background-color: ' + color()"
|
||||||
|
></div>
|
||||||
|
{{color()}}
|
||||||
|
</div>
|
||||||
|
}
|
||||||
23
admin/src/app/components/color-view/color-view.spec.ts
Normal file
23
admin/src/app/components/color-view/color-view.spec.ts
Normal file
@ -0,0 +1,23 @@
|
|||||||
|
import { ComponentFixture, TestBed } from '@angular/core/testing';
|
||||||
|
|
||||||
|
import { ColorView } from './color-view';
|
||||||
|
|
||||||
|
describe('ColorView', () => {
|
||||||
|
let component: ColorView;
|
||||||
|
let fixture: ComponentFixture<ColorView>;
|
||||||
|
|
||||||
|
beforeEach(async () => {
|
||||||
|
await TestBed.configureTestingModule({
|
||||||
|
imports: [ColorView]
|
||||||
|
})
|
||||||
|
.compileComponents();
|
||||||
|
|
||||||
|
fixture = TestBed.createComponent(ColorView);
|
||||||
|
component = fixture.componentInstance;
|
||||||
|
fixture.detectChanges();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should create', () => {
|
||||||
|
expect(component).toBeTruthy();
|
||||||
|
});
|
||||||
|
});
|
||||||
11
admin/src/app/components/color-view/color-view.ts
Normal file
11
admin/src/app/components/color-view/color-view.ts
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
import { Component, input } from '@angular/core';
|
||||||
|
|
||||||
|
@Component({
|
||||||
|
selector: 'app-color-view',
|
||||||
|
imports: [],
|
||||||
|
templateUrl: './color-view.html',
|
||||||
|
styleUrl: './color-view.css',
|
||||||
|
})
|
||||||
|
export class ColorView {
|
||||||
|
color = input<string>();
|
||||||
|
}
|
||||||
@ -1,5 +1,7 @@
|
|||||||
|
<div class="flex flex-row gap-1 items-center">
|
||||||
|
|
||||||
@for (action of actions(); track action){
|
@for (action of actions(); track action){
|
||||||
<a class="btn btn-primary" (click)="onClick($event,action)">
|
<a class="btn btn-primary" title="{{action.title ?? '' }}" (click)="onClick($event,action)">
|
||||||
@if(action.svgIcon){
|
@if(action.svgIcon){
|
||||||
<span [outerHTML]="action.svgIcon | safeHtml"></span>
|
<span [outerHTML]="action.svgIcon | safeHtml"></span>
|
||||||
}
|
}
|
||||||
@ -8,3 +10,4 @@
|
|||||||
}
|
}
|
||||||
</a>
|
</a>
|
||||||
}
|
}
|
||||||
|
</div>
|
||||||
|
|||||||
@ -1,10 +1,14 @@
|
|||||||
import { Component, inject, input, OnInit } from '@angular/core';
|
import { Component, inject, input, OnInit } from '@angular/core';
|
||||||
import { Router } from '@angular/router';
|
import { Router } from '@angular/router';
|
||||||
import { SafeHtmlPipe } from '../../pipes/safe-html-pipe';
|
import { SafeHtmlPipe } from '../../pipes/safe-html-pipe';
|
||||||
|
import { SvgIcons } from '../../svg-icons';
|
||||||
|
import { EventType } from '../../features/event-type/models/event-type.model';
|
||||||
|
import { CellDefinition, StyleClassContext } from '../generic-table/cell-definition.interface';
|
||||||
|
|
||||||
export interface ActionDefinition<T> {
|
export interface ActionDefinition<T> {
|
||||||
action: string;
|
action: string;
|
||||||
text?: string|false;
|
text?: string | false;
|
||||||
|
title?: string;
|
||||||
generate: (action: string, item?: T) => string;
|
generate: (action: string, item?: T) => string;
|
||||||
handler?: (action: ActionDefinition<T>, item?: T) => void;
|
handler?: (action: ActionDefinition<T>, item?: T) => void;
|
||||||
svgIcon?: string; //https://heroicons.com/
|
svgIcon?: string; //https://heroicons.com/
|
||||||
@ -30,12 +34,45 @@ export class GenericActionColumn<T> implements OnInit {
|
|||||||
ngOnInit(): void {
|
ngOnInit(): void {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
onClick($event: any, actionDefinition: ActionDefinition<T>) {
|
onClick($event: any, actionDefinition: ActionDefinition<T>) {
|
||||||
if (actionDefinition?.handler) {
|
if (actionDefinition?.handler) {
|
||||||
actionDefinition.handler(actionDefinition, this.item());
|
actionDefinition.handler(actionDefinition, this.item());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export interface CreateActionColumnCellDefinitionContext<T> {
|
||||||
|
actionHandler?: (action: ActionDefinition<T>, item?: T) => void;
|
||||||
|
styleClass?: (definition: StyleClassContext<T>) => string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export const createActionColumnCellDefinition = <T>(createCtx: CreateActionColumnCellDefinitionContext<T>): CellDefinition<T> => {
|
||||||
|
return {
|
||||||
|
styleClass: createCtx.styleClass ?? (ctx => 'w-[1%]'),
|
||||||
|
component: GenericActionColumn,
|
||||||
|
componentInputs: item => ({
|
||||||
|
item: item,
|
||||||
|
actions: [
|
||||||
|
{
|
||||||
|
action: 'view',
|
||||||
|
title: 'Részletek',
|
||||||
|
text: false,
|
||||||
|
handler: createCtx.actionHandler,
|
||||||
|
svgIcon: SvgIcons.heroDocument,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
action: 'edit', title: 'Szerkesztés', text: false,
|
||||||
|
svgIcon: SvgIcons.heroCog6Tooth,
|
||||||
|
handler: createCtx.actionHandler,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
action: 'delete',
|
||||||
|
title: 'Törlés',
|
||||||
|
text: false,
|
||||||
|
handler: createCtx.actionHandler,
|
||||||
|
svgIcon: SvgIcons.heroTrash,
|
||||||
|
},
|
||||||
|
] as ActionDefinition<EventType>[],
|
||||||
|
}),
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|||||||
@ -5,8 +5,6 @@ export interface TypeDefinition{
|
|||||||
params?: Record<string, any>;
|
params?: Record<string, any>;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
export interface ColumnDefinition<T> {
|
export interface ColumnDefinition<T> {
|
||||||
attribute: keyof T;
|
attribute: keyof T;
|
||||||
type: TypeDefinition;
|
type: TypeDefinition;
|
||||||
|
|||||||
@ -4,7 +4,7 @@
|
|||||||
|
|
||||||
</div>
|
</div>
|
||||||
@if (data$ | async; as getDataResponse) {
|
@if (data$ | async; as getDataResponse) {
|
||||||
<table class="table w-full table-zebra">
|
<table class="table w-full table-zebra" [class]="config.tableCssClass ?? ''">
|
||||||
<thead>
|
<thead>
|
||||||
<tr>
|
<tr>
|
||||||
|
|
||||||
@ -37,10 +37,10 @@
|
|||||||
<td [class]="getValueStyleClass(column!,column.valueCell!,item) ">
|
<td [class]="getValueStyleClass(column!,column.valueCell!,item) ">
|
||||||
@if (column.valueCell) {
|
@if (column.valueCell) {
|
||||||
@if (typeof column.valueCell === 'boolean') {
|
@if (typeof column.valueCell === 'boolean') {
|
||||||
{{ resolveValue(item, column) }}
|
<div [outerHTML]=" resolveValue(item, column) | safeHtml "></div>
|
||||||
} @else {
|
} @else {
|
||||||
@if (!column.valueCell.component) {
|
@if (!column.valueCell.component) {
|
||||||
{{ resolveValue(item, column, column.valueCell) }}
|
<div [outerHTML]=" resolveValue(item, column, column.valueCell) | safeHtml "></div>
|
||||||
} @else {
|
} @else {
|
||||||
<ng-container
|
<ng-container
|
||||||
*ngComponentOutlet="column.valueCell.component; inputs: getComponentInputs(item, column,column.valueCell)"></ng-container>
|
*ngComponentOutlet="column.valueCell.component; inputs: getComponentInputs(item, column,column.valueCell)"></ng-container>
|
||||||
|
|||||||
@ -8,11 +8,12 @@ import { DomSanitizer } from '@angular/platform-browser';
|
|||||||
import { GenericTableConfig } from './generic-table.config';
|
import { GenericTableConfig } from './generic-table.config';
|
||||||
import { startWith, switchMap } from 'rxjs/operators';
|
import { startWith, switchMap } from 'rxjs/operators';
|
||||||
import { GenericTableSearchForm } from './generic-table-search-form/generic-table-search-form';
|
import { GenericTableSearchForm } from './generic-table-search-form/generic-table-search-form';
|
||||||
|
import { SafeHtmlPipe } from '../../pipes/safe-html-pipe';
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'app-generic-table',
|
selector: 'app-generic-table',
|
||||||
templateUrl: './generic-table.html',
|
templateUrl: './generic-table.html',
|
||||||
imports: [NgClass, AsyncPipe, NgComponentOutlet, GenericTableSearchForm],
|
imports: [NgClass, AsyncPipe, NgComponentOutlet, GenericTableSearchForm, SafeHtmlPipe],
|
||||||
standalone: true,
|
standalone: true,
|
||||||
})
|
})
|
||||||
export class GenericTable<T> implements OnInit {
|
export class GenericTable<T> implements OnInit {
|
||||||
@ -68,7 +69,7 @@ export class GenericTable<T> implements OnInit {
|
|||||||
if (cell.componentInputs) {
|
if (cell.componentInputs) {
|
||||||
return cell.componentInputs(item);
|
return cell.componentInputs(item);
|
||||||
}
|
}
|
||||||
return { data: item }; // Default input
|
return { item }; // Default input
|
||||||
}
|
}
|
||||||
|
|
||||||
getAsHtml(str: string) {
|
getAsHtml(str: string) {
|
||||||
|
|||||||
@ -3,7 +3,7 @@
|
|||||||
<!-- Generated by the CLI -->
|
<!-- Generated by the CLI -->
|
||||||
<div class="p-4 md:p-8 space-y-6">
|
<div class="p-4 md:p-8 space-y-6">
|
||||||
<div class="flex justify-between items-center">
|
<div class="flex justify-between items-center">
|
||||||
<h1 class="text-3xl font-bold">EventTypes (Generic Table)</h1>
|
<h1 class="text-3xl font-bold">Esemény típusok</h1>
|
||||||
<a routerLink="/event-type/new" class="btn btn-primary">Create New</a>
|
<a routerLink="/event-type/new" class="btn btn-primary">Create New</a>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|||||||
@ -15,6 +15,7 @@ import {
|
|||||||
import { EventTypeService } from '../../services/event-type.service';
|
import { EventTypeService } from '../../services/event-type.service';
|
||||||
import { BehaviorSubject } from 'rxjs';
|
import { BehaviorSubject } from 'rxjs';
|
||||||
import { SvgIcons } from '../../../../svg-icons';
|
import { SvgIcons } from '../../../../svg-icons';
|
||||||
|
import { ColorView } from '../../../../components/color-view/color-view';
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'app-event-type-table',
|
selector: 'app-event-type-table',
|
||||||
@ -60,42 +61,52 @@ export class EventTypeTableComponent implements OnInit {
|
|||||||
{
|
{
|
||||||
attribute: 'name',
|
attribute: 'name',
|
||||||
headerCell: true,
|
headerCell: true,
|
||||||
valueCell: true,
|
valueCell: {
|
||||||
|
styleClass: ctx => 'w-[1%]',
|
||||||
|
value: item => item?.name,
|
||||||
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
attribute: 'description',
|
attribute: 'description',
|
||||||
headerCell: true,
|
headerCell: true,
|
||||||
valueCell: {
|
valueCell: {
|
||||||
styleClass: ctx => 'w-auto',
|
|
||||||
value: item => item?.description,
|
value: item => item?.description,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
attribute: 'color',
|
attribute: 'color',
|
||||||
headerCell: true,
|
headerCell: true,
|
||||||
valueCell: true,
|
valueCell: {
|
||||||
|
styleClass: ctx => 'w-[1%]',
|
||||||
|
value: item => item?.color,
|
||||||
|
component: ColorView,
|
||||||
|
componentInputs: item => {
|
||||||
|
return { color: item?.color };
|
||||||
|
}
|
||||||
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
attribute: 'actions',
|
attribute: 'actions',
|
||||||
headerCell: { value: 'Actions' },
|
headerCell: { value: 'Actions' },
|
||||||
valueCell: {
|
valueCell: {
|
||||||
|
styleClass: ctx => 'w-[1%]',
|
||||||
component: GenericActionColumn,
|
component: GenericActionColumn,
|
||||||
componentInputs: item => ({
|
componentInputs: item => ({
|
||||||
item: item,
|
item: item,
|
||||||
actions: [
|
actions: [
|
||||||
{ action: 'view', text: false, handler: actionHandler, svgIcon: SvgIcons.heroDocument },
|
{ action: 'view', title: 'Részletek', text: false, handler: actionHandler, svgIcon: SvgIcons.heroDocument },
|
||||||
{
|
{
|
||||||
action: 'edit', text: false,
|
action: 'edit', title: 'Szerkesztés', text: false,
|
||||||
svgIcon: SvgIcons.heroCog6Tooth,
|
svgIcon: SvgIcons.heroCog6Tooth,
|
||||||
handler: actionHandler,
|
handler: actionHandler,
|
||||||
},
|
},
|
||||||
{ action: 'delete', text: false, handler: actionHandler, svgIcon: SvgIcons.heroTrash },
|
{ action: 'delete', title: 'Törlés', text: false, handler: actionHandler, svgIcon: SvgIcons.heroTrash },
|
||||||
] as ActionDefinition<EventType>[],
|
] as ActionDefinition<EventType>[],
|
||||||
}),
|
}),
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
] as ColumnDefinition<EventType>[],
|
] as ColumnDefinition<EventType>[],
|
||||||
tableCssClass: 'event-type-table-container',
|
tableCssClass: 'event-type-table-container w-full',
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user