Skip to content
Projects
Groups
Snippets
Help
This project
Loading...
Sign in / Register
Toggle navigation
P
portal-apps-manage
Overview
Overview
Details
Activity
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Registry
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
angular
portal-apps-manage
Commits
5c675edd
Commit
5c675edd
authored
Aug 25, 2025
by
Ooh-Ao
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
aa
parent
090de8bc
Hide whitespace changes
Inline
Side-by-side
Showing
5 changed files
with
124 additions
and
33 deletions
+124
-33
dashboard-management.component.html
.../dashboard-management/dashboard-management.component.html
+1
-1
dashboard-management.component.ts
...PU/dashboard-management/dashboard-management.component.ts
+40
-25
dashboard-viewer.component.ts
src/app/DPU/dashboard-viewer/dashboard-viewer.component.ts
+4
-7
dashboard-data.service.ts
src/app/DPU/services/dashboard-data.service.ts
+60
-0
mock-dashboard.service.ts
src/app/DPU/services/mock-dashboard.service.ts
+19
-0
No files found.
src/app/DPU/dashboard-management/dashboard-management.component.html
View file @
5c675edd
<div
*
ngIf=
"errorMessage$ | async as errorMessage"
class=
"alert alert-danger"
>
{{errorMessage}}
</div>
<div
class=
"flex h-screen bg-gray-50"
>
<!-- Widget Sidebar -->
...
...
src/app/DPU/dashboard-management/dashboard-management.component.ts
View file @
5c675edd
...
...
@@ -5,12 +5,10 @@ import { ActivatedRoute, RouterModule } from '@angular/router';
import
{
CommonModule
,
TitleCasePipe
}
from
'@angular/common'
;
import
{
NgComponentOutlet
}
from
'@angular/common'
;
import
{
FormsModule
}
from
'@angular/forms'
;
import
{
Store
}
from
'@ngrx/store'
;
import
{
Observable
}
from
'rxjs'
;
import
{
Observable
,
of
}
from
'rxjs'
;
import
{
DashboardModel
,
WidgetModel
,
DatasetModel
}
from
'../models/widgets.model'
;
import
*
as
DashboardActions
from
'../state/dashboard.actions'
;
import
*
as
DashboardSelectors
from
'../state/dashboard.selectors'
;
import
{
DashboardDataService
}
from
'../services/dashboard-data.service'
;
// Import all the widget components
import
{
CompanyInfoWidgetComponent
}
from
'../widgets/company-info-widget.component'
;
...
...
@@ -26,7 +24,6 @@ import { SyncfusionDatagridWidgetComponent } from '../widgets/syncfusion-datagri
import
{
SyncfusionPivotWidgetComponent
}
from
'../widgets/syncfusion-pivot-widget/syncfusion-pivot-widget.component'
;
import
{
SyncfusionChartWidgetComponent
}
from
'../widgets/syncfusion-chart-widget/syncfusion-chart-widget.component'
;
import
{
DatasetPickerComponent
}
from
'./dataset-picker.component'
;
import
{
MockDashboardService
}
from
'../services/mock-dashboard.service'
;
@
Component
({
selector
:
'app-dashboard-management'
,
...
...
@@ -44,15 +41,11 @@ export class DashboardManagementComponent implements OnInit {
public
filteredAvailableWidgets
:
WidgetModel
[]
=
[];
public
widgetSearchTerm
:
string
=
''
;
public
dashboardData
:
DashboardModel
;
public
dashboardData
:
DashboardModel
|
null
=
null
;
public
userDashboards
:
DashboardModel
[]
=
[];
public
selectedDashboardId
:
string
=
''
;
public
userDashboards
$
:
Observable
<
DashboardModel
[]
>
;
public
availableWidgets
$
:
Observable
<
WidgetModel
[]
>
;
public
errorMessage
$
:
Observable
<
string
|
null
>
;
private
widgetComponentMap
:
{
[
key
:
string
]:
Type
<
any
>
}
=
{
'CompanyInfoWidgetComponent'
:
CompanyInfoWidgetComponent
,
'HeadcountWidgetComponent'
:
HeadcountWidgetComponent
,
...
...
@@ -69,24 +62,24 @@ export class DashboardManagementComponent implements OnInit {
};
constructor
(
private
store
:
Store
,
private
route
:
ActivatedRoute
,
private
mockDashboardService
:
MockDashboard
Service
private
dashboardDataService
:
DashboardData
Service
)
{
}
ngOnInit
():
void
{
this
.
store
.
dispatch
(
DashboardActions
.
loadDashboards
());
this
.
store
.
dispatch
(
DashboardActions
.
loadWidgets
());
this
.
userDashboards$
=
this
.
store
.
select
(
DashboardSelectors
.
selectAllDashboards
);
this
.
availableWidgets$
=
this
.
store
.
select
(
DashboardSelectors
.
selectAllWidgets
);
this
.
errorMessage$
=
this
.
store
.
select
(
DashboardSelectors
.
selectError
);
this
.
mockDashboardService
.
getDashboards
().
subscribe
(
dashboards
=>
{
this
.
dashboardDataService
.
getDashboards
().
subscribe
(
dashboards
=>
{
this
.
userDashboards
=
dashboards
;
if
(
this
.
userDashboards
.
length
>
0
)
{
this
.
selectedDashboardId
=
this
.
userDashboards
[
0
].
id
;
this
.
loadSelectedDashboard
();
}
});
// Assuming availableWidgets are loaded from a separate service or hardcoded for now
// If they come from an API, DashboardDataService should provide a getWidgets() method
// For now, we'll just use the mock service's getWidgets if it exists, or hardcode them.
// Since MockDashboardService doesn't have getWidgets(), we'll leave availableWidgets empty for now
// or you can populate it with static data if needed for testing the widget sidebar.
this
.
availableWidgets
=
[];
// Or populate with static data if needed
}
...
...
@@ -108,7 +101,7 @@ export class DashboardManagementComponent implements OnInit {
loadSelectedDashboard
():
void
{
if
(
this
.
selectedDashboardId
)
{
this
.
store
.
select
(
DashboardSelectors
.
selectDashboardById
(
this
.
selectedDashboardId
)
).
subscribe
(
dashboard
=>
{
this
.
dashboardDataService
.
getDashboardById
(
this
.
selectedDashboardId
).
subscribe
(
dashboard
=>
{
if
(
dashboard
)
{
this
.
dashboardData
=
dashboard
;
this
.
panels
=
this
.
mapWidgetsToPanels
(
dashboard
.
widgets
||
[]);
...
...
@@ -126,13 +119,17 @@ export class DashboardManagementComponent implements OnInit {
name
:
newDashboardName
,
widgets
:
[]
});
this
.
store
.
dispatch
(
DashboardActions
.
addDashboard
({
dashboard
:
newDashboard
}));
this
.
dashboardDataService
.
addDashboard
(
newDashboard
).
subscribe
(
addedDashboard
=>
{
this
.
userDashboards
.
push
(
addedDashboard
);
this
.
selectedDashboardId
=
addedDashboard
.
id
;
this
.
loadSelectedDashboard
();
});
}
}
saveDashboardName
():
void
{
if
(
this
.
dashboardData
)
{
this
.
store
.
dispatch
(
DashboardActions
.
updateDashboard
({
dashboard
:
this
.
dashboardData
})
);
this
.
dashboardDataService
.
updateDashboard
(
this
.
dashboardData
).
subscribe
(
);
}
}
...
...
@@ -145,17 +142,18 @@ export class DashboardManagementComponent implements OnInit {
row
:
widget
.
y
,
col
:
widget
.
x
,
componentType
:
this
.
widgetComponentMap
[
widget
.
component
],
componentInputs
:
{
...
widget
.
data
,
datasetId
:
this
.
dashboardData
.
datasetId
}
componentInputs
:
{
...
widget
.
data
,
datasetId
:
this
.
dashboardData
?
.
datasetId
}
}));
}
saveLayout
():
void
{
if
(
!
this
.
dashboardData
)
return
;
this
.
store
.
dispatch
(
DashboardActions
.
updateDashboard
({
dashboard
:
this
.
dashboardData
})
);
this
.
dashboardDataService
.
updateDashboard
(
this
.
dashboardData
).
subscribe
(
);
}
addWidgetToDashboard
(
widget
:
WidgetModel
):
void
{
if
(
!
this
.
dashboardData
)
return
;
// Add null check
if
(
this
.
dashboardData
.
widgets
.
find
(
w
=>
w
.
id
===
widget
.
id
))
{
alert
(
'Widget already exists in the dashboard.'
);
return
;
...
...
@@ -166,14 +164,31 @@ export class DashboardManagementComponent implements OnInit {
deleteDashboard
():
void
{
if
(
this
.
selectedDashboardId
&&
confirm
(
'Are you sure you want to delete this dashboard?'
))
{
this
.
store
.
dispatch
(
DashboardActions
.
deleteDashboard
({
id
:
this
.
selectedDashboardId
}));
this
.
dashboardDataService
.
deleteDashboard
(
this
.
selectedDashboardId
).
subscribe
(()
=>
{
// After deletion, reload dashboards and select the first one or clear selection
this
.
dashboardDataService
.
getDashboards
().
subscribe
(
dashboards
=>
{
this
.
userDashboards
=
dashboards
;
if
(
this
.
userDashboards
.
length
>
0
)
{
this
.
selectedDashboardId
=
this
.
userDashboards
[
0
].
id
;
this
.
loadSelectedDashboard
();
}
else
{
this
.
selectedDashboardId
=
''
;
this
.
dashboardData
=
null
;
// Clear dashboard data if no dashboards left
this
.
panels
=
[];
}
});
});
}
}
removeWidgetFromDashboard
(
panelId
:
string
):
void
{
if
(
!
this
.
dashboardData
)
return
;
// Add null check
if
(
confirm
(
'Are you sure you want to remove this widget?'
))
{
const
updatedDashboard
=
{
...
this
.
dashboardData
,
widgets
:
this
.
dashboardData
.
widgets
.
filter
(
w
=>
w
.
id
!==
panelId
)
};
this
.
store
.
dispatch
(
DashboardActions
.
updateDashboard
({
dashboard
:
updatedDashboard
}));
this
.
dashboardDataService
.
updateDashboard
(
updatedDashboard
).
subscribe
(
updated
=>
{
this
.
dashboardData
=
updated
;
this
.
panels
=
this
.
mapWidgetsToPanels
(
this
.
dashboardData
.
widgets
);
});
}
}
...
...
src/app/DPU/dashboard-viewer/dashboard-viewer.component.ts
View file @
5c675edd
...
...
@@ -3,12 +3,10 @@ import { Component, OnInit, Type, ChangeDetectionStrategy } from '@angular/core'
import
{
CommonModule
}
from
'@angular/common'
;
import
{
ActivatedRoute
,
RouterModule
}
from
'@angular/router'
;
import
{
DashboardLayoutModule
,
PanelModel
}
from
'@syncfusion/ej2-angular-layouts'
;
import
{
Store
}
from
'@ngrx/store
'
;
import
{
Observable
,
of
}
from
'rxjs
'
;
import
{
map
,
switchMap
}
from
'rxjs/operators'
;
import
{
of
}
from
'rxjs'
;
import
{
NgComponentOutlet
}
from
'@angular/common'
;
// Import NgComponentOutlet
import
*
as
DashboardActions
from
'../state/dashboard.actions'
;
import
*
as
DashboardSelectors
from
'../state/dashboard.selectors'
;
import
{
DashboardDataService
}
from
'../services/dashboard-data.service'
;
import
{
DashboardModel
}
from
'../models/widgets.model'
;
// Import all the widget components
...
...
@@ -61,7 +59,7 @@ export class DashboardViewerComponent implements OnInit {
constructor
(
private
route
:
ActivatedRoute
,
private
store
:
Stor
e
private
dashboardDataService
:
DashboardDataServic
e
)
{
}
ngOnInit
():
void
{
...
...
@@ -72,8 +70,7 @@ export class DashboardViewerComponent implements OnInit {
console
.
error
(
'Dashboard ID is missing from the route.'
);
return
of
(
null
);
}
this
.
store
.
dispatch
(
DashboardActions
.
loadDashboards
());
return
this
.
store
.
select
(
DashboardSelectors
.
selectDashboardById
(
id
));
return
this
.
dashboardDataService
.
getDashboardById
(
id
);
})
).
subscribe
({
next
:
dashboard
=>
{
...
...
src/app/DPU/services/dashboard-data.service.ts
0 → 100644
View file @
5c675edd
import
{
Injectable
}
from
'@angular/core'
;
import
{
Observable
,
of
}
from
'rxjs'
;
import
{
DashboardModel
,
WidgetModel
}
from
'../models/widgets.model'
;
import
{
MockDashboardService
}
from
'./mock-dashboard.service'
;
@
Injectable
({
providedIn
:
'root'
})
export
class
DashboardDataService
{
constructor
(
private
mockDashboardService
:
MockDashboardService
)
{
}
getDashboards
():
Observable
<
DashboardModel
[]
>
{
// In a real application, this would call an API
return
this
.
mockDashboardService
.
getDashboards
();
}
getDashboardById
(
id
:
string
):
Observable
<
DashboardModel
|
undefined
>
{
// In a real application, this would call an API
return
this
.
mockDashboardService
.
getDashboardById
(
id
);
}
// For now, these methods will operate on the in-memory mock data
// In a real application, these would call API endpoints for CUD operations
addDashboard
(
dashboard
:
DashboardModel
):
Observable
<
DashboardModel
>
{
// Simulate adding to mock data (not persistent across app restarts)
const
currentDashboards
=
this
.
mockDashboardService
.
getDashboards
();
currentDashboards
.
subscribe
(
dashboards
=>
{
dashboards
.
push
(
dashboard
);
});
return
of
(
dashboard
);
}
updateDashboard
(
updatedDashboard
:
DashboardModel
):
Observable
<
DashboardModel
>
{
// Simulate updating mock data (not persistent across app restarts)
const
currentDashboards
=
this
.
mockDashboardService
.
getDashboards
();
currentDashboards
.
subscribe
(
dashboards
=>
{
const
index
=
dashboards
.
findIndex
(
d
=>
d
.
id
===
updatedDashboard
.
id
);
if
(
index
>
-
1
)
{
dashboards
[
index
]
=
updatedDashboard
;
}
});
return
of
(
updatedDashboard
);
}
deleteDashboard
(
id
:
string
):
Observable
<
void
>
{
// Simulate deleting from mock data (not persistent across app restarts)
const
currentDashboards
=
this
.
mockDashboardService
.
getDashboards
();
currentDashboards
.
subscribe
(
dashboards
=>
{
const
index
=
dashboards
.
findIndex
(
d
=>
d
.
id
===
id
);
if
(
index
>
-
1
)
{
dashboards
.
splice
(
index
,
1
);
}
});
return
of
(
undefined
);
}
// Assuming widgets are managed as part of dashboards for now
// If widgets were separate entities, you'd have getWidgets, addWidget, etc.
}
src/app/DPU/services/mock-dashboard.service.ts
View file @
5c675edd
...
...
@@ -20,6 +20,25 @@ export const MOCK_DASHBOARD_DATA: DashboardModel[] = [
{
id
:
'201'
,
name
:
'Website Traffic'
,
component
:
'ChartWidgetComponent'
,
cols
:
2
,
rows
:
1
,
x
:
0
,
y
:
0
,
data
:
{
type
:
'line'
,
labels
:
[
'Week 1'
,
'Week 2'
,
'Week 3'
],
datasets
:
[{
data
:
[
120
,
150
,
130
],
label
:
'Visitors'
}]
}
},
{
id
:
'202'
,
name
:
'Conversion Rate'
,
component
:
'KpiWidgetComponent'
,
cols
:
1
,
rows
:
1
,
x
:
2
,
y
:
0
,
data
:
{
value
:
'2.5%'
,
label
:
'Conversion'
}
}
]
},
{
id
:
'3'
,
name
:
'All Widgets Test Dashboard'
,
description
:
'Dashboard for testing all available widgets.'
,
widgets
:
[
{
id
:
'301'
,
name
:
'Company Info'
,
component
:
'CompanyInfoWidgetComponent'
,
cols
:
2
,
rows
:
1
,
x
:
0
,
y
:
0
,
data
:
{
companyName
:
'Test Company'
,
address
:
'123 Test St.'
}
},
{
id
:
'302'
,
name
:
'Headcount'
,
component
:
'HeadcountWidgetComponent'
,
cols
:
1
,
rows
:
1
,
x
:
2
,
y
:
0
,
data
:
{
count
:
150
}
},
{
id
:
'303'
,
name
:
'Attendance Overview'
,
component
:
'AttendanceOverviewWidgetComponent'
,
cols
:
2
,
rows
:
1
,
x
:
3
,
y
:
0
,
data
:
{
present
:
140
,
absent
:
10
}
},
{
id
:
'304'
,
name
:
'Payroll Summary'
,
component
:
'PayrollSummaryWidgetComponent'
,
cols
:
2
,
rows
:
1
,
x
:
0
,
y
:
1
,
data
:
{
totalPayroll
:
100000
,
currency
:
'USD'
}
},
{
id
:
'305'
,
name
:
'Employee Directory'
,
component
:
'EmployeeDirectoryWidgetComponent'
,
cols
:
2
,
rows
:
2
,
x
:
2
,
y
:
1
,
data
:
{
employees
:
[{
name
:
'Alice'
,
dept
:
'HR'
},
{
name
:
'Bob'
,
dept
:
'IT'
}]
}
},
{
id
:
'306'
,
name
:
'KPI Widget'
,
component
:
'KpiWidgetComponent'
,
cols
:
1
,
rows
:
1
,
x
:
4
,
y
:
1
,
data
:
{
value
:
'95%'
,
label
:
'Success Rate'
}
},
{
id
:
'307'
,
name
:
'Welcome Widget'
,
component
:
'WelcomeWidgetComponent'
,
cols
:
2
,
rows
:
1
,
x
:
0
,
y
:
3
,
data
:
{
message
:
'Welcome to the Dashboard!'
}
},
{
id
:
'308'
,
name
:
'Chart Widget'
,
component
:
'ChartWidgetComponent'
,
cols
:
2
,
rows
:
1
,
x
:
2
,
y
:
3
,
data
:
{
type
:
'bar'
,
labels
:
[
'A'
,
'B'
,
'C'
],
datasets
:
[{
data
:
[
10
,
20
,
30
],
label
:
'Data'
}]
}
},
{
id
:
'309'
,
name
:
'Quick Links'
,
component
:
'QuickLinksWidgetComponent'
,
cols
:
1
,
rows
:
1
,
x
:
4
,
y
:
3
,
data
:
{
links
:
[{
name
:
'Google'
,
url
:
'https://google.com'
}]
}
},
{
id
:
'310'
,
name
:
'Syncfusion Datagrid'
,
component
:
'SyncfusionDatagridWidgetComponent'
,
cols
:
3
,
rows
:
2
,
x
:
0
,
y
:
4
,
data
:
{
columns
:
[
'ID'
,
'Name'
],
data
:
[{
ID
:
1
,
Name
:
'Item 1'
},
{
ID
:
2
,
Name
:
'Item 2'
}]
}
},
{
id
:
'311'
,
name
:
'Syncfusion Pivot'
,
component
:
'SyncfusionPivotWidgetComponent'
,
cols
:
3
,
rows
:
2
,
x
:
3
,
y
:
4
,
data
:
{
data
:
[{
year
:
'2023'
,
sales
:
100
},
{
year
:
'2024'
,
sales
:
120
}],
rows
:
[{
name
:
'year'
}],
columns
:
[{
name
:
'sales'
}]
}
},
{
id
:
'312'
,
name
:
'Syncfusion Chart'
,
component
:
'SyncfusionChartWidgetComponent'
,
cols
:
2
,
rows
:
1
,
x
:
0
,
y
:
6
,
data
:
{
chartData
:
[{
x
:
'Jan'
,
y
:
10
},
{
x
:
'Feb'
,
y
:
20
}],
primaryXAxis
:
{
valueType
:
'Category'
},
series
:
[{
type
:
'Column'
,
xName
:
'x'
,
yName
:
'y'
}]
}
}
]
}
];
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment