@zentto/report-designer 1.6.6 → 1.7.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -72,14 +72,35 @@ const ELEMENT_TYPE_ICONS = {
72
72
  totalPages: '#',
73
73
  };
74
74
  const TOOLBOX_ITEMS = [
75
- { type: 'text', label: 'Text', icon: 'T', preview: 'Aa', description: 'Static text label or title' },
76
- { type: 'field', label: 'Field', icon: 'F', preview: '[Field]', description: 'Data-bound field from a source' },
77
- { type: 'image', label: 'Image', icon: '\u{1F5BC}', preview: '\u{1F304}', description: 'Static or dynamic image' },
78
- { type: 'line', label: 'Line', icon: '/', preview: '\u2500\u2500\u2500', description: 'Horizontal or vertical line' },
79
- { type: 'rect', label: 'Rectangle', icon: '[]', preview: '\u25AD', description: 'Rectangle or filled box' },
80
- { type: 'barcode', label: 'Barcode', icon: 'BC', preview: '||||', description: 'QR, Code128, EAN13, Code39' },
81
- { type: 'pageNumber', label: 'Page #', icon: '#', preview: '1/5', description: 'Current page number' },
82
- { type: 'currentDate', label: 'Date', icon: 'D', preview: '27/03', description: 'Current date/time stamp' },
75
+ // ─── Text & Data ───
76
+ { type: 'text', label: 'Text', icon: 'T', preview: 'Aa', description: 'Static text label or title', category: 'Text & Data' },
77
+ { type: 'field', label: 'Field', icon: 'F', preview: '[Field]', description: 'Data-bound field from a source', category: 'Text & Data' },
78
+ { type: 'text', label: 'Title', icon: 'H', preview: 'Title', description: 'Large bold title text', category: 'Text & Data', extraProps: { content: 'Title', style: { fontSize: 18, fontWeight: 'bold' }, width: 80, height: 10 } },
79
+ { type: 'text', label: 'Subtitle', icon: 'h', preview: 'Subtitle', description: 'Medium subtitle text', category: 'Text & Data', extraProps: { content: 'Subtitle', style: { fontSize: 13, fontWeight: 'bold', color: '#666' }, width: 60, height: 8 } },
80
+ { type: 'text', label: 'Label', icon: 'L', preview: 'Label:', description: 'Small bold label', category: 'Text & Data', extraProps: { content: 'Label:', style: { fontSize: 9, fontWeight: 'bold' }, width: 25, height: 6 } },
81
+ // ─── Shapes & Lines ───
82
+ { type: 'line', label: 'Line', icon: '\u2500', preview: '\u2500\u2500\u2500', description: 'Horizontal line separator', category: 'Shapes' },
83
+ { type: 'line', label: 'Thick Line', icon: '\u2501', preview: '\u2501\u2501\u2501', description: 'Thick separator line', category: 'Shapes', extraProps: { lineStyle: { color: '#000', width: 3, style: 'solid' }, width: 80 } },
84
+ { type: 'line', label: 'Dashed Line', icon: '\u2504', preview: '- - -', description: 'Dashed separator', category: 'Shapes', extraProps: { lineStyle: { color: '#999', width: 1, style: 'dashed' }, width: 80 } },
85
+ { type: 'rect', label: 'Rectangle', icon: '\u25AD', preview: '\u25AD', description: 'Rectangle or filled box', category: 'Shapes' },
86
+ { type: 'rect', label: 'Filled Box', icon: '\u25A0', preview: '\u25A0', description: 'Filled color box', category: 'Shapes', extraProps: { fill: '#1976d2', lineStyle: { width: 0 }, width: 30, height: 15 } },
87
+ { type: 'rect', label: 'Rounded Box', icon: '\u25A2', preview: '\u25A2', description: 'Box with rounded corners', category: 'Shapes', extraProps: { cornerRadius: 6, lineStyle: { color: '#ccc', width: 1, style: 'solid' }, width: 40, height: 15 } },
88
+ // ─── Media ───
89
+ { type: 'image', label: 'Image', icon: '\u{1F5BC}', preview: '\u{1F304}', description: 'Static or dynamic image', category: 'Media' },
90
+ { type: 'barcode', label: 'QR Code', icon: '\u2588', preview: 'QR', description: 'QR code from field or value', category: 'Media', extraProps: { barcodeType: 'qr', value: '12345', width: 20, height: 20 } },
91
+ { type: 'barcode', label: 'Barcode 128', icon: '|||', preview: '||||', description: 'Code128 barcode', category: 'Media', extraProps: { barcodeType: 'code128', value: '12345' } },
92
+ { type: 'barcode', label: 'EAN-13', icon: '\u2584', preview: 'EAN', description: 'EAN-13 product barcode', category: 'Media', extraProps: { barcodeType: 'ean13', value: '5901234123457' } },
93
+ // ─── Charts ───
94
+ { type: 'chart', label: 'Bar Chart', icon: '\u{1F4CA}', preview: '\u{2581}\u{2583}\u{2585}\u{2587}', description: 'Bar chart visualization', category: 'Charts', extraProps: { chartType: 'bar', labelField: '', valueFields: [], width: 80, height: 50 } },
95
+ { type: 'chart', label: 'Line Chart', icon: '\u{1F4C8}', preview: '\u{2571}\u{2572}\u{2571}', description: 'Line chart with trends', category: 'Charts', extraProps: { chartType: 'line', labelField: '', valueFields: [], width: 80, height: 50 } },
96
+ { type: 'chart', label: 'Pie Chart', icon: '\u{1F967}', preview: '\u{25D4}', description: 'Pie/donut chart', category: 'Charts', extraProps: { chartType: 'pie', labelField: '', valueFields: [], width: 50, height: 50 } },
97
+ { type: 'chart', label: 'Area Chart', icon: '\u{1F30A}', preview: '\u{2586}\u{2584}\u{2582}', description: 'Area chart with fill', category: 'Charts', extraProps: { chartType: 'area', labelField: '', valueFields: [], width: 80, height: 50 } },
98
+ { type: 'chart', label: 'Combo Chart', icon: '\u{1F4CA}', preview: '\u{2581}\u{2571}\u{2585}', description: 'Bars + lines combined', category: 'Charts', extraProps: { chartType: 'combo', labelField: '', valueFields: [], width: 80, height: 50 } },
99
+ // ─── Page & Special ───
100
+ { type: 'pageNumber', label: 'Page Number', icon: '#', preview: '1/5', description: 'Page N of M', category: 'Special' },
101
+ { type: 'currentDate', label: 'Print Date', icon: '\u{1F4C5}', preview: '27/03', description: 'Current date/time', category: 'Special' },
102
+ { type: 'currentDate', label: 'Print Time', icon: '\u{1F552}', preview: '14:30', description: 'Current time only', category: 'Special', extraProps: { format: 'HH:mm:ss' } },
103
+ { type: 'text', label: 'Watermark', icon: '\u{1F4A7}', preview: 'DRAFT', description: 'Semi-transparent watermark text', category: 'Special', extraProps: { content: 'DRAFT', style: { fontSize: 48, fontWeight: 'bold', color: '#ccc', textAlign: 'center', opacity: 0.3 }, width: 120, height: 30 } },
83
104
  ];
84
105
  let ZenttoReportDesigner = class ZenttoReportDesigner extends LitElement {
85
106
  constructor() {
@@ -1575,6 +1596,9 @@ let ZenttoReportDesigner = class ZenttoReportDesigner extends LitElement {
1575
1596
  case 'barcode':
1576
1597
  element = { ...baseProps, type: 'barcode', barcodeType: 'qr', value: '12345', width: 15, height: 15 };
1577
1598
  break;
1599
+ case 'chart':
1600
+ element = { ...baseProps, type: 'chart', chartType: 'bar', dataSource: '', labelField: '', valueFields: [], width: 80, height: 50 };
1601
+ break;
1578
1602
  case 'pageNumber':
1579
1603
  element = { ...baseProps, type: 'pageNumber', format: 'Page {page} of {pages}', width: 30 };
1580
1604
  break;
@@ -1901,7 +1925,10 @@ let ZenttoReportDesigner = class ZenttoReportDesigner extends LitElement {
1901
1925
  });
1902
1926
  }
1903
1927
  else if (type) {
1904
- this._addElementToBand(bandId, type);
1928
+ // Check for extra props from toolbox items (Title, Watermark, etc.)
1929
+ const extraJson = e.dataTransfer?.getData('extra-props');
1930
+ const extraProps = extraJson ? JSON.parse(extraJson) : undefined;
1931
+ this._addElementToBand(bandId, type, extraProps);
1905
1932
  }
1906
1933
  }
1907
1934
  _onBandDragOver(e) {
@@ -2983,17 +3010,32 @@ REGLAS:
2983
3010
  }
2984
3011
  // ─── Toolbox ──────────────────────────────────────────────────
2985
3012
  _renderToolbox() {
3013
+ // Group items by category
3014
+ const categories = new Map();
3015
+ for (const item of TOOLBOX_ITEMS) {
3016
+ if (!categories.has(item.category))
3017
+ categories.set(item.category, []);
3018
+ categories.get(item.category).push(item);
3019
+ }
2986
3020
  return html `
2987
- ${TOOLBOX_ITEMS.map(item => html `
2988
- <div class="toolbox-item"
2989
- draggable="true"
2990
- @dragstart=${(e) => this._onToolboxDragStart(e, item.type)}>
2991
- <div class="toolbox-icon" data-type="${item.type}">${item.preview}</div>
2992
- <div class="toolbox-info">
2993
- <span class="toolbox-label">${item.label}</span>
2994
- <span class="toolbox-desc">${item.description}</span>
3021
+ ${[...categories.entries()].map(([cat, items]) => html `
3022
+ <div style="padding:4px 10px 2px;font-size:10px;font-weight:600;color:var(--zrd-text-muted,#999);text-transform:uppercase;letter-spacing:0.5px;margin-top:4px;">${cat}</div>
3023
+ ${items.map(item => html `
3024
+ <div class="toolbox-item"
3025
+ draggable="true"
3026
+ @dragstart=${(e) => {
3027
+ this._onToolboxDragStart(e, item.type);
3028
+ if (item.extraProps) {
3029
+ e.dataTransfer?.setData('extra-props', JSON.stringify(item.extraProps));
3030
+ }
3031
+ }}>
3032
+ <div class="toolbox-icon" data-type="${item.type}">${item.preview}</div>
3033
+ <div class="toolbox-info">
3034
+ <span class="toolbox-label">${item.label}</span>
3035
+ <span class="toolbox-desc">${item.description}</span>
3036
+ </div>
2995
3037
  </div>
2996
- </div>
3038
+ `)}
2997
3039
  `)}
2998
3040
  `;
2999
3041
  }
@@ -3023,31 +3065,28 @@ REGLAS:
3023
3065
  ${this._renderOverlays()}
3024
3066
  `;
3025
3067
  }
3026
- // Action buttons bar
3027
- const hasActions = this.dbProvider || this.zenttoProvider || this._layout.dataSources.length > 0;
3068
+ // Action buttons bar — always show so user can connect data sources
3028
3069
  return html `
3029
- ${hasActions ? html `
3030
- <div style="padding:6px 8px;display:flex;gap:4px;border-bottom:1px solid var(--zrd-border,#e0e0e0);flex-shrink:0;flex-wrap:wrap;">
3031
- ${this.dbProvider ? html `
3032
- <button style="flex:1;padding:5px 6px;border:1px solid var(--zrd-border,#ddd);border-radius:4px;cursor:pointer;font-size:10px;font-weight:600;background:var(--zrd-input-bg,#fff);color:var(--zrd-primary,#1976d2);min-width:70px;"
3033
- @click=${() => { this._dbConnectorOpen = true; }}>
3034
- \u{1F5C4} DB
3035
- </button>
3036
- ` : nothing}
3037
- ${this.zenttoProvider ? html `
3038
- <button style="flex:1;padding:5px 6px;border:1px solid var(--zrd-border,#ddd);border-radius:4px;cursor:pointer;font-size:10px;font-weight:600;background:var(--zrd-input-bg,#fff);color:#e65100;min-width:70px;"
3039
- @click=${() => { this._zenttoConnectorOpen = true; }}>
3040
- \u{1F310} Zentto
3041
- </button>
3042
- ` : nothing}
3043
- ${this._layout.dataSources.length > 0 ? html `
3044
- <button style="flex:1;padding:5px 6px;border:1px solid var(--zrd-border,#ddd);border-radius:4px;cursor:pointer;font-size:10px;font-weight:600;background:var(--zrd-input-bg,#fff);color:var(--zrd-text,#555);min-width:70px;"
3045
- @click=${() => { this._erOverlayOpen = true; }}>
3046
- \u{1F4CA} ER
3047
- </button>
3048
- ` : nothing}
3049
- </div>
3050
- ` : nothing}
3070
+ <div style="padding:6px 8px;display:flex;gap:4px;border-bottom:1px solid var(--zrd-border,#e0e0e0);flex-shrink:0;flex-wrap:wrap;">
3071
+ <button style="flex:1;padding:5px 6px;border:1px solid var(--zrd-border,#ddd);border-radius:4px;cursor:pointer;font-size:10px;font-weight:600;background:var(--zrd-input-bg,#fff);color:var(--zrd-primary,#1976d2);min-width:50px;"
3072
+ @click=${() => { this._dbConnectorOpen = true; }}>
3073
+ \u{1F5C4} DB
3074
+ </button>
3075
+ <button style="flex:1;padding:5px 6px;border:1px solid var(--zrd-border,#ddd);border-radius:4px;cursor:pointer;font-size:10px;font-weight:600;background:var(--zrd-input-bg,#fff);color:#e65100;min-width:50px;"
3076
+ @click=${() => { this._zenttoConnectorOpen = true; }}>
3077
+ \u{1F310} Zentto
3078
+ </button>
3079
+ <button style="flex:1;padding:5px 6px;border:1px solid var(--zrd-border,#ddd);border-radius:4px;cursor:pointer;font-size:10px;font-weight:600;background:var(--zrd-input-bg,#fff);color:#2e7d32;min-width:50px;"
3080
+ @click=${() => { this.dispatchEvent(new CustomEvent('add-rest-source', { bubbles: true, composed: true })); }}>
3081
+ \u{1F517} REST
3082
+ </button>
3083
+ ${this._layout.dataSources.length > 0 ? html `
3084
+ <button style="flex:1;padding:5px 6px;border:1px solid var(--zrd-border,#ddd);border-radius:4px;cursor:pointer;font-size:10px;font-weight:600;background:var(--zrd-input-bg,#fff);color:var(--zrd-text,#555);min-width:50px;"
3085
+ @click=${() => { this._erOverlayOpen = true; }}>
3086
+ \u{1F4CA} ER
3087
+ </button>
3088
+ ` : nothing}
3089
+ </div>
3051
3090
  <zrd-data-source-tree
3052
3091
  .dataSources=${this._layout.dataSources}
3053
3092
  .relations=${this._layout.relations || []}
@@ -3091,7 +3130,10 @@ REGLAS:
3091
3130
  _renderErOverlay() {
3092
3131
  return html `
3093
3132
  <div style="position:fixed;inset:0;background:rgba(0,0,0,0.5);z-index:10000;display:flex;align-items:center;justify-content:center;backdrop-filter:blur(2px);"
3094
- @click=${() => { this._erOverlayOpen = false; }}>
3133
+ @click=${() => { this._erOverlayOpen = false; }}
3134
+ @keydown=${(e) => { if (e.key === 'Escape')
3135
+ this._erOverlayOpen = false; }}
3136
+ tabindex="-1">
3095
3137
  <div style="background:var(--zrd-panel-bg,#fff);border-radius:12px;box-shadow:0 20px 60px rgba(0,0,0,0.3);width:85vw;height:80vh;display:flex;flex-direction:column;overflow:hidden;"
3096
3138
  @click=${(e) => e.stopPropagation()}>
3097
3139
  <div style="padding:16px 20px;border-bottom:1px solid var(--zrd-border,#eee);display:flex;justify-content:space-between;align-items:center;">
@@ -3103,6 +3145,8 @@ REGLAS:
3103
3145
  <zrd-er-diagram
3104
3146
  .dataSources=${this._layout.dataSources}
3105
3147
  .relations=${this._layout.relations || []}
3148
+ .dbProvider=${this.dbProvider}
3149
+ .zenttoProvider=${this.zenttoProvider}
3106
3150
  @relation-edit=${(e) => {
3107
3151
  this._editingRelation = e.detail.relation;
3108
3152
  this._relationEditorOpen = true;
@@ -3115,8 +3159,7 @@ REGLAS:
3115
3159
  this._layout = { ...this._layout, relations: (this._layout.relations || []).filter(r => r.id !== id) };
3116
3160
  this._commitChange();
3117
3161
  }}
3118
- @add-datasource=${() => { this._erOverlayOpen = false; this._dbConnectorOpen = true; this._activePanel = 'data'; }}
3119
- @add-zentto=${() => { this._erOverlayOpen = false; this._zenttoConnectorOpen = true; this._activePanel = 'data'; }}
3162
+ @datasources-ready=${(e) => this._onDatasourcesReady(e.detail)}
3120
3163
  @add-rest=${() => { }}
3121
3164
  @table-focus=${() => {
3122
3165
  this._erOverlayOpen = false;
@@ -3385,6 +3428,9 @@ REGLAS:
3385
3428
  case 'barcode':
3386
3429
  content = `[${el.barcodeType}]`;
3387
3430
  break;
3431
+ case 'chart':
3432
+ content = `\u{1F4CA} [${el.chartType || 'chart'}]`;
3433
+ break;
3388
3434
  case 'pageNumber':
3389
3435
  content = el.format || 'Page #';
3390
3436
  break;