This commit is contained in:
string 2025-06-09 10:17:39 +05:30
parent 0ced644864
commit 5e70585afc
28 changed files with 11547 additions and 1690 deletions

View File

@ -62,6 +62,9 @@
<clr-dg-column [clrDgField]="'Java Code'"> <ng-container *clrDgHideableColumn="{hidden: false}"> javacode
</ng-container></clr-dg-column>
<!-- <clr-dg-column [clrDgField]="'tag'"> <ng-container *clrDgHideableColumn="{hidden: false}"> Tag
</ng-container></clr-dg-column> -->
<clr-dg-column [clrDgField]="'Active'"> <ng-container *clrDgHideableColumn="{hidden: false}"> Active
</ng-container></clr-dg-column>
@ -107,6 +110,9 @@
style="cursor: pointer; align-items: center;"><clr-icon shape="details"></clr-icon>
</clr-dg-cell>
<!-- <clr-dg-cell>{{user.tag }}</clr-dg-cell> -->
<clr-dg-cell>{{user. active }}</clr-dg-cell>
@ -377,6 +383,14 @@
placeholder="Textarea"> </textarea>
</div>
<div class="clr-col-sm-12">
<label>Tag</label>
<select name="tag" [(ngModel)]="rowSelected.tag">
<option [value]="null">Choose Tag</option>
<option *ngFor=" let item of selectTagdata" [value]="item.id">{{item.name }}</option>
</select>
</div>
</div>
@ -497,6 +511,14 @@
<textarea cols="10" rows="2" formControlName="javacode" placeholder="Textarea"> </textarea>
</div>
<div class="clr-col-sm-12">
<label> Tag</label>
<select formControlName="tag">
<option [value]="null">Choose Tag</option>
<option *ngFor="let item of selectTagdata " [value]="item.id">{{item.name}}</option>
</select>
</div>
</div>

View File

@ -10,6 +10,7 @@ import { UserInfoService } from 'src/app/services/user-info.service';
import { SiteTreeservice } from '../SiteBuilderGrid/SiteTree.service';
import { COMMON_CSS } from '../WireframesUi/common-css';
import { ActivatedRoute } from '@angular/router';
import { Tagservice } from '../Tag/Tag.service';
declare var JsBarcode: any;
@Component({
selector: 'app-Design_lbrary',
@ -44,6 +45,7 @@ export class Design_lbraryComponent implements OnInit {
modaldelete = false;
modalEdit = false;
modalAdd = false;
selectTagdata;
public entryForm: FormGroup;
loading = false;
product;
@ -61,6 +63,7 @@ export class Design_lbraryComponent implements OnInit {
private _fb: FormBuilder,
private siteTreeService: SiteTreeservice,
private route: ActivatedRoute,
private tagService: Tagservice,
) { }
// component button
@ -74,6 +77,7 @@ export class Design_lbraryComponent implements OnInit {
}
this.userrole = this.userInfoService.getRoles();
this.getData();
this.getallTags();
this.entryForm = this._fb.group({
name: [null],
@ -82,6 +86,8 @@ export class Design_lbraryComponent implements OnInit {
active: [false],
htmljson: [null],
tag: [null],
css: [null],
templatetype: [null],
@ -247,6 +253,14 @@ export class Design_lbraryComponent implements OnInit {
this.rowSelected = row; this.rsModaljavacode = true;
}
getallTags() {
this.tagService.getAll().subscribe(data => {
this.selectTagdata = data;
console.log('tag data ', data);
}, (error) => { console.log(error); });
}
// updateaction
public htmlContent: string = '';

View File

@ -15,11 +15,9 @@
<button id="add" class="btn btn-primary" (click)="goToAdd(product)">
<clr-icon shape="plus"></clr-icon>ADD
</button>
</div>
</div>
<ng-container *ngIf="!isCardview"> <!-- GET ALL --> <clr-datagrid [clrDgLoading]="loading"
[(clrDgSelected)]="selected">
<clr-dg-placeholder>
@ -29,7 +27,7 @@
<div *ngIf="error;else loadingSpinner">{{error}}</div>
</clr-dg-placeholder>
<clr-dg-column [clrDgField]="' name'"> <ng-container *clrDgHideableColumn="{hidden: false}"> Name
<clr-dg-column [clrDgField]="' name'"> <ng-container *clrDgHideableColumn="{hidden: false}">Website Name
</ng-container></clr-dg-column>
@ -49,7 +47,7 @@
<clr-dg-row *clrDgItems="let user of product?.slice()?.reverse()" [clrDgItem]="user">
<clr-dg-cell>{{user. name }}</clr-dg-cell>
<clr-dg-cell>{{user.name }}</clr-dg-cell>
<clr-dg-cell (click)="goToReplaceStringdescription (user.description)"
@ -57,7 +55,7 @@
</clr-dg-cell>
<clr-dg-cell>{{user. active }}</clr-dg-cell>
<clr-dg-cell>{{user.active }}</clr-dg-cell>
<!-- who column -->
@ -98,6 +96,9 @@
</clr-dg-pagination>
</clr-dg-footer>
</clr-datagrid> </ng-container>
<ng-template #showInfo>
<div class="alert alert-info" role="alert">
<div class="alert-items">
@ -110,13 +111,20 @@
</div>
</div>
</div>
</ng-template><ng-container *ngIf="isCardview">
</ng-template><ng-container *ngIf="isCardview">
<div *ngIf="product; else showInfo" class="clr-row clr-align-items-start clr-justify-content-start">
<div *ngFor="let app of product| filter:search; let index = i" class="clr-col-auto">
<div class="clr-row">
<div class="clr-col-lg-12 clr-col-md-4 clr-col-sm-4 clr-col-12" style="width: 410px;">
<div class="card" style="padding: 10px; "
[style.background-color]="cardmodal.cardColor !== '' ? cardmodal.cardColor : 'white'">
<div class="card-body"
style="display: grid; grid-template-columns: repeat(13, 1fr); grid-template-rows: repeat(7, 1fr); gap: 5px;">
<ng-container *ngFor="let item of dashboardArray">
@ -224,179 +232,336 @@
</div>
</div>
</ng-container>
</div>
<!-- card view start -->
<!-- <div *ngIf="isCardview" class="project-container" style="height: 600px; overflow-y: scroll;">
<div *ngIf="product else showInfo" class="clr-row clr-align-items-start clr-justify-content-start"
style="margin: 0px;">
<div *ngFor="let app of product | filter:search; let index = i" class="clr-col-auto">
<div class="clr-row">
<div class="clr-col-lg-12 clr-col-md-4 clr-col-sm-4 clr-col-12" style="width: 410px;">
<div class="card" (click)="gotositebuilder(app.id)">
<div class="card-header">
<div class="clr-row">
<div class="clr-col-5">
<b style="font-size: 15px; display: inline-block;
width: 180px;
white-space: nowrap;
overflow: hidden !important;
text-overflow: ellipsis;" [title]="app.name"> {{app.name}}</b>
</div>
</div>
<div class="card-title1" id="word">
<b class="word" style="font-size: 15px; " [title]="app.projectName">{{app.projectName}}</b>
</div>
<div class="clr-row">
<div class="clr-col-9">
<div class="card-title1" id="word">
<b style="font-size: 15px;" class="p2" [title]="app.description">{{app.description}}</b>
</div>
</div>
<div class="clr-col-3"
style="text-align: right; display: flex; align-items: center; justify-content: flex-end; padding:0;">
<clr-modal [(clrModalOpen)]="rsModaldescription" [clrModalSize]="'xl'" [clrModalStaticBackdrop]="true">
<div class="modal-body">
<textarea class="form-control" style="width:100%; height: 400px;" readonly>{{rowSelected}}</textarea>
</div>
</clr-modal>
</div>
</div>
</div>
<div style="padding: 0 10px;cursor: pointer;position:relative; "
(click)="openModal(app.id);$event.stopPropagation();">
<!-- // EDIT DATA......... -->
<clr-modal [(clrModalOpen)]="modalEdit" [clrModalSize]="'lg'" [clrModalStaticBackdrop]="true">
<h3 class="modal-title">Update Site Builder <!--update button -->
<clr-progress-bar [clrValue]="app.progressValue" clrLabeled></clr-progress-bar>
</div>
<div class="card-block" style="padding: 10px 10px 0px 10px;">
<div class="card-text">
<div class="clr-row">
<div class="clr-col-7">
<span *ngFor="let tech of app?.technology?.slice(0, 6); let i = index">
<span class="label label-light-blue p7 wordwrap" style="margin-top: .4em;" [title]="tech">
{{tech}}</span>
</span>
</div>
<div class="clr-col-5" (click)="stopRedirection($event)" style="-ms-flex-align: end;">
<div class="profile-pics">
<ng-container *ngFor="let imageitem of app?.images; let i = index">
<img (click)="openprofile(app.id); $event.stopPropagation();"
[src]="imageitem?.image ? imageitem?.image : '../../../../../assets/images/images.png'"
[title]="imageitem?.user_name" [style.z-index]="i + 2" [style.left.rem]="i * 0.9"
[style.display]="i < 5 ? 'block' : 'none'" />
</ng-container>
</div>
</div>
</h3>
<div class="modal-body" *ngIf="rowSelected.id">
<h2 class="heading">{{rowSelected.id}}</h2>
<!-- button -->
<form>
<div class="clr-row">
<div class="clr-col-sm-12">
<label>Name</label>
<input class="clr-input" type="text" [(ngModel)]="rowSelected.name" name="name" />
</div>
<div class="clr-col-sm-12">
<label> Description</label>
<textarea cols="10" rows="2" [(ngModel)]="rowSelected.description" name="description "
placeholder="Textarea"> </textarea>
</div>
<div class="clr-col-sm-12">
<label> Active</label>
<input type="checkbox" name="active" clrToggle [(ngModel)]="rowSelected.active" />
</div>
</div>
<!-- form code start -->
<div *ngIf="checkFormCode">
<h4 style="font-weight: 300;display: inline;">Extension</h4>
<br>
<hr>
<div class="clr-row">
<div class="clr-col-4" *ngFor="let field of additionalFieldsFromBackend">
<ng-container *ngIf="field.formCode === formcode" [ngSwitch]="field.fieldType">
<!-- Text Input --> <label *ngSwitchCase="'text'">{{ field.fieldName }}</label>
<input *ngSwitchCase="'text'" [type]="field.fieldType" name="{{ field.extValue }}"
[(ngModel)]="rowSelected[field.extValue]" class="clr-input" />
<!-- Date Input --> <label *ngSwitchCase="'date'">{{ field.fieldName }}</label>
<input *ngSwitchCase="'date'" [type]="field.fieldType" name="{{ field.extValue }}"
[(ngModel)]="rowSelected[field.extValue]" class="clr-input" />
<!-- Textarea --> <label *ngSwitchCase="'textarea'">{{ field.fieldName }}</label>
<textarea *ngSwitchCase="'textarea'" name="{{ field.extValue }}" [(ngModel)]="rowSelected[field.extValue]"
col="10" row="2"></textarea>
<!-- Checkbox --> <label *ngSwitchCase="'checkbox'">{{ field.fieldName }}</label><br>
<input *ngSwitchCase="'checkbox'" [type]="field.fieldType" name="{{ field.extValue }}"
[(ngModel)]="rowSelected[field.extValue]" class="clr-checkbox" />
</ng-container>
</div>
</div>
<div class="card-footer" style="padding: 0px 10px 6px 10px">
<button class="btn btn-sm btn-link"> Last Updated On: {{app.updatedAt|date}}</button> <span
style="margin: 0 0 0 10px; padding: 5px;" class="label p7"><clr-icon
shape="calendar"></clr-icon>&nbsp;{{app.createdAt | timePipe}}</span>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
<!-- form code end -->
<div class="modal-footer">
<button type="button" class="btn btn-outline" (click)="modalEdit = false">Cancel</button>
<button type="submit" class="btn btn-primary" (click)="onUpdate(rowSelected.id)">Update</button>
</div> -->
<!-- card view end -->
<clr-modal [(clrModalOpen)]="rsModaldescription" [clrModalSize]="'xl'" [clrModalStaticBackdrop]="true">
<div class="modal-body">
<textarea class="form-control" style="width:100%; height: 400px;" readonly>{{rowSelected}}</textarea>
</div>
</form>
</div>
</clr-modal>
<clr-modal [(clrModalOpen)]="modaldelete" [clrModalSize]="'lg'" [clrModalStaticBackdrop]="true">
<div class="modal-body" *ngIf="rowSelected.id">
<h1 class="delete">Are You Sure Want to delete?</h1>
<h2 class="heading">{{rowSelected.id}}</h2>
<div class="modal-footer">
<button type="button" class="btn btn-outline" (click)="modaldelete = false">Cancel</button>
<button type="button" (click)="delete(rowSelected.id)" class="btn btn-primary">Delete</button>
</div>
</div>
</clr-modal>
<!-- ADD FORM ..... -->
<clr-modal [(clrModalOpen)]="modalAdd" [clrModalSize]="'lg'" [clrModalStaticBackdrop]="true">
<h3 class="modal-title">Add Site Builder
<!-- aeroplane icon -->
&nbsp; &nbsp; &nbsp; &nbsp;
<a *ngIf="userrole.includes('ROLE_ADMIN')" style="float: right;" href="javascript:void(0)" role="tooltip"
aria-haspopup="true" class="tooltip tooltip-sm tooltip-bottom-left">
<a id="build_extension" [routerLink]="['../extension/all']" [queryParams]="{ formCode: 'Visa_status_formCode' }">
<clr-icon shape="airplane" size="32"></clr-icon>
</a>
<span class="tooltip-content">Form Extension</span>
</a>
</h3>
<div class="modal-body">
<form [formGroup]="entryForm">
<div class="clr-row" style="height: fit-content;">
<div class="clr-col-sm-12">
<label> Name</label>
<input class="clr-input" type="text" formControlName="name" />
</div>
<div class="clr-col-sm-12">
<label> Description</label>
<textarea cols="10" rows="2" formControlName="description" placeholder="Textarea"> </textarea>
</div>
<div class="clr-col-sm-12">
<label> Active</label>
<input type="checkbox" formControlName="active" clrToggle />
</div>
</clr-modal>
</div>
<!-- // EDIT DATA......... -->
<clr-modal [(clrModalOpen)]="modalEdit" [clrModalSize]="'lg'" [clrModalStaticBackdrop]="true">
<h3 class="modal-title">Update Site Builder <!--update button -->
</h3>
<div class="modal-body" *ngIf="rowSelected.id">
<h2 class="heading">{{rowSelected.id}}</h2>
<!-- button -->
<form>
<div class="clr-row">
<div class="clr-col-sm-12">
<label>Website Name</label>
<input class="clr-input" type="text" [(ngModel)]="rowSelected.name" name="name" />
</div>
<div class="clr-col-sm-12">
<label> Description</label>
<textarea cols="10" rows="2" [(ngModel)]="rowSelected.description" name="description "
placeholder="Textarea"> </textarea>
</div>
<div class="clr-col-sm-12">
<label> Active</label>
<input type="checkbox" name="active" clrToggle [(ngModel)]="rowSelected.active" />
</div>
<!-- form code start -->
<div *ngIf="checkFormCode">
<h4 style="font-weight: 300;display: inline;">Extension</h4>
<br>
<hr>
<div class="clr-row">
<div class="clr-col-4" *ngFor="let field of additionalFieldsFromBackend">
<ng-container *ngIf="field.formCode === formcode" [ngSwitch]="field.fieldType">
<!-- Text Input --> <label *ngSwitchCase="'text'">{{ field.fieldName }}</label>
<input *ngSwitchCase="'text'" [type]="field.fieldType" [formControlName]="field.extValue"
class="clr-input" />
<!-- Date Input --> <label *ngSwitchCase="'date'">{{ field.fieldName }}</label>
<input *ngSwitchCase="'date'" [type]="field.fieldType" [formControlName]="field.extValue"
class="clr-input" />
<!-- Textarea --> <label *ngSwitchCase="'textarea'">{{ field.fieldName }}</label>
<textarea *ngSwitchCase="'textarea'" [formControlName]="field.extValue" col="10" row="2"></textarea>
<!-- Checkbox --> <label *ngSwitchCase="'checkbox'">{{ field.fieldName }}</label><br>
<input *ngSwitchCase="'checkbox'" [type]="field.fieldType" [formControlName]="field.extValue"
class="clr-checkbox" />
</ng-container>
</div>
<h6> List of logoupload</h6>
<div class="clr-row" style="margin-top: 10px;">
<table class="table">
<thead>
<tr>
<th>No</th>
<th> File</th>
<th>File Name</th>
<th>Preview</th>
<th>Cancel</th>
</tr>
</thead>
<tbody>
<tr *ngFor="let attach of FileDatalogoupload; let i=index">
<td style="width: 70px;"><input type="text" class="clr-input" value={{i+1}} [readonly]="true"> </td>
<td><input type="file" (change)="onFileChangedlogoupload($event, i)" accept="image/*" />
</td>
<td>{{attach.uploadedfile_name}}</td>
<td> <img [src]="attach.filePreview" alt="File Preview" [ngModelOptions]="{standalone: true}"
name="filePreview" width="100px" height="100px"></td>
<td>
<clr-signpost style="padding-right: 10px;">
<clr-icon shape="trash" class="is-error" aria-label="Icon Button Trigger"
clrSignpostTrigger></clr-icon>
<clr-signpost-content [clrPosition]="'bottom-middle'" *clrIfOpen>
<div style="text-align: center;"><b>Are you sure?</b></div>
<button class="btn btn-outline" [clrSignpostTrigger]="false">cancel</button>&nbsp;
<button class="btn btn-primary" (click)="deleteRowlogoupload(i,attach.id)">Delete</button>
</clr-signpost-content>
</clr-signpost>
</td>
</tr>
</tbody>
<button type="button" class="btn btn-primary button1" style="margin-left: 20px;"
(click)="onAddLineslogoupload()">
<clr-icon shape="plus"></clr-icon>
</button>
</table>
</div>
<!-- form code start -->
<div *ngIf="checkFormCode">
<h4 style="font-weight: 300;display: inline;">Extension</h4>
<br>
<hr>
<div class="clr-row">
<div class="clr-col-4" *ngFor="let field of additionalFieldsFromBackend">
<ng-container *ngIf="field.formCode === formcode" [ngSwitch]="field.fieldType">
<!-- Text Input --> <label *ngSwitchCase="'text'">{{ field.fieldName }}</label>
<input *ngSwitchCase="'text'" [type]="field.fieldType" name="{{ field.extValue }}"
[(ngModel)]="rowSelected[field.extValue]" class="clr-input" />
<!-- Date Input --> <label *ngSwitchCase="'date'">{{ field.fieldName }}</label>
<input *ngSwitchCase="'date'" [type]="field.fieldType" name="{{ field.extValue }}"
[(ngModel)]="rowSelected[field.extValue]" class="clr-input" />
<!-- Textarea --> <label *ngSwitchCase="'textarea'">{{ field.fieldName }}</label>
<textarea *ngSwitchCase="'textarea'" name="{{ field.extValue }}"
[(ngModel)]="rowSelected[field.extValue]" col="10" row="2"></textarea>
<!-- Checkbox --> <label *ngSwitchCase="'checkbox'">{{ field.fieldName }}</label><br>
<input *ngSwitchCase="'checkbox'" [type]="field.fieldType" name="{{ field.extValue }}"
[(ngModel)]="rowSelected[field.extValue]" class="clr-checkbox" />
</ng-container>
</div>
</div>
</div>
<!-- form code end -->
<div class="modal-footer">
<button type="button" class="btn btn-outline" (click)="modalEdit = false">Cancel</button>
<button type="submit" class="btn btn-primary" (click)="onUpdate(rowSelected.id)">Update</button>
</div>
</form>
</div>
</clr-modal>
<clr-modal [(clrModalOpen)]="modaldelete" [clrModalSize]="'lg'" [clrModalStaticBackdrop]="true">
<div class="modal-body" *ngIf="rowSelected.id">
<h1 class="delete">Are You Sure Want to delete?</h1>
<h2 class="heading">{{rowSelected.id}}</h2>
<div class="modal-footer">
<button type="button" class="btn btn-outline" (click)="modaldelete = false">Cancel</button>
<button type="button" (click)="delete(rowSelected.id)" class="btn btn-primary">Delete</button>
</div>
</div>
<!-- form code end -->
<div class="modal-footer">
<button type="button" class="btn btn-outline" (click)="modalAdd = false">Cancel</button>
<button type="submit" class="btn btn-primary" (click)="onSubmit()">ADD</button>
</clr-modal>
<!-- ADD FORM ..... -->
<clr-modal [(clrModalOpen)]="modalAdd" [clrModalSize]="'lg'" [clrModalStaticBackdrop]="true">
<h3 class="modal-title">Add Site Builder
<!-- aeroplane icon -->
&nbsp; &nbsp; &nbsp; &nbsp;
<a *ngIf="userrole?.includes('ROLE_ADMIN')" style="float: right;" href="javascript:void(0)" role="tooltip"
aria-haspopup="true" class="tooltip tooltip-sm tooltip-bottom-left">
<a id="build_extension" [routerLink]="['../extension/all']"
[queryParams]="{ formCode: 'Visa_status_formCode' }">
<clr-icon shape="airplane" size="32"></clr-icon>
</a>
<span class="tooltip-content">Form Extension</span>
</a>
</h3>
<div class="modal-body">
<form [formGroup]="entryForm">
<div class="clr-row" style="height: fit-content;">
<div class="clr-col-sm-12">
<label>Website Name</label>
<input class="clr-input" type="text" formControlName="name" />
</div>
<div class="clr-col-sm-12">
<label> Description</label>
<textarea cols="10" rows="2" formControlName="description" placeholder="Textarea"> </textarea>
</div>
<div class="clr-col-sm-12">
<label> Active</label>
<input type="checkbox" formControlName="active" clrToggle />
</div>
</div>
<h6> List of logoupload</h6>
<div class="clr-row" style="margin-top: 10px;">
<table class="table">
<thead>
<tr>
<th>No</th>
<th> File</th>
<th>File Name</th>
<th>Preview</th>
<th>Cancel</th>
</tr>
</thead>
<tbody>
<tr *ngFor="let attach of FileDatalogoupload; let i=index">
<td style="width: 70px;"><input type="text" class="clr-input" value={{i+1}} [readonly]="true"> </td>
<td><input type="file" (change)="onFileChangedlogoupload($event, i)"
accept="image/*" /><!--accept=".pdf,.doc,.docx,.jpg,.msg"-->
</td>
<td>{{attach.uploadedfile_name}}</td>
<td> <img [src]="attach.filePreview" alt="File Preview" [ngModelOptions]="{standalone: true}"
name="filePreview" width="100px" height="100px"></td>
<td>
<a (click)="deleteRowlogoupload(i)">
<clr-icon shape="trash" class="is-error"></clr-icon>
</a>
</td>
</tr>
</tbody>
<button type="button" class="btn btn-primary button1" style="margin-left: 20px;"
(click)="onAddLineslogoupload()">
<clr-icon shape="plus"></clr-icon>
</button>
</table>
</div>
<!-- form code start -->
<div *ngIf="checkFormCode">
<h4 style="font-weight: 300;display: inline;">Extension</h4>
<br>
<hr>
<div class="clr-row">
<div class="clr-col-4" *ngFor="let field of additionalFieldsFromBackend">
<ng-container *ngIf="field.formCode === formcode" [ngSwitch]="field.fieldType">
<!-- Text Input --> <label *ngSwitchCase="'text'">{{ field.fieldName }}</label>
<input *ngSwitchCase="'text'" [type]="field.fieldType" [formControlName]="field.extValue"
class="clr-input" />
<!-- Date Input --> <label *ngSwitchCase="'date'">{{ field.fieldName }}</label>
<input *ngSwitchCase="'date'" [type]="field.fieldType" [formControlName]="field.extValue"
class="clr-input" />
<!-- Textarea --> <label *ngSwitchCase="'textarea'">{{ field.fieldName }}</label>
<textarea *ngSwitchCase="'textarea'" [formControlName]="field.extValue" col="10" row="2"></textarea>
<!-- Checkbox --> <label *ngSwitchCase="'checkbox'">{{ field.fieldName }}</label><br>
<input *ngSwitchCase="'checkbox'" [type]="field.fieldType" [formControlName]="field.extValue"
class="clr-checkbox" />
</ng-container>
</div>
</div>
</div>
<!-- form code end -->
<div class="modal-footer">
<button type="button" class="btn btn-outline" (click)="modalAdd = false">Cancel</button>
<button type="submit" class="btn btn-primary" (click)="onSubmit()">ADD</button>
</div>
</form>
</div>
</form>
</div>
</clr-modal>
</clr-modal>
<!-- htmlpopup -->
<!-- htmlpopup -->

View File

@ -59,19 +59,21 @@ export class SiteTreeComponent implements OnInit {
) { }
// component button
ngOnInit(): void {
this.getData();
if (this.cardmodeldata !== '') {
this.cardmodal = JSON.parse(this.cardmodeldata);
this.dashboardArray = this.cardmodal.dashboard.slice();
console.log(this.dashboardArray)
console.log('card data ', this.dashboardArray)
}
this.userrole = this.userInfoService.getRoles();
this.getData();
this.entryForm = this._fb.group({
name: [null],
description: [null],
active: [false],
active: [true],
}); // component_button200
// form code start
@ -99,11 +101,15 @@ export class SiteTreeComponent implements OnInit {
}
FileDataLogoupload: any[];
selectedLogoupload: any[];
error;
getData() {
this.mainService.getAll().subscribe((data) => {
console.log(data);
this.product = data;
console.log('site data ', this.product);
if (this.product.length == 0) {
this.error = "No Data Available"
}
@ -116,6 +122,15 @@ export class SiteTreeComponent implements OnInit {
}
onEdit(row) {
this.rowSelected = row;
this.selectedlogoupload = [];
this.mainService.uploadLogouploadgetById(row.id, this.tableName).subscribe(uploaddata => {
console.log(uploaddata);
this.FileDatalogoupload = uploaddata;
})
this.modalEdit = true;
}
onDelete(row) {
@ -149,6 +164,13 @@ export class SiteTreeComponent implements OnInit {
this.ngOnInit();
}, 500);
for (let i = 0; i < this.selectedlogoupload.length; i++) {
this.mainService.uploadLogoupload(data.id, this.tableName, this.selectedlogoupload[i]).subscribe(uploaddata => {
console.log(uploaddata);
})
}
}, (error) => {
console.log(error);
if (error.status >= 200 && error.status <= 299) {
@ -178,6 +200,13 @@ export class SiteTreeComponent implements OnInit {
this.ngOnInit();
}, 500);
for (let i = 0; i < this.selectedlogoupload.length; i++) {
this.mainService.uploadLogoupload(data.id, this.tableName, this.selectedlogoupload[i]).subscribe(uploaddata => {
console.log(uploaddata);
})
}
}, (error) => {
console.log(error);
if (error.status >= 200 && error.status <= 299) {
@ -195,7 +224,9 @@ export class SiteTreeComponent implements OnInit {
}, 500);
}
goToAdd(row) {
this.modalAdd = true; this.submitted = false;
console.log('go to add ')
this.modalAdd = true;
this.submitted = false;
}
@ -218,6 +249,47 @@ export class SiteTreeComponent implements OnInit {
filePreviewlogoupload: string | ArrayBuffer | null = null;
FileDatalogoupload: { uploadedfile_name?: any, filePreview: string | ArrayBuffer | null }[] = []; // Initialize the array
selectedlogoupload: File[] = [];
public onFileChangedlogoupload(event, index) {
const files = event.target.files;
for (let i = 0; i < files.length; i++) {
const file = files[i];
this.FileDatalogoupload[index].uploadedfile_name = files[i].name;
this.selectedlogoupload.push(files[i]);
if (file.type.startsWith('image/')) {
const reader = new FileReader();
reader.onload = (e) => {
// Set the file preview source
const filePreview = e.target?.result as string;
this.FileDatalogoupload[index] = {
...this.FileDatalogoupload[index], // Preserve existing properties
filePreview: filePreview // Update only the filePreview property
};
};
reader.readAsDataURL(file);
}
}
}
onAddLineslogoupload() {
this.FileDatalogoupload.push({
uploadedfile_name: "",
filePreview: "",
// f3: "",
});
}
deleteRowlogoupload(index, id) {
this.FileDatalogoupload.splice(index, 1);
if (id) {
this.mainService.uploadLogouploaddelete(id).subscribe(data => {
console.log(data);
})
}
}
// updateaction
gotositebuilder(id) {

View File

@ -7,9 +7,10 @@ import { environment } from 'src/environments/environment';
providedIn: 'root'
})
export class SiteTreeservice {
private baseURL = "SiteTree/SiteTree";
private baseURL = "SiteTree/SiteTree";
private dlfbaseURL = environment.nodeUrl + "/entityBuilder";
private llmURL = environment.nodeUrl + "/llm";
private geminiURL = environment.ollamaUrl;
constructor(
@ -52,7 +53,7 @@ export class SiteTreeservice {
return this.apiRequest.get(_http);
}
callLlm(data: any): Observable<any> {
callLlm(data: any): Observable<any> {
return this.http.post(`${this.llmURL}/chatMemory`, data);
}
@ -68,24 +69,24 @@ export class SiteTreeservice {
return this.apiRequest.post(`sureops/deploy?projId=` + projId, data);
}
deploySiteBuilder(siteId: number, siteName: string, data: any): Observable<any> {
const formattedSiteName = this.formatSiteName(siteName);
const _http = `${this.baseURL}/deploy?siteId=${siteId}&siteBuilderName=${formattedSiteName}`;
return this.apiRequest.post(_http, data);
}
deploySiteBuilder(siteId: number, siteName: string, data: any): Observable<any> {
const formattedSiteName = this.formatSiteName(siteName);
const _http = `${this.baseURL}/deploy?siteId=${siteId}&siteBuilderName=${formattedSiteName}`;
return this.apiRequest.post(_http, data);
}
createHtmlfile(siteId: number, siteName: string, data: any): Observable<any> {
const formattedSiteName = this.formatSiteName(siteName);
const _http = `${this.baseURL}/createFile?siteId=${siteId}&siteBuilderName=${formattedSiteName}`;
return this.apiRequest.post(_http, data);
}
createHtmlfile(siteId: number, siteName: string, data: any): Observable<any> {
const formattedSiteName = this.formatSiteName(siteName);
const _http = `${this.baseURL}/createFile?siteId=${siteId}&siteBuilderName=${formattedSiteName}`;
return this.apiRequest.post(_http, data);
}
readPages( siteName: string, pageName: string): Observable<any> {
const formattedSite = this.formatSiteName(siteName);
const _http = `${this.baseURL}/read?siteBuilderName=${formattedSite}&filename=${pageName}`;
return this.apiRequest.get(_http, undefined, 'text');
}
readPages(siteName: string, pageName: string): Observable<any> {
const formattedSite = this.formatSiteName(siteName);
const _http = `${this.baseURL}/read?siteBuilderName=${formattedSite}&filename=${pageName}`;
return this.apiRequest.get(_http, undefined, 'text');
}
@ -94,11 +95,11 @@ readPages( siteName: string, pageName: string): Observable<any> {
}
private formatSiteName(name: string): string {
return name
.replace(/([a-z])([A-Z])/g, '$1_$2') // Convert camelCase to snake_case
.replace(/\s+/g, '_') // Replace spaces with underscores
.toLowerCase();
}
return name
.replace(/([a-z])([A-Z])/g, '$1_$2') // Convert camelCase to snake_case
.replace(/\s+/g, '_') // Replace spaces with underscores
.toLowerCase();
}
// readPages(siteNmae: String, pageNmae: String): Observable<any> {
@ -110,5 +111,22 @@ readPages( siteName: string, pageName: string): Observable<any> {
return this.http.post(`${this.llmURL}/api/gemini`, data);
}
uploadLogoupload(ref: any, Sitebuilder: any, file: any): Observable<any> {
const formData = new FormData();
formData.append('file', file);
return this.apiRequest.postFormData(`FileUpload/Uploadeddocs/${ref}/${Sitebuilder}`, formData);
}
uploadLogouploadgetById(ref: any, Sitebuilder: any,): Observable<any> {
return this.apiRequest.get(`FileUpload/Uploadeddocs/${ref}/${Sitebuilder}`);
}
uploadLogouploaddelete(id: number): Observable<any> {
return this.apiRequest.delete(`FileUpload/Uploadeddocs/${id}`);
}
// updateactionƒ
}

View File

@ -1,4 +1,6 @@
export const SiteTreecardvariable = {
"cardButton": false,
// "cardmodeldata": ``
"cardmodeldata": ``
}

View File

@ -0,0 +1,376 @@
<ol class="breadcrumb breadcrumb-arrow font-trirong">
<li><a href="javascript://"> Tag</a></li>
</ol>
<div class="dg-wrapper">
<div class="clr-row">
<div class="clr-col-8">
<h3>Tag </h3>
</div>
<div class="clr-col-4" style="text-align: right;">
<button *ngIf="cardButton" id="add" class="btn btn-primary btn-icon" (click)="changeView()" >
<clr-icon *ngIf="!isCardview" shape="grid-view"></clr-icon> <clr-icon *ngIf="isCardview" shape="bars"></clr-icon>
</button>
<!-- button -->
<button id="add" class="btn btn-primary" (click)="goToAdd(product)" >
<clr-icon shape="plus"></clr-icon>ADD
</button>
</div></div>
<ng-container *ngIf="!isCardview"> <!-- GET ALL --> <clr-datagrid [clrDgLoading]="loading" [(clrDgSelected)]="selected">
<clr-dg-placeholder>
<ng-template #loadingSpinner>
<clr-spinner>Loading ... </clr-spinner>
</ng-template>
<div *ngIf="error;else loadingSpinner">{{error}}</div>
</clr-dg-placeholder>
<clr-dg-column [clrDgField]="' name'"> <ng-container *clrDgHideableColumn="{hidden: false}"> Name
</ng-container></clr-dg-column>
<clr-dg-column [clrDgField]="' description'"> <ng-container *clrDgHideableColumn="{hidden: false}"> Description
</ng-container></clr-dg-column>
<clr-dg-column [clrDgField]="' active'"> <ng-container *clrDgHideableColumn="{hidden: false}"> Active
</ng-container></clr-dg-column>
<!-- who column -->
<clr-dg-column> <ng-container *clrDgHideableColumn="{hidden: false}">
<clr-icon shape="bars"></clr-icon> Action
</ng-container></clr-dg-column>
<!-- end -->
<clr-dg-row *clrDgItems="let user of product" [clrDgItem]="user">
<clr-dg-cell>{{user. name }}</clr-dg-cell>
<clr-dg-cell (click)="goToReplaceStringdescription (user.description)" style="cursor: pointer; align-items: center;"><clr-icon shape="details"></clr-icon>
</clr-dg-cell>
<clr-dg-cell>{{user. active }}</clr-dg-cell>
<!-- who column -->
<clr-dg-cell>
<clr-signpost>
<span style="cursor: pointer;" clrSignpostTrigger><clr-icon shape="help" class="success" style="color: rgb(0, 130, 236);"></clr-icon></span>
<clr-signpost-content [clrPosition]="'left-middle'" *clrIfOpen>
<h5 style="margin-top: 0">Who Column</h5>
<div>Account ID: <code class="clr-code">{{user.accountId}}</code></div>
<div>Created At: <code class="clr-code">{{user.createdAt| date}}</code></div>
<div>Created By: <code class="clr-code">{{user.createdBy}}</code></div>
<div>Updated At: <code class="clr-code">{{user.updatedAt | date}}</code></div>
<div>Updated By: <code class="clr-code">{{user.updatedBy}}</code></div>
</clr-signpost-content>
</clr-signpost>
</clr-dg-cell>
<!-- who colmn -->
<clr-dg-action-overflow>
<button class="action-item" (click)="onEdit(user)">Edit</button>
<button class="action-item" (click)="onDelete(user)">Delete</button>
</clr-dg-action-overflow>
</clr-dg-row>
<clr-dg-footer>
<clr-dg-pagination #pagination [clrDgPageSize]="10">
<clr-dg-page-size [clrPageSizeOptions]="[10,20,50,100]">Users per page</clr-dg-page-size>
{{pagination.firstItem + 1}} - {{pagination.lastItem + 1}}
of {{pagination.totalItems}} users
</clr-dg-pagination>
</clr-dg-footer>
</clr-datagrid> </ng-container>
<ng-template #showInfo>
<div class="alert alert-info" role="alert">
<div class="alert-items">
<div class="alert-item static">
<span class="alert-text">
<clr-icon class="alert-icon" shape="info-circle"></clr-icon>
Data could be found. Loading..
<clr-spinner [clrMedium]="true">Loading ...</clr-spinner>
</span>
</div>
</div>
</div>
</ng-template><ng-container *ngIf="isCardview">
<div *ngIf="product; else showInfo" class="clr-row clr-align-items-start clr-justify-content-start">
<div *ngFor="let app of product| filter:search; let index = i" class="clr-col-auto" >
<div class="clr-row">
<div class="clr-col-lg-12 clr-col-md-4 clr-col-sm-4 clr-col-12" style="width: 410px;">
<div class="card" style="padding: 10px; "[style.background-color]="cardmodal.cardColor !== '' ? cardmodal.cardColor : 'white'">
<div class="card-body" style="display: grid; grid-template-columns: repeat(13, 1fr); grid-template-rows: repeat(7, 1fr); gap: 5px;">
<ng-container *ngFor="let item of dashboardArray">
<div [style.gridColumn]="item.x + 1" [style.gridRow]="item.y + 1" [style.gridColumnEnd]="item.x + item.cols + 1"
[style.gridRowEnd]="item.y + item.rows + 1">
<div *ngIf="item.name === 'textField'" class="title-card card-title"
[style.text-align]="item.alignment !== '' ? item.alignment : 'left'"
[style.line-height]="item.textlineheight !== '' ? item.textlineheight : '1'"
[style.font-family]="item.fontName !== '' ? item.fontName : 'Metropolis'"
[style.font-size]="item.fontSize !== '' ? item.fontSize : '100%'"
[style.font-style]="item.italic == true ? 'Italic' : 'normal'"
[style.font-weight]="item.bold == true ? 'bold' : 'normal'" [style.text-decoration]="(item.underline && item.strikethough) ? 'underline line-through' :
(item.underline ? 'underline' : (item.strikethough ? 'line-through' : 'none'))"
[style.background-color]="item.backgroundcolor !== '' ? item.backgroundcolor : 'white'"
[style.color]="item.textcolor !== '' ? item.textcolor : 'black'" [style.background-color]="item.conditionValue == app[transform(item.fieldtext) ] ? item.conditionbackgroundcolor : item.backgroundcolor"
[style.color]="item.conditionValue == app[transform(item.fieldtext) ] ? item.conditiontextcolor : item.textcolor">
{{beforeText(item.fieldtext)}}
{{ app[transform(item.fieldtext) ] }}
{{afterText(item.fieldtext)}}
</div>
<div *ngIf="item.name === 'dateField'" class="title-card card-title"
[style.text-align]="item.alignment !== '' ? item.alignment : 'left'"
[style.line-height]="item.textlineheight !== '' ? item.textlineheight : '1'"
[style.font-family]="item.fontName !== '' ? item.fontName : 'Metropolis'"
[style.font-size]="item.fontSize !== '' ? item.fontSize : '100%'"
[style.font-style]="item.italic == true ? 'Italic' : 'normal'"
[style.font-weight]="item.bold == true ? 'bold' : 'normal'" [style.text-decoration]="(item.underline && item.strikethough) ? 'underline line-through' :
(item.underline ? 'underline' : (item.strikethough ? 'line-through' : 'none'))"
[style.background-color]="item.backgroundcolor !== '' ? item.backgroundcolor : 'white'"
[style.color]="item.textcolor !== '' ? item.textcolor : 'black'" [style.background-color]="item.conditionValue == app[transform(item.fieldtext) ] ? item.conditionbackgroundcolor : item.backgroundcolor"
[style.color]="item.conditionValue == app[transform(item.fieldtext) ] ? item.conditiontextcolor : item.textcolor">
{{beforeText(item.fieldtext)}}
{{ app[transform(item.fieldtext) ] | date}}
{{afterText(item.fieldtext)}}
</div>
<div *ngIf="item.name === 'numberField'" class="title-card card-title"
[style.text-align]="item.alignment !== '' ? item.alignment : 'left'"
[style.line-height]="item.textlineheight !== '' ? item.textlineheight : '1'"
[style.font-family]="item.fontName !== '' ? item.fontName : 'Metropolis'"
[style.font-size]="item.fontSize !== '' ? item.fontSize : '100%'"
[style.font-style]="item.italic == true ? 'Italic' : 'normal'"
[style.font-weight]="item.bold == true ? 'bold' : 'normal'" [style.text-decoration]="(item.underline && item.strikethough) ? 'underline line-through' :
(item.underline ? 'underline' : (item.strikethough ? 'line-through' : 'none'))"
[style.background-color]="item.backgroundcolor !== '' ? item.backgroundcolor : 'white'"
[style.color]="item.textcolor !== '' ? item.textcolor : 'black'" [style.background-color]="item.conditionValue == app[transform(item.fieldtext) ] ? item.conditionbackgroundcolor : item.backgroundcolor"
[style.color]="item.conditionValue == app[transform(item.fieldtext) ] ? item.conditiontextcolor : item.textcolor">
{{beforeText(item.fieldtext)}}
{{ app[transform(item.fieldtext) ]}}
{{afterText(item.fieldtext)}}
</div>
<div *ngIf="item.name === 'Line'" class="title-card card-title"
[style.text-align]="item.alignment !== '' ? item.alignment : 'left'"
[style.line-height]="item.textlineheight !== '' ? item.textlineheight : '1'"
[style.font-family]="item.fontName !== '' ? item.fontName : 'Metropolis'"
[style.font-size]="item.fontSize !== '' ? item.fontSize : '100%'"
[style.font-style]="item.italic == true ? 'Italic' : 'normal'"
[style.font-weight]="item.bold == true ? 'bold' : 'normal'" [style.text-decoration]="(item.underline && item.strikethough) ? 'underline line-through' :
(item.underline ? 'underline' : (item.strikethough ? 'line-through' : 'none'))"
[style.background-color]="item.backgroundcolor !== '' ? item.backgroundcolor : 'white'"
[style.color]="item.textcolor !== '' ? item.textcolor : 'black'">
<hr>
</div>
<div *ngIf="item.name === 'Icon'" class="icon-card"
[style.text-align]="item.alignment !== '' ? item.alignment : 'left'"
[style.line-height]="item.textlineheight !== '' ? item.textlineheight : '1'"
[style.font-family]="item.fontName !== '' ? item.fontName : 'Metropolis'"
[style.font-size]="item.fontSize !== '' ? item.fontSize : '100%'"
[style.font-style]="item.italic == true ? 'Italic' : 'normal'"
[style.font-weight]="item.bold == true ? 'bold' : 'normal'" [style.text-decoration]="(item.underline && item.strikethough) ? 'underline line-through' :
(item.underline ? 'underline' : (item.strikethough ? 'line-through' : 'none'))"
[style.background-color]="item.backgroundcolor !== '' ? item.backgroundcolor : 'white'"
[style.color]="item.textcolor !== '' ? item.textcolor : 'black'"
>
<clr-icon [attr.shape]="item.iconName"></clr-icon>
</div>
<div *ngIf="item.name == 'Image'"
[style.text-align]="item.alignment !== '' ? item.alignment : 'left'"
[style.line-height]="item.textlineheight !== '' ? item.textlineheight : '1'"
[style.font-family]="item.fontName !== '' ? item.fontName : 'Metropolis'"
[style.font-size]="item.fontSize !== '' ? item.fontSize : '100%'"
[style.font-style]="item.italic == true ? 'Italic' : 'normal'"
[style.font-weight]="item.bold == true ? 'bold' : 'normal'" [style.text-decoration]="(item.underline && item.strikethough) ? 'underline line-through' :
(item.underline ? 'underline' : (item.strikethough ? 'line-through' : 'none'))"
[style.background-color]="item.backgroundcolor !== '' ? item.backgroundcolor : 'white'"
[style.color]="item.textcolor !== '' ? item.textcolor : 'black'"
[style.background-color]="item.conditionValue == app[transform(item.fieldtext) ] ? item.conditionbackgroundcolor : item.backgroundcolor"
[style.color]="item.conditionValue == app[transform(item.fieldtext) ] ? item.conditiontextcolor : item.textcolor"> <img id="filePreview" [src]="item.imageURL" alt="File Preview"
[style.width]="item.imagewidth !== '' ? item.imagewidth + 'px' : '100px'"
[style.height]="item.imagewidth !== '' ? item.imagewidth + 'px' : '100px'"></div>
</div>
</ng-container>
</div>
</div>
</div>
</div>
</div>
</div>
</ng-container>
</div>
<clr-modal [(clrModalOpen)]="rsModaldescription" [clrModalSize]="'xl'" [clrModalStaticBackdrop]="true">
<div class="modal-body">
<textarea class="form-control" style="width:100%; height: 400px;" readonly>{{rowSelected}}</textarea>
</div></clr-modal>
<!-- // EDIT DATA......... -->
<clr-modal [(clrModalOpen)]="modalEdit" [clrModalSize]="'lg'" [clrModalStaticBackdrop]="true">
<h3 class="modal-title">Update Tag
<!--update button -->
</h3>
<div class="modal-body" *ngIf="rowSelected.id">
<h2 class="heading">{{rowSelected.id}}</h2>
<!-- button -->
<form >
<div class="clr-row">
<div class="clr-col-sm-12">
<label>Name</label>
<input class="clr-input" type="text" [(ngModel)]="rowSelected.name" name="name" />
</div>
<div class="clr-col-sm-12">
<label> Description</label>
<textarea cols="10" rows="2"[(ngModel)]="rowSelected.description" name="description " placeholder="Textarea"> </textarea>
</div>
<div class="clr-col-sm-12">
<label> Active</label>
<input type="checkbox" name="active" clrToggle [(ngModel)]="rowSelected.active" /> </div>
</div>
<!-- form code start -->
<div *ngIf="checkFormCode">
<h4 style="font-weight: 300;display: inline;">Extension</h4>
<br>
<hr>
<div class="clr-row">
<div class="clr-col-4" *ngFor="let field of additionalFieldsFromBackend">
<ng-container *ngIf="field.formCode === formcode" [ngSwitch]="field.fieldType">
<!-- Text Input --> <label *ngSwitchCase="'text'">{{ field.fieldName }}</label>
<input *ngSwitchCase="'text'" [type]="field.fieldType" name="{{ field.extValue }}" [(ngModel)]="rowSelected[field.extValue]" class="clr-input" />
<!-- Date Input --> <label *ngSwitchCase="'date'">{{ field.fieldName }}</label>
<input *ngSwitchCase="'date'" [type]="field.fieldType" name="{{ field.extValue }}" [(ngModel)]="rowSelected[field.extValue]" class="clr-input" />
<!-- Textarea --> <label *ngSwitchCase="'textarea'">{{ field.fieldName }}</label>
<textarea *ngSwitchCase="'textarea'" name="{{ field.extValue }}" [(ngModel)]="rowSelected[field.extValue]" col="10" row="2"></textarea>
<!-- Checkbox --> <label *ngSwitchCase="'checkbox'">{{ field.fieldName }}</label><br>
<input *ngSwitchCase="'checkbox'" [type]="field.fieldType" name="{{ field.extValue }}" [(ngModel)]="rowSelected[field.extValue]" class="clr-checkbox" />
</ng-container>
</div>
</div>
</div>
<!-- form code end --> <div class="modal-footer">
<button type="button" class="btn btn-outline" (click)="modalEdit = false">Cancel</button>
<button type="submit" class="btn btn-primary" (click)="onUpdate(rowSelected.id)">Update</button>
</div>
</form>
</div>
</clr-modal>
<clr-modal [(clrModalOpen)]="modaldelete" [clrModalSize]="'lg'" [clrModalStaticBackdrop]="true">
<div class="modal-body" *ngIf="rowSelected.id">
<h1 class="delete">Are You Sure Want to delete?</h1>
<h2 class="heading">{{rowSelected.id}}</h2>
<div class="modal-footer">
<button type="button" class="btn btn-outline" (click)="modaldelete = false">Cancel</button>
<button type="button" (click)="delete(rowSelected.id)" class="btn btn-primary" >Delete</button>
</div>
</div>
</clr-modal>
<!-- ADD FORM ..... -->
<clr-modal [(clrModalOpen)]="modalAdd" [clrModalSize]="'lg'" [clrModalStaticBackdrop]="true">
<h3 class="modal-title">Add Tag
<!-- aeroplane icon -->
&nbsp; &nbsp; &nbsp; &nbsp;
<a *ngIf="userrole.includes('ADMIN')" style="float: right;" href="javascript:void(0)" role="tooltip" aria-haspopup="true"
class="tooltip tooltip-sm tooltip-bottom-left">
<a id="build_extension" [routerLink]="['../extension/all']" [queryParams]="{ formCode: 'Tag_formCode' }">
<clr-icon shape="airplane" size="32"></clr-icon>
</a>
<span class="tooltip-content">Form Extension</span>
</a> </h3>
<div class="modal-body">
<form [formGroup]="entryForm" >
<div class="clr-row" style="height: fit-content;">
<div class="clr-col-sm-12">
<label> Name</label>
<input class="clr-input" type="text" formControlName="name" />
</div>
<div class="clr-col-sm-12">
<label> Description</label>
<textarea cols="10" rows="2" formControlName="description" placeholder="Textarea"> </textarea>
</div>
<div class="clr-col-sm-12">
<label> Active</label>
<input type="checkbox" formControlName="active" clrToggle/> </div>
</div>
<!-- form code start -->
<div *ngIf="checkFormCode">
<h4 style="font-weight: 300;display: inline;">Extension</h4>
<br>
<hr>
<div class="clr-row">
<div class="clr-col-4" *ngFor="let field of additionalFieldsFromBackend">
<ng-container *ngIf="field.formCode === formcode" [ngSwitch]="field.fieldType">
<!-- Text Input --> <label *ngSwitchCase="'text'">{{ field.fieldName }}</label>
<input *ngSwitchCase="'text'" [type]="field.fieldType" [formControlName]="field.extValue"
class="clr-input" />
<!-- Date Input --> <label *ngSwitchCase="'date'">{{ field.fieldName }}</label>
<input *ngSwitchCase="'date'" [type]="field.fieldType" [formControlName]="field.extValue"
class="clr-input" />
<!-- Textarea --> <label *ngSwitchCase="'textarea'">{{ field.fieldName }}</label>
<textarea *ngSwitchCase="'textarea'" [formControlName]="field.extValue" col="10" row="2"></textarea>
<!-- Checkbox --> <label *ngSwitchCase="'checkbox'">{{ field.fieldName }}</label><br>
<input *ngSwitchCase="'checkbox'" [type]="field.fieldType" [formControlName]="field.extValue"
class="clr-checkbox" />
</ng-container>
</div>
</div>
</div>
<!-- form code end --> <div class="modal-footer">
<button type="button" class="btn btn-outline" (click)="modalAdd = false">Cancel</button>
<button type="submit" class="btn btn-primary" (click)="onSubmit()">ADD</button>
</div>
</form>
</div>
</clr-modal>
<!-- htmlpopup -->

View File

@ -0,0 +1,78 @@
//@import "../../../../assets/scss/var";
.s-info-bar {
display: flex;
flex-direction: row;
justify-content: space-between;
button {
outline: none;
}
}
.delete,.heading{
text-align: center;
color: red;
}
.entry-pg {
width: 750px;
}
.button1::after {
content: none;
}
.button1:hover::after {
content: "ADD ROWS";
}
.section {
background-color: #dddddd;
height: 40px;
}
.section p {
//color: white;
padding: 10px;
font-size: 18px;
}
.clr-input {
color: #212529;
border: 1px solid #ced4da;
border-radius: 0.25rem;
padding: 0.75rem 0.75rem;
margin-top: 3px;
width: 100%;
margin-bottom: 10px;
}
.clr-file {
color: #212529;
border: 1px solid #ced4da;
border-radius: 0.25rem;
//padding: 0.6rem 0.75rem;
margin-top: 3px;
width: 100%;
margin-bottom: 10px;
}
.center {
text-align: center;
}
select{
width: 100%;
margin-top: 3px;
padding: 5px 5px;
border: 1px solid #ccc;
border-radius: 4px;
}
input[type=text],[type=date],[type=number],textarea {
width: 100%;
padding: 15px 15px;
background-color:rgb(255, 255, 255);
// margin: 8px 0;
display: inline-block;
border: 1px solid #ccc;
border-radius: 4px;
box-sizing: border-box;
}
.error_mess {
color: red;
}

View File

@ -0,0 +1,244 @@
import { Component, OnInit } from '@angular/core';
import { ToastrService } from 'ngx-toastr';
import { AlertService } from 'src/app/services/alert.service';
import { Tagservice } from './Tag.service';
import { AbstractControl, FormArray, FormBuilder, FormGroup, Validators, ValidationErrors } from '@angular/forms';
import { ExtensionService } from 'src/app/services/fnd/extension.service';
import { DashboardContentModel2 } from 'src/app/models/builder/dashboard';
import { Tagcardvariable } from './Tag_cardvariable';
import { UserInfoService } from 'src/app/services/user-info.service';
declare var JsBarcode: any;
@Component({
selector: 'app-Tag',
templateUrl: './Tag.component.html',
styleUrls: ['./Tag.component.scss']
})
export class TagComponent implements OnInit {
cardButton = Tagcardvariable.cardButton;
cardmodeldata = Tagcardvariable.cardmodeldata;
public dashboardArray: DashboardContentModel2[];
isCardview = Tagcardvariable.cardButton;
cardmodal; changeView() {
this.isCardview = !this.isCardview;
}
beforeText(fieldtext: string): string { // Extract the text before the first '<'
const index = fieldtext.indexOf('<');
return index !== -1 ? fieldtext.substring(0, index) : fieldtext;
}
afterText(fieldtext: string): string { // Extract the text after the last '>'
const index = fieldtext.lastIndexOf('>');
return index !== -1 ? fieldtext.substring(index + 1) : '';
}
transform(fieldtext: string): string {
const match = fieldtext.match(/<([^>]*)>/);
return match ? match[1] : ''; // Extract the text between '<' and '>'
}
userrole;
rowSelected: any = {};
modaldelete = false;
modalEdit = false;
modalAdd = false;
public entryForm: FormGroup;
loading = false;
product;
modalOpenedforNewLine = false;
newLine: any;
additionalFieldsFromBackend: any[] = [];
formcode = 'Tag_formCode'
tableName = 'Tag'; checkFormCode; selected: any[] = []; constructor(
private extensionService: ExtensionService,
private userInfoService: UserInfoService,
private mainService: Tagservice,
private alertService: AlertService,
private toastr: ToastrService,
private _fb: FormBuilder,
) { }
// component button
ngOnInit(): void {
if (this.cardmodeldata !== '') {
this.cardmodal = JSON.parse(this.cardmodeldata);
this.dashboardArray = this.cardmodal.dashboard.slice();
console.log(this.dashboardArray)
}
this.userrole = this.userInfoService.getRoles();
this.getData();
this.entryForm = this._fb.group({
name: [null],
description: [null],
active: [false],
}); // component_button200
// form code start
this.extensionService.getJsonObjectsByFormCodeList(this.formcode).subscribe(data => {
console.log(data);
const jsonArray = data.map((str) => JSON.parse(str));
this.additionalFieldsFromBackend = jsonArray;
this.checkFormCode = this.additionalFieldsFromBackend.some(field => field.formCode === "Tag_formCode");
console.log(this.checkFormCode);
console.log(this.additionalFieldsFromBackend);
if (this.additionalFieldsFromBackend && this.additionalFieldsFromBackend.length > 0) {
this.additionalFieldsFromBackend.forEach(field => {
if (field.formCode === this.formcode) {
if (!this.entryForm.contains(field.extValue)) {
// Add the control only if it doesn't exist in the form
this.entryForm.addControl(field.extValue, this._fb.control(field.fieldValue));
}
}
});
}
});
console.log(this.entryForm.value);
// form code end
}
error;
getData() {
this.mainService.getAll().subscribe((data) => {
console.log(data);
this.product = data;
if (this.product.length == 0) {
this.error = "No Data Available"
}
}, (error) => {
console.log(error);
if (error) {
this.error = "Server Error";
}
});
}
onEdit(row) {
this.rowSelected = row;
this.modalEdit = true;
}
onDelete(row) {
this.rowSelected = row;
this.modaldelete = true;
}
delete(id) {
this.modaldelete = false;
console.log("in delete " + id);
this.mainService.delete(id).subscribe(
(data) => {
console.log(data);
this.ngOnInit();
if (data) { this.toastr.success('Deleted successfully'); }
});
}
onUpdate(id) {
this.modalEdit = false;
//console.log("in update");
console.log("id " + id);
console.log(this.rowSelected);
//console.log("out update");
this.mainService.update(id, this.rowSelected).subscribe(
(data) => {
console.log(data);
if (data || data.status >= 200 && data.status <= 299) {
this.toastr.success("Update Successfully");
}
setTimeout(() => {
this.ngOnInit();
}, 500);
}, (error) => {
console.log(error);
if (error.status >= 200 && error.status <= 299) {
// this.toastr.success("update Succesfully");
}
if (error.status >= 400 && error.status <= 499) {
this.toastr.error("Not Updated");
}
if (error.status >= 500 && error.status <= 599) {
this.toastr.error("Not Updated");
}
});
setTimeout(() => {
this.ngOnInit();
}, 500);
}
onCreate() {
this.modalAdd = false;
this.mainService.create(this.entryForm.value).subscribe(
(data) => {
console.log(data);
if (data || data.status >= 200 && data.status <= 299) {
this.toastr.success("Added Successfully");
}
setTimeout(() => {
this.ngOnInit();
}, 500);
}, (error) => {
console.log(error);
if (error.status >= 200 && error.status <= 299) {
// this.toastr.success("Added Succesfully");
}
if (error.status >= 400 && error.status <= 499) {
this.toastr.error("Not Added");
}
if (error.status >= 500 && error.status <= 599) {
this.toastr.error("Not Added");
}
});
setTimeout(() => {
this.ngOnInit();
}, 500);
}
goToAdd(row) {
this.modalAdd = true; this.submitted = false;
}
submitted = false;
onSubmit() {
console.log(this.entryForm.value);
this.submitted = true;
if (this.entryForm.invalid) {
return;
} this.onCreate();
}
rsModaldescription = false;
goToReplaceStringdescription(row) {
this.rowSelected = row; this.rsModaldescription = true;
}
// updateaction
}

View File

@ -0,0 +1,39 @@
import { Injectable } from '@angular/core';
import { Observable } from "rxjs";
import { HttpClient, HttpHeaders, HttpParams, } from "@angular/common/http";
import { ApiRequestService } from "src/app/services/api/api-request.service";
import { environment } from 'src/environments/environment';
@Injectable({
providedIn: 'root'
})
export class Tagservice{
private baseURL = "Tag/Tag" ; constructor(
private http: HttpClient,
private apiRequest: ApiRequestService,
) { }
getAll(page?: number, size?: number): Observable<any> {
return this.apiRequest.get(this.baseURL);
}
getById(id: number): Observable<any> {
const _http = this.baseURL + "/" + id;
return this.apiRequest.get(_http);
}
create(data: any): Observable<any> {
return this.apiRequest.post(this.baseURL, data);
}
update(id: number, data: any): Observable<any> {
const _http = this.baseURL + "/" + id;
return this.apiRequest.put(_http, data);
}
delete(id: number): Observable<any> {
const _http = this.baseURL + "/" + id;
return this.apiRequest.delete(_http);
}
// updateaction
}

View File

@ -0,0 +1,4 @@
export const Tagcardvariable = {
"cardButton": false,
"cardmodeldata": ``
}

View File

@ -9,8 +9,12 @@ import * as sha256 from 'crypto-js/sha256';
import SHA256 from 'crypto-js/sha256';
import { CdkDrag, CdkDragDrop, CdkDropList, moveItemInArray, transferArrayItem } from '@angular/cdk/drag-drop';
import { trigger, transition, style, animate, state } from '@angular/animations';
import * as e from 'express';
import { json } from 'stream/consumers';
interface GeneratedSectionContent {
json: string;
css: string;
}
@Component({
selector: 'app-wireframe-renderer',
@ -50,6 +54,8 @@ import { json } from 'stream/consumers';
]
})
export class WireframeRendererComponent implements OnInit {
globalSections = [
@ -177,6 +183,8 @@ export class WireframeRendererComponent implements OnInit {
initialPrompt = '';
id: number;
allPagePrompts: Record<string, Record<string, string>> = {};
allPageCss: Record<string, Record<string, string>> = {};
initialGeneratedPrompts: Record<string, Record<string, string>> = {};
promptHashCache: Record<string, string> = {};
pageSections: Record<string, { FullPage: SafeHtml }> = {};
@ -186,12 +194,14 @@ export class WireframeRendererComponent implements OnInit {
sidebarCollapsed: boolean = false;
newlyGeneratedPages: string[] = [];
newlyGeneratedPages: string[] = [];
// Add toggle method
processedCssSections: string[] = [];
finalCssBundle: string = '';
deployedUrl: string | null = null;
deployedUrl: string | null = null;
// Added properties for grid and drag functionality
hoveredPage: string | null = null;
hoveredSection: string | null = null;
@ -202,7 +212,7 @@ deployedUrl: string | null = null;
lastX: number = 0;
lastY: number = 0;
isDragging = false;
startPanPosition = { x: 0, y: 0 };
startPanPosition = { x: 0, y: 0 };
// Edit mode properties
editMode: boolean = false;
editingSection: { page: string, section: string } | null = null;
@ -320,6 +330,7 @@ private async checkAllExistingFilesEnhanced(siteName: string, expectedPages: str
// Only create new HTML structure if the original doesn't have proper HTML tags
if (!rawHtml.includes('<!DOCTYPE') || !rawHtml.includes('<html')) {
completeHtml = this.createCompleteHtml(pageName, parsed.css, parsed.bodyHtml);
}
@ -867,7 +878,9 @@ fetchTreeById(id: number) {
this.dividePagesToExistingOrNew(this.jsonInput, this.sitename);
this.updateLoadingProgress(20, 'Model data loaded successfully');
await this.generateMissingPagesWithAI(this.missingPages, this.jsonInput);
console.log("Printing Final Map of Html ", this.missingHtmlPages)
console.log("Printing Final Map of Html ", this.mapofPageAndHtmlBody)
// Start the enhanced processing flow
// await this.processAllPagesWithExistingCheck(this.jsonInput);
} catch (err) {
@ -887,11 +900,11 @@ fetchTreeById(id: number) {
}
});
}
goToWireFrameEdit(){
let mapOfHtml:any;
this.router.navigate(["../WireFrameEdit/",{ mapOfHtml: this.mapofPageAndHtmlBody }])
goToWireFrameEdit() {
localStorage.setItem('mapOfHtml',JSON.stringify(this.mapofPageAndHtmlBody));
this.router.navigate(['/cns-portal/WireFrameEdit']);
}
/* Step 2: Process all pages with existing file checking
*/
async processAllPagesWithExistingCheck(treeJsonString: string) {
@ -1037,8 +1050,25 @@ private async generatePromptsForMissingPage(pageName: string, sections: any) {
this.sectionOrderMap[pageName].push(sectionName);
const prompt = await this.generatePromptFromSection(sectionName, sectionDescription as string);
sectionPrompts[sectionName] = prompt;
sectionPrompts[sectionName] = prompt.json;
// ✅ Store section-wise CSS externally
if (!this.allPageCss[pageName]) {
this.allPageCss[pageName] = {};
}
this.allPageCss[pageName][sectionName] = prompt.css;
// store for unique css
const templateKey = sectionName.toLowerCase().replace(/section$/, '').trim();
if (!this.processedCssSections.includes(templateKey)) {
this.processedCssSections.push(templateKey);
this.finalCssBundle += prompt.css + '\n';
}
}
this.allPagePrompts[pageName] = sectionPrompts;
this.initialGeneratedPrompts[pageName] = { ...sectionPrompts };
@ -1449,8 +1479,26 @@ private async processMissingPagesEnhanced(treeJson: any, missingPages: string[])
this.sectionOrderMap[pageName].push(sectionName);
const prompt = await this.generatePromptFromSection(sectionName, sectionDescription as string);
sectionPrompts[sectionName] = prompt;
sectionPrompts[sectionName] = prompt.json;
// ✅ Store section-wise CSS externally
if (!this.allPageCss[pageName]) {
this.allPageCss[pageName] = {};
}
this.allPageCss[pageName][sectionName] = prompt.css;
// store for unique css
const templateKey = sectionName.toLowerCase().replace(/section$/, '').trim();
if (!this.processedCssSections.includes(templateKey)) {
this.processedCssSections.push(templateKey);
this.finalCssBundle += prompt.css + '\n';
}
}
this.allPagePrompts[pageName] = sectionPrompts;
this.initialGeneratedPrompts[pageName] = { ...sectionPrompts };
@ -1501,7 +1549,21 @@ private async processAllPagesEnhanced(treeJson: any) {
this.sectionOrderMap[pageName].push(sectionName);
const prompt = await this.generatePromptFromSection(sectionName, sectionDescription);
sectionPrompts[sectionName] = prompt;
sectionPrompts[sectionName] = prompt.json;
// ✅ Store section-wise CSS externally
if (!this.allPageCss[pageName]) {
this.allPageCss[pageName] = {};
}
this.allPageCss[pageName][sectionName] = prompt.css;
// store for unique css
const templateKey = sectionName.toLowerCase().replace(/section$/, '').trim();
if (!this.processedCssSections.includes(templateKey)) {
this.processedCssSections.push(templateKey);
this.finalCssBundle += prompt.css + '\n';
}
}
this.allPagePrompts[pageName] = sectionPrompts;
@ -1579,7 +1641,10 @@ async processPageSectionsEnhanced(pageName: string, sectionMap: Record<string, s
await Promise.all(htmlTasks);
// Create complete HTML structure for the page
const completeHtml = this.createCompleteHtml(pageName, COMMON_CSS, sectionHtmls.join('\n'));
const css = this.getCombinedSectionCss(pageName);
const completeHtml = this.createCompleteHtml(pageName, css, sectionHtmls.join('\n'));
const safeHtml = completeHtml;
this.pageSections[pageName] = { FullPage: safeHtml };
@ -1622,13 +1687,14 @@ HTML Only. No CSS.
Focus on layout that matches a modern UI semantic, responsive, and readable.
Use placeholders for image/icon blocks where appropriate (e.g., <div style="width:100px;height:30px;background:#ccc;"></div>)`;
// Generate prompt from section
async generatePromptFromSection(
sectionName: string,
sectionDescription: string,
headerId: number = 35,
operationType: string = 'template 1'
): Promise<string> {
): Promise<GeneratedSectionContent> {
return new Promise((resolve) => {
const fieldType = sectionName.toLowerCase().replace(/section$/i, '').trim();
@ -1639,8 +1705,11 @@ HTML Only. No CSS.
try {
// const jsonBlock = res?.javacode;
const jsonBlock = res?.htmljson;
const sectionCss = res?.css || '';
// if (!jsonBlock) return resolve('{}');
if (!jsonBlock) return resolve({ json: '{}', css: '' });
if (!jsonBlock) return resolve('{}');
console.log(' base json is ...',jsonBlock);
const baseJson = typeof jsonBlock === 'string' ? JSON.parse(jsonBlock) : jsonBlock;
@ -1673,7 +1742,9 @@ HTML Only. No CSS.
const hash = sha256(enhancedPrompt).toString();
if (this.promptHashCache[hash]) {
return resolve(this.promptHashCache[hash]);
// return resolve(this.promptHashCache[hash]);
return resolve({ json: this.promptHashCache[hash], css: sectionCss });
}
const enhanced = await this.callAi(enhancedPrompt);
@ -1682,16 +1753,27 @@ HTML Only. No CSS.
this.promptHashCache[hash] = enhanced;
// resolve(baseJsonString);
resolve(this.promptHashCache[hash]);
// resolve(this.promptHashCache[hash]);
resolve({ json: this.promptHashCache[hash], css: sectionCss });
} catch (err) {
console.error('❌ JSON parse error:', err);
resolve('{}');
// resolve('{}');
resolve({ json: '{}', css: '' });
}
},
error: () => resolve('{}')
error: () => resolve({ json: '{}', css: '' })
// error: () => resolve('{}')
});
});
}
private getCombinedSectionCss(pageName: string): string {
const sectionCssMap = this.allPageCss[pageName] || {};
return Object.values(sectionCssMap).join('\n');
}
// Process all pages live update
async processAllPagesLiveUpdate() {
const htmlGenerationTasks: Promise<void>[] = [];
@ -1828,8 +1910,6 @@ private createCompleteHtml(pageName: string, css: string, bodyHtml: string): str
<style>
${css}
/* Additional common styles */
${COMMON_CSS}
html, body {
margin: 0 !important;
@ -1905,7 +1985,8 @@ createHtmlFiles() {
// Ensure we have valid HTML
if (!html.includes('<!DOCTYPE') && !html.includes('<html')) {
// If it's just body content, wrap it properly
html = this.createCompleteHtml(pageName, COMMON_CSS, html);
const css = this.getCombinedSectionCss(pageName);
html = this.createCompleteHtml(pageName, css, html);
}
const sanitizedPageName = this.sanitizeFilename(pageName);
@ -1933,9 +2014,9 @@ async generateJson(data: { jsonStructure: any, sectionType: string }): Promise<s
return new Promise((resolve) => {
try {
const parsedJson =
typeof data.jsonStructure === 'string'
? JSON.parse(data.jsonStructure)
: data.jsonStructure;
typeof data.jsonStructure.json === 'string'
? JSON.parse(data.jsonStructure.json)
: data.jsonStructure.json;
// Check for empty or invalid parsed JSON
const isEmpty = !parsedJson || Object.keys(parsedJson).length === 0;
@ -2059,6 +2140,64 @@ downloadHtml(pageName: string) {
});
}
buildSiteBuilder() {
const pageHtmlMap: Record<string, string> = {};
for (const [pageName, section] of Object.entries(this.pageSections)) {
const html = section.FullPage?.toString() || '';
pageHtmlMap[pageName] = html;
}
const payload = {
css: this.finalCssBundle,
pageHtmlMap: pageHtmlMap
};
this.siteTreeService.deploySiteBuilder(this.siteId,this.sitename,payload).subscribe(
(data) => {
console.log(data);
if (data || data.status >= 200 && data.status <= 299) {
this.siteTreeService.getById(this.siteId).subscribe({
next: async (res) => {
console.log('📥 Fetched from getById again :', res);
if (res ) {
this.deployedUrl = res.deployedUrl;
console.log('deployed url is ', this.deployedUrl)
} else {
console.warn('⚠️ Deployed Url Not found');
}
},
error: (err) => {
console.error('❌ Error in getById:', err);
}
});
this.toastr.success("Site builder Deploying Start..");
}
// setTimeout(() => {
// this.ngOnInit();
// }, 500);
}, (error) => {
console.log(error);
if (error.status >= 200 && error.status <= 299) {
this.toastr.success("deployed Files Created Successfully");
}
if (error.status >= 400 && error.status <= 499) {
this.toastr.error(" deployed Files Not Created");
}
if (error.status >= 500 && error.status <= 599) {
this.toastr.error("deployed Server Error");
}
});
}
@ -2568,6 +2707,42 @@ copyPageToClipboard(pageName?: string): void {
}
}
// this is for show code
showCodeModal = false;
editableHtml = '';
currentEditingPage = '';
showCode(pageName?: string): void {
const pageToSelect = pageName || this.getCurrentPageName();
const html = this.mapofPageAndHtmlBody[pageToSelect];
if (html) {
this.currentEditingPage = pageToSelect;
this.editableHtml = html;
this.showCodeModal = true;
} else {
this.toastr.error('No code found for this page');
}
}
saveEditedCode(): void {
if (this.currentEditingPage && this.editableHtml) {
this.mapofPageAndHtmlBody[this.currentEditingPage] = this.editableHtml;
this.toastr.success(`${this.currentEditingPage} HTML updated`);
this.showCodeModal = false;
} else {
this.toastr.error('Failed to save. Missing page or HTML.');
}
}
cancelEdit(): void {
this.showCodeModal = false;
this.editableHtml = '';
this.currentEditingPage = '';
}
// show code end
@ -2899,9 +3074,9 @@ downloadCurrentPage(): void {
// Add this to initialize the current page
getPageTransform(): string {
return `scale(${this.scale})`;
}
getPageTransform(): string {
return `scale(${this.scale})`;
}
refreshAllSectionCSS(): void {
// Refresh CSS in all section previews
@ -3096,20 +3271,20 @@ getCurrentPageName(): string {
// Update the canvas transform methods
// Detect if the device is mobile (simple check)
get isMobile(): boolean {
return /Android|webOS|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini/i.test(navigator.userAgent);
}
// Open new section modal
addNewSection(pageName: string, afterSection: string = null) {
this.showNewSectionModal = true;
this.newSectionPage = pageName;
this.newSectionAfter = afterSection;
this.newSectionName = '';
this.newSectionType = '';
this.newSectionDescription = '';
}
// Detect if the device is mobile (simple check)
get isMobile(): boolean {
return /Android|webOS|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini/i.test(navigator.userAgent);
}
// Open new section modal
addNewSection(pageName: string, afterSection: string = null) {
this.showNewSectionModal = true;
this.newSectionPage = pageName;
this.newSectionAfter = afterSection;
this.newSectionName = '';
this.newSectionType = '';
this.newSectionDescription = '';
}
// Cancel adding new section
cancelAddSection() {
@ -3214,7 +3389,7 @@ getCurrentPageName(): string {
missingPages:string[] = [];
existingPages:string[] = [];
async dividePagesToExistingOrNew(jsonOutput: string, siteName: string) {
async dividePagesToExistingOrNew(jsonOutput: string, siteName: string) {
let parseJson = JSON.parse(jsonOutput);
// Extract pages in the exact order they appear in JSON
@ -3363,6 +3538,8 @@ async mapOfExistingPagesWithHtmlCss(existingPages: string[]): Promise<void> {
try {
await Promise.all(pagePromises);
console.log('All existing pages loaded:', this.mapofPageAndHtmlBody);
console.log("Start The Deployment! ")
await this.deployAllPages()
} catch (error) {
console.error('Error loading some pages:', error);
}
@ -3393,7 +3570,9 @@ calculateSectionHtmlsForExistingPage(pageName: string, htmlContent: string): voi
this.sectionHtmls[pageName]['FullPage'] = this.sanitizer.bypassSecurityTrustHtml(htmlContent);
}
}
async generateMissingPagesWithAI(missingPages: string[], jsonInput: string): Promise<void> {
async generateMissingPagesWithAI(missingPages: string[], jsonInput: string): Promise<void> {
if (!missingPages.length) {
this.toastr.info('No missing pages to generate');
return;
@ -3447,7 +3626,22 @@ calculateSectionHtmlsForExistingPage(pageName: string, htmlContent: string): voi
for (const [sectionName, sectionDescription] of sectionEntries) {
// Generate prompt for section, passing the full jsonInput as context
const prompt = await this.generatePromptFromSection(sectionName, sectionDescription as string);
this.allPagePrompts[pageName][sectionName] = prompt;
this.allPagePrompts[pageName][sectionName] = prompt.json;
// ✅ Store section-wise CSS externally
if (!this.allPageCss[pageName]) {
this.allPageCss[pageName] = {};
}
this.allPageCss[pageName][sectionName] = prompt.css;
// store for unique css
const templateKey = sectionName.toLowerCase().replace(/section$/, '').trim();
if (!this.processedCssSections.includes(templateKey)) {
this.processedCssSections.push(templateKey);
this.finalCssBundle += prompt.css + '\n';
}
// Generate HTML for section
const html = await this.generateJson({ sectionType: sectionName, jsonStructure: prompt });
@ -3458,7 +3652,9 @@ calculateSectionHtmlsForExistingPage(pageName: string, htmlContent: string): voi
sanitizedPageName = this.sanitizeFilename(pageName);
// Combine all section HTMLs and CSS for the page
const finalHtml = this.createCompleteHtml(sanitizedPageName, COMMON_CSS, sectionHtmls.join('\n'));
const css = this.getCombinedSectionCss(pageName);
const finalHtml = this.createCompleteHtml(sanitizedPageName, css, sectionHtmls.join('\n'));
this.pageSections[pageName] = { FullPage: finalHtml };
this.mapofPageAndHtmlBody[pageName] = finalHtml;
@ -3472,17 +3668,22 @@ calculateSectionHtmlsForExistingPage(pageName: string, htmlContent: string): voi
for (const [pageName, html] of pagesToSave.entries()) {
const pageObj: Record<string, string> = { [pageName]: html };
const payload = {
css: this.finalCssBundle,
pageHtmlMap: pageObj
};
// Ensure the page name is sanitized
await new Promise<void>((resolve) => {
this.siteTreeService.createHtmlfile(this.siteId, this.sitename, pageObj).subscribe({
this.siteTreeService.createHtmlfile(this.siteId, this.sitename, payload).subscribe({
next: (response) => {
console.log(`Page "${pageName}" created successfully.`);
this.toastr.success(`Generated and saved page: ${pageName}`);
// this.toastr.success(`Generated and saved page: ${pageName}`);
resolve();
},
error: (error) => {
console.error(`Error creating page "${pageName}":`, error);
this.toastr.error(`Failed to save generated page: ${pageName}`);
// this.toastr.error(`Failed to save generated page: ${pageName}`);
resolve();
}
});
@ -3506,7 +3707,9 @@ calculateSectionHtmlsForExistingPage(pageName: string, htmlContent: string): voi
// }
console.log('Map of All Pages with HTML:', this.mapofPageAndHtmlBody);
this.toastr.success('Generated all missing pages with AI.');
console.log('Generated all missing pages with AI...');
// this.toastr.success('Generated all missing pages with AI.');
this.cdr.detectChanges();
}
@ -3519,6 +3722,26 @@ calculateSectionHtmlsForExistingPage(pageName: string, htmlContent: string): voi
// Add this property to your component
isGridView: boolean = false; // Set to true for grid, false for single page
async deployAllPages() {
// this.toastr.info("Deploying all pages...");
try {
console.log("SITE ID ",this.siteId)
console.log("SITE NAME FORMATTED ",this.formatSiteName(this.sitename));
this.siteTreeService.deploySiteBuilder(+this.siteId,
this.formatSiteName(this.sitename).trim(),
this.mapofPageAndHtmlBody
)
// this.toastr.success("All pages deployed successfully!");
} catch (error) {
console.error(`Error deploy}:`, error);
this.toastr.error(`Failed to deploy page: `);
}
}
}

View File

@ -146,7 +146,7 @@
left: 0;
width: 100%;
height: 100%;
background: rgba(0,0,0,0.75);
background: rgba(0, 0, 0, 0.75);
display: flex;
align-items: center;
justify-content: center;
@ -155,17 +155,27 @@
animation: fadeIn 0.3s ease-out;
}
/* Main Popup Content */
/* Main Popup Content */
.popup-content {
width: 600px;
max-height: none;
width: 900px;
/* ⬅️ Increased from 600px to 900px */
max-width: 95vw;
/* ⬅️ Prevent overflow on smaller screens */
max-height: 90vh;
/* ⬅️ Avoid overflowing vertically */
padding: 24px;
box-shadow: 0 8px 24px rgba(0,0,0,0.25);
border-radius: 8px;
/* ⬅️ More spacing */
box-shadow: 0 8px 24px rgba(0, 0, 0, 0.25);
border-radius: 12px;
/* ⬅️ Slightly larger corners */
background-color: snow;
animation: slideIn 0.4s ease-out;
overflow-y: auto;
/* ⬅️ Scroll if content overflows vertically */
}
.close-btn {
background: transparent;
border: none;
@ -193,7 +203,7 @@
font-family: inherit;
resize: vertical;
transition: border 0.3s ease;
box-shadow: 0 2px 4px rgba(0,0,0,0.05);
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.05);
padding: 12px;
border: 1px solid #ddd;
border-radius: 6px;
@ -240,13 +250,13 @@
border-radius: 4px;
cursor: pointer;
transition: all 0.2s ease;
box-shadow: 0 2px 4px rgba(0,0,0,0.2);
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.2);
}
.generate-btn:hover {
background: #1565c0;
transform: translateY(-1px);
box-shadow: 0 4px 8px rgba(0,0,0,0.3);
box-shadow: 0 4px 8px rgba(0, 0, 0, 0.3);
}
/* Loading Container */
@ -255,7 +265,7 @@
padding: 40px;
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
border-radius: 16px;
box-shadow: 0 20px 40px rgba(0,0,0,0.3);
box-shadow: 0 20px 40px rgba(0, 0, 0, 0.3);
text-align: center;
position: relative;
overflow: hidden;
@ -269,13 +279,11 @@
right: 0;
bottom: 0;
opacity: 0.1;
background-image: repeating-linear-gradient(
45deg,
transparent,
transparent 10px,
rgba(255,255,255,0.1) 10px,
rgba(255,255,255,0.1) 20px
);
background-image: repeating-linear-gradient(45deg,
transparent,
transparent 10px,
rgba(255, 255, 255, 0.1) 10px,
rgba(255, 255, 255, 0.1) 20px);
}
.loader-content {
@ -287,12 +295,12 @@
width: 80px;
height: 80px;
margin: 0 auto 24px;
background: rgba(255,255,255,0.15);
background: rgba(255, 255, 255, 0.15);
border-radius: 50%;
display: flex;
align-items: center;
justify-content: center;
box-shadow: 0 8px 32px rgba(0,0,0,0.2);
box-shadow: 0 8px 32px rgba(0, 0, 0, 0.2);
animation: spinPulse 2s ease-in-out infinite;
}
@ -306,7 +314,7 @@
font-size: 28px;
font-weight: 600;
margin-bottom: 16px;
text-shadow: 0 2px 4px rgba(0,0,0,0.3);
text-shadow: 0 2px 4px rgba(0, 0, 0, 0.3);
}
.dots {
@ -314,7 +322,7 @@
}
.thinking-subtitle {
color: rgba(255,255,255,0.9);
color: rgba(255, 255, 255, 0.9);
font-size: 16px;
margin-bottom: 32px;
}
@ -330,15 +338,29 @@
width: 12px;
height: 12px;
border-radius: 50%;
background: rgba(255,255,255,0.4);
background: rgba(255, 255, 255, 0.4);
animation: dotPulse 1.4s infinite ease-in-out;
}
.dot-1 { animation-delay: 0s; }
.dot-2 { animation-delay: 0.2s; }
.dot-3 { animation-delay: 0.4s; }
.dot-4 { animation-delay: 0.6s; }
.dot-5 { animation-delay: 0.8s; }
.dot-1 {
animation-delay: 0s;
}
.dot-2 {
animation-delay: 0.2s;
}
.dot-3 {
animation-delay: 0.4s;
}
.dot-4 {
animation-delay: 0.6s;
}
.dot-5 {
animation-delay: 0.8s;
}
.particles {
position: absolute;
@ -352,7 +374,7 @@
.particle {
position: absolute;
border-radius: 50%;
background: rgba(255,255,255,0.6);
background: rgba(255, 255, 255, 0.6);
animation: float 3s infinite ease-in-out;
}
@ -367,7 +389,7 @@
.particle-2 {
width: 6px;
height: 6px;
background: rgba(255,255,255,0.4);
background: rgba(255, 255, 255, 0.4);
top: 60%;
right: 20%;
animation-duration: 4s;
@ -377,7 +399,7 @@
.particle-3 {
width: 3px;
height: 3px;
background: rgba(255,255,255,0.7);
background: rgba(255, 255, 255, 0.7);
bottom: 30%;
left: 25%;
animation-duration: 2.5s;
@ -386,7 +408,7 @@
.particle-4 {
width: 5px;
height: 5px;
background: rgba(255,255,255,0.5);
background: rgba(255, 255, 255, 0.5);
top: 40%;
right: 15%;
animation-duration: 3.5s;
@ -399,7 +421,7 @@
padding: 32px;
background: linear-gradient(135deg, #ff6b6b 0%, #ee5a52 100%);
border-radius: 16px;
box-shadow: 0 20px 40px rgba(0,0,0,0.3);
box-shadow: 0 20px 40px rgba(0, 0, 0, 0.3);
text-align: center;
position: relative;
animation: slideIn 0.4s ease-out;
@ -409,7 +431,7 @@
width: 80px;
height: 80px;
margin: 0 auto 24px;
background: rgba(255,255,255,0.15);
background: rgba(255, 255, 255, 0.15);
border-radius: 50%;
display: flex;
align-items: center;
@ -422,11 +444,11 @@
font-size: 24px;
font-weight: 600;
margin-bottom: 12px;
text-shadow: 0 2px 4px rgba(0,0,0,0.3);
text-shadow: 0 2px 4px rgba(0, 0, 0, 0.3);
}
.error-message {
color: rgba(255,255,255,0.9);
color: rgba(255, 255, 255, 0.9);
font-size: 16px;
margin-bottom: 32px;
line-height: 1.5;
@ -434,9 +456,9 @@
.retry-btn {
padding: 12px 20px;
background: rgba(255,255,255,0.2);
background: rgba(255, 255, 255, 0.2);
color: white;
border: 1px solid rgba(255,255,255,0.3);
border: 1px solid rgba(255, 255, 255, 0.3);
border-radius: 8px;
cursor: pointer;
transition: all 0.2s ease;
@ -444,7 +466,7 @@
}
.retry-btn:hover {
background: rgba(255,255,255,0.3);
background: rgba(255, 255, 255, 0.3);
transform: translateY(-1px);
}
@ -469,6 +491,7 @@
from {
opacity: 0;
}
to {
opacity: 1;
}
@ -479,6 +502,7 @@
opacity: 0;
transform: translateY(30px) scale(0.95);
}
to {
opacity: 1;
transform: translateY(0) scale(1);
@ -486,44 +510,76 @@
}
@keyframes spinPulse {
0%, 100% {
0%,
100% {
transform: rotate(0deg) scale(1);
box-shadow: 0 8px 32px rgba(0,0,0,0.2);
box-shadow: 0 8px 32px rgba(0, 0, 0, 0.2);
}
50% {
transform: rotate(180deg) scale(1.1);
box-shadow: 0 12px 48px rgba(0,0,0,0.3);
box-shadow: 0 12px 48px rgba(0, 0, 0, 0.3);
}
}
@keyframes brainThink {
0%, 100% { transform: scale(1) rotate(0deg); }
25% { transform: scale(1.1) rotate(-5deg); }
75% { transform: scale(0.95) rotate(5deg); }
0%,
100% {
transform: scale(1) rotate(0deg);
}
25% {
transform: scale(1.1) rotate(-5deg);
}
75% {
transform: scale(0.95) rotate(5deg);
}
}
@keyframes typewriter {
0%, 20% { opacity: 1; }
50% { opacity: 0; }
80%, 100% { opacity: 1; }
0%,
20% {
opacity: 1;
}
50% {
opacity: 0;
}
80%,
100% {
opacity: 1;
}
}
@keyframes dotPulse {
0%, 20%, 80%, 100% {
0%,
20%,
80%,
100% {
transform: scale(1);
background: rgba(255,255,255,0.4);
background: rgba(255, 255, 255, 0.4);
}
40% {
transform: scale(1.5);
background: rgba(255,255,255,0.9);
background: rgba(255, 255, 255, 0.9);
}
}
@keyframes float {
0%, 100% {
0%,
100% {
transform: translateY(0px) rotate(0deg);
opacity: 0.6;
}
50% {
transform: translateY(-20px) rotate(180deg);
opacity: 1;
@ -531,14 +587,27 @@
}
@keyframes errorShake {
0%, 100% { transform: translateX(0); }
25% { transform: translateX(-10px); }
75% { transform: translateX(10px); }
0%,
100% {
transform: translateX(0);
}
25% {
transform: translateX(-10px);
}
75% {
transform: translateX(10px);
}
}
/* Responsive Design */
@media (max-width: 768px) {
.popup-content, .loading-container, .error-container {
.popup-content,
.loading-container,
.error-container {
width: 90%;
margin: 0 20px;
}

View File

@ -145,18 +145,19 @@ export class TreeVisualizerComponent {
}
// Add these properties to your component class
isLoading = false;
showError = false;
// Add these properties to your component class
isLoading = false;
showError = false;
// Method to handle the enhanced generate flow
generateJsonWithLoading() {
// Method to handle the enhanced generate flow
generateJsonWithLoading() {
this.isLoading = true;
this.showError = false;
console.log('🔄 Starting generateJsonWithLoading...');
// Call the actual generateJson method
const [minPages, maxPages] = this.selectedPageRange.split("-").map(Number);
const prompt = `
You are a JSON structure generator for website UI and sitemap hierarchy.
@ -165,19 +166,20 @@ showError = false;
Each page must contain:
- 4 to 5 meaningful UI sections (e.g., "Header Section", "Form Section", "Feature Section", etc.)
- Each page MUST contain at least 6 meaningful UI sections (including "Navbar" and "Footer"). These sections should be clearly named and described (e.g., "Header Section", "Hero Section", "Testimonial Section", etc.). You are NOT allowed to include fewer than 6 sections on any page.
- A "Navbar" and a "Footer" section (always included on every page)
- A short, clear description for each section (to support frontend development)
Constraints:
- Total number of pages (including nested children) must be between ${this.selectedPageRange}
- Do NOT create unnecessary or generic pages (e.g., no "Blog", "FAQ", etc.) unless explicitly present in the user flow
- Pages that appear after user actions (e.g., clicking a card or after login) must be nested under the relevant parent using a "Children" key
- DO NOT include any standalone section like "FAQ" or "Blog" as top-level pages unless mentioned
📘 Website Context:
${this.rawInputText}
🔒 Strict Constraints:
- You MUST generate at least ${minPages} and not more than ${maxPages} unique pages in total (including nested children), be strict on this
- Each page MUST contain at least 6 meaningful UI sections (including "Navbar" and "Footer")
- Do NOT create unnecessary or generic pages (e.g., no "Blog", "FAQ", etc.) unless explicitly present in the user flow
- Pages that appear after user actions (e.g., clicking a card or after login) must be nested under the relevant parent using a "Children" key
- DO NOT include any standalone section like "FAQ" or "Blog" as top-level pages unless mentioned
--- Reference Format (DO NOT COPY; for structure only) ---
@ -202,7 +204,6 @@ showError = false;
}
}
---
🚫 DO NOT:
- Include any explanation, notes, comments, or formatting (like \`\`\` or \`json\`)
- Do NOT return escaped or markdown-formatted JSON
@ -290,66 +291,66 @@ showError = false;
});
}
// Helper method to check if all calls are complete
private checkAndCompleteGeneration(parsedJson: any, pendingCalls: number) {
if (pendingCalls === 0) {
this.completeGeneration(parsedJson);
}
}
// Helper method to complete the generation process
private completeGeneration(parsedJson: any) {
this.inputJson = JSON.stringify(parsedJson);
const updatePayload = {
prompt: this.rawInputText + ' ',
model: this.inputJson
};
console.log('✅ Final merged JSON ready, updating server...');
this.siteTreeService.update(this.id, updatePayload).subscribe({
next: (resp) => {
console.log('✅ Successfully updated server:', resp);
// Success - close popup and show results
this.isLoading = false;
this.showPopup = false;
this.activeTab = 'sitemap';
// Convert and display the tree
this.convertJson();
console.log('🎉 Generation completed successfully!');
},
error: (err) => {
console.error('❌ Failed to update server:', err);
this.handleGenerationError('Failed to save site structure');
// Helper method to check if all calls are complete
private checkAndCompleteGeneration(parsedJson: any, pendingCalls: number) {
if (pendingCalls === 0) {
this.completeGeneration(parsedJson);
}
});
}
}
// Helper method to handle errors
private handleGenerationError(message: string) {
console.error('❌ Generation failed:', message);
this.isLoading = false;
this.showError = true;
// Don't close popup so user can retry
}
// Helper method to complete the generation process
private completeGeneration(parsedJson: any) {
this.inputJson = JSON.stringify(parsedJson);
const updatePayload = {
prompt: this.rawInputText + ' ',
model: this.inputJson
};
console.log('✅ Final merged JSON ready, updating server...');
this.siteTreeService.update(this.id, updatePayload).subscribe({
next: (resp) => {
console.log('✅ Successfully updated server:', resp);
// Success - close popup and show results
this.isLoading = false;
this.showPopup = false;
this.activeTab = 'sitemap';
// Convert and display the tree
this.convertJson();
console.log('🎉 Generation completed successfully!');
},
error: (err) => {
console.error('❌ Failed to update server:', err);
this.handleGenerationError('Failed to save site structure');
}
});
}
// Helper method to handle errors
private handleGenerationError(message: string) {
console.error('❌ Generation failed:', message);
this.isLoading = false;
this.showError = true;
// Don't close popup so user can retry
}
// Enhanced close method
closePopup() {
this.showPopup = false;
this.isLoading = false;
this.showError = false;
}
// Enhanced close method
closePopup() {
this.showPopup = false;
this.isLoading = false;
this.showError = false;
}
// Retry method for error state
retryGeneration() {
this.showError = false;
this.generateJsonWithLoading();
}
// Retry method for error state
retryGeneration() {
this.showError = false;
this.generateJsonWithLoading();
}
convertJson() {
try {
const parsed = JSON.parse(this.inputJson);
@ -645,6 +646,7 @@ retryGeneration() {
alert('Model data is not valid JSON format');
}
} else {
this.openPopup();
console.warn('⚠️ Model key not found or empty, keeping inputJson as is.');
}
},

View File

@ -1 +1,34 @@
<p>wire-frame-edit works!</p>
<div class="wireframe-container">
<!-- GrapesJS Editor + Sidebar -->
<div class="app-container" *ngIf="currentPageHtml">
<div class="canvas-container">
<div #gjsContainer class="page-canvas"></div>
</div>
</div>
<!-- No content message -->
<div class="no-content" *ngIf="!currentPageHtml">
<p *ngIf="totalPages === 0">No HTML pages found in localStorage.</p>
<p *ngIf="totalPages > 0 && !currentPageHtml">Current page has no HTML content.</p>
</div>
<!-- Sticky Navigation buttons at bottom center -->
<div class="sticky-navigation" *ngIf="totalPages > 1">
<button
class="nav-btn prev-btn"
[disabled]="!hasPrevPage()"
(click)="prevPage()">
← Previous
</button>
<span class="page-indicator">
{{ getCurrentPageNumber() }} / {{ totalPages }}
</span>
<button
class="nav-btn next-btn"
[disabled]="!hasNextPage()"
(click)="nextPage()">
Next →
</button>
</div>
</div>

View File

@ -0,0 +1,161 @@
// Hide GrapesJS outlines/highlights - IMPORTANT: This must be global
:host ::ng-deep .gjs-dashed *[data-gjs-highlightable] {
display: none !important;
}
:host ::ng-deep .gjs-cv-canvas {
.gjs-dashed *[data-gjs-highlightable] {
display: none !important;
}
// Hide any other GrapesJS visual indicators
.gjs-hovered,
.gjs-selected {
outline: none !important;
border: none !important;
}
}
.wireframe-container {
padding: 0;
margin: 0;
width: 100%;
height: 100vh;
position: relative;
.app-container {
display: flex;
height: 100vh;
width: 100%;
.canvas-container {
flex: 1;
height: 100%;
overflow: hidden;
.page-canvas {
width: 100%;
height: 100%;
}
}
}
.no-content {
display: flex;
align-items: center;
justify-content: center;
height: 100vh;
background-color: #f9f9f9;
color: #666;
p {
font-size: 18px;
margin: 0;
}
}
.page-list {
position: fixed;
top: 20px;
right: 20px;
background: rgba(255, 255, 255, 0.95);
padding: 15px;
border-radius: 8px;
box-shadow: 0 2px 10px rgba(0, 0, 0, 0.1);
backdrop-filter: blur(10px);
z-index: 999;
h4 {
margin: 0 0 10px 0;
font-size: 14px;
color: #333;
}
.page-buttons {
display: flex;
flex-direction: column;
gap: 5px;
.page-btn {
padding: 8px 12px;
border: 1px solid #ddd;
background: white;
cursor: pointer;
font-size: 12px;
border-radius: 4px;
transition: all 0.2s ease;
&:hover {
background: #f8f9fa;
}
&.active {
background: #007bff;
color: white;
border-color: #007bff;
}
}
}
}
// Sticky navigation at bottom center
.sticky-navigation {
position: fixed;
bottom: 20px;
left: 50%;
transform: translateX(-50%);
display: flex;
justify-content: center;
align-items: center;
gap: 20px;
background-color: rgba(255, 255, 255, 0.95);
padding: 15px 25px;
border-radius: 50px;
box-shadow: 0 4px 20px rgba(0, 0, 0, 0.15);
backdrop-filter: blur(10px);
border: 1px solid rgba(255, 255, 255, 0.2);
z-index: 1000;
.nav-btn {
padding: 10px 20px;
border: none;
border-radius: 25px;
background-color: #2196F3;
color: white;
cursor: pointer;
font-size: 14px;
font-weight: 500;
transition: all 0.3s ease;
&:hover:not(:disabled) {
background-color: #1976D2;
transform: translateY(-2px);
}
&:disabled {
background-color: #cccccc;
cursor: not-allowed;
transform: none;
}
&.prev-btn {
background-color: #FF9800;
&:hover:not(:disabled) {
background-color: #F57C00;
}
}
}
.page-indicator {
padding: 8px 16px;
background-color: rgba(33, 150, 243, 0.1);
border-radius: 20px;
font-weight: bold;
color: #333;
border: 2px solid #2196F3;
font-size: 14px;
}
}
}

View File

@ -1,10 +1,142 @@
import { Component } from '@angular/core';
import { Component, OnInit, ViewChild, ElementRef, OnDestroy } from '@angular/core';
import grapesjs from 'grapesjs';
import presetWebpage from 'grapesjs-preset-webpage';
const editor = grapesjs.init({
container: '#editor',
plugins: [presetWebpage],
});
import { COMMON_CSS } from './common-css';
@Component({
selector: 'app-wire-frame-edit',
templateUrl: './wire-frame-edit.component.html',
styleUrls: ['./wire-frame-edit.component.scss']
styleUrls: ['./wire-frame-edit.component.scss'] // use your CSS here
})
export class WireFrameEditComponent {
export class WireFrameEditComponent implements OnInit, OnDestroy {
@ViewChild('gjsContainer', { static: false }) gjsContainer!: ElementRef<HTMLDivElement>;
mapOfAllHtmlPages: { [key: string]: string } = {};
pageKeys: string[] = [];
currentPageIndex: number = 0;
currentPageName: string = '';
currentPageHtml: string = '';
totalPages: number = 0;
sidebarOpen = true;
private editor: any = null;
ngOnInit(): void {
this.mapOfAllHtmlPages = JSON.parse(localStorage.getItem('mapOfHtml') || '{}');
this.pageKeys = Object.keys(this.mapOfAllHtmlPages);
this.totalPages = this.pageKeys.length;
if (this.totalPages > 0) {
this.loadPage(0);
}
}
ngAfterViewInit() {
// Initialize GrapesJS after view is ready
if (this.gjsContainer && this.currentPageHtml) {
this.initGrapesJs();
}
}
ngOnDestroy() {
this.editor?.destroy();
}
loadPage(index: number): void {
if (index >= 0 && index < this.totalPages) {
this.currentPageIndex = index;
this.currentPageName = this.pageKeys[index];
this.currentPageHtml = this.mapOfAllHtmlPages[this.currentPageName];
// If GrapesJS already initialized, update its content
if (this.editor) {
this.editor.setComponents(this.currentPageHtml, { keepScripts: true });
}
}
}
nextPage(): void {
if (this.currentPageIndex < this.totalPages - 1) {
this.loadPage(this.currentPageIndex + 1);
}
}
prevPage(): void {
if (this.currentPageIndex > 0) {
this.loadPage(this.currentPageIndex - 1);
}
}
hasNextPage(): boolean {
return this.currentPageIndex < this.totalPages - 1;
}
hasPrevPage(): boolean {
return this.currentPageIndex > 0;
}
getCurrentPageNumber(): number {
return this.currentPageIndex + 1;
}
toggleSidebar() {
this.sidebarOpen = !this.sidebarOpen;
}
downloadHtml() {
const blob = new Blob([this.currentPageHtml], { type: 'text/html' });
const a = document.createElement('a');
a.href = URL.createObjectURL(blob);
a.download = `${this.currentPageName || 'exported-page'}.html`;
a.click();
URL.revokeObjectURL(a.href);
}
private initGrapesJs() {
// If already initialized, destroy and re-init
if (this.editor) {
this.editor.destroy();
}
this.editor = grapesjs.init({
container: this.gjsContainer.nativeElement,
fromElement: false,
storageManager: false,
plugins: ['gjs-preset-webpage'],
allowScripts: 1,
} as any);
this.editor.setComponents(this.currentPageHtml, { keepScripts: true });
this.editor.on('component:update', this.updateCurrentPageHtml.bind(this));
this.editor.on('style:change', this.updateCurrentPageHtml.bind(this));
}
private updateCurrentPageHtml() {
if (!this.editor) return;
const html = this.editor.getHtml();
const css = this.editor.getCss();
this.currentPageHtml = `
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>${this.currentPageName}</title>
<style>${css }</style>
<style>${COMMON_CSS }</style>
</head>
<body>
${html}
</body>
</html>
`;
// Optionally, update your map and localStorage here if you want autosave
// this.mapOfAllHtmlPages[this.currentPageName] = this.currentPageHtml;
// localStorage.setItem('mapOfHtml', JSON.stringify(this.mapOfAllHtmlPages));
}
}

View File

@ -101,6 +101,7 @@ import { EditstepperComponent } from './BuilderComponents/vpspack/Visa_applicati
import { Design_lbraryComponent } from './fnd/SiteTreeBuilder/Design_lbrary/Design_lbrary.component';
import { Dlf_headerComponent } from './fnd/SiteTreeBuilder/Dlf_header/Dlf_header.component';
import { WireFrameEditComponent } from './fnd/SiteTreeBuilder/wire-frame-edit/wire-frame-edit.component';
import { TagComponent } from './fnd/SiteTreeBuilder/Tag/Tag.component';
@ -272,10 +273,14 @@ const routes: Routes = [
// buildercomponents
{ path: 'Tag', component: TagComponent },
{ path: 'Dlf_header', component: Dlf_headerComponent },
// { path: 'Design_lbrary', component: Design_lbraryComponent },
{ path: 'Design_lbrary/:id', component: Design_lbraryComponent },
{ path: 'WireFrameEdit', component: WireFrameEditComponent },
{ path: 'sitetree', component: SiteTreeComponent, },

View File

@ -129,6 +129,7 @@ import { Design_lbraryComponent } from './fnd/SiteTreeBuilder/Design_lbrary/Desi
import { Dlf_headerComponent } from './fnd/SiteTreeBuilder/Dlf_header/Dlf_header.component';
import { EditstepperTfComponent } from './fnd/Visa_application/VisaOrderWorkflow/editstepperTf.component';
import { WireFrameEditComponent } from './fnd/SiteTreeBuilder/wire-frame-edit/wire-frame-edit.component';
import { TagComponent } from './fnd/SiteTreeBuilder/Tag/Tag.component';
@NgModule({
@ -152,6 +153,8 @@ import { WireFrameEditComponent } from './fnd/SiteTreeBuilder/wire-frame-edit/wi
// buildercomponents
WireFrameEditComponent,
TagComponent,
EditstepperTfComponent,
Dlf_headerComponent,
Design_lbraryComponent,