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
bcf94449
Commit
bcf94449
authored
Aug 31, 2025
by
Ooh-Ao
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
ปรับวิดเจ็ท
parent
cce1d45e
Hide whitespace changes
Inline
Side-by-side
Showing
6 changed files
with
121 additions
and
99 deletions
+121
-99
kpi-widget.component.html
src/app/DPU/widgets/kpi-widget/kpi-widget.component.html
+17
-3
kpi-widget.component.ts
src/app/DPU/widgets/kpi-widget/kpi-widget.component.ts
+34
-19
quick-links-widget.component.html
...gets/quick-links-widget/quick-links-widget.component.html
+19
-2
quick-links-widget.component.ts
...idgets/quick-links-widget/quick-links-widget.component.ts
+21
-40
welcome-widget.component.html
.../DPU/widgets/welcome-widget/welcome-widget.component.html
+15
-1
welcome-widget.component.ts
...pp/DPU/widgets/welcome-widget/welcome-widget.component.ts
+15
-34
No files found.
src/app/DPU/widgets/kpi-widget/kpi-widget.component.html
View file @
bcf94449
<div
class=
"p-4 bg-white rounded-lg shadow-md h-full flex flex-col justify-between"
>
<div>
<h5
class=
"text-lg font-semibold text-gray-600 mb-2"
>
{{ kpiName }}
</h5>
<!-- Loading State -->
<div
*
ngIf=
"isLoading"
class=
"flex justify-center items-center h-full"
>
<div
class=
"animate-spin rounded-full h-16 w-16 border-t-2 border-b-2 border-blue-500"
></div>
</div>
<!-- Error State -->
<div
*
ngIf=
"hasError"
class=
"flex flex-col justify-center items-center h-full text-red-500"
>
<i
class=
"bi bi-exclamation-triangle-fill text-4xl"
></i>
<p
class=
"mt-2"
>
{{ errorMessage }}
</p>
</div>
<!-- Content -->
<div
*
ngIf=
"!isLoading && !hasError"
>
<h5
class=
"text-lg font-semibold text-gray-600 mb-2"
>
{{ title }}
</h5>
<div
class=
"text-4xl font-bold text-gray-800"
>
{{ kpiData.value }}
<span
*
ngIf=
"kpiData.unit"
class=
"text-2xl ml-1"
>
{{ kpiData.unit }}
</span>
</div>
...
...
@@ -18,4 +31,5 @@
</span>
</div>
</div>
</div>
</div>
src/app/DPU/widgets/kpi-widget/kpi-widget.component.ts
View file @
bcf94449
import
{
Component
,
Input
,
OnInit
,
OnChanges
,
SimpleChanges
}
from
'@angular/core'
;
import
{
Component
}
from
'@angular/core'
;
import
{
CommonModule
}
from
'@angular/common'
;
import
{
HttpClient
,
HttpClientModule
}
from
'@angular/common/http'
;
import
{
DatasetService
}
from
'../../services/dataset.service'
;
import
{
DatasetModel
}
from
'../../models/widgets.model'
;
import
{
MockDataService
}
from
'../../common/mock-data.service'
;
import
{
DashboardStateService
}
from
'../../services/dashboard-state.service'
;
import
{
BaseWidgetComponent
}
from
'../base-widget.component'
;
@
Component
({
selector
:
'app-kpi-widget'
,
standalone
:
true
,
imports
:
[
CommonModule
,
HttpClientModule
],
providers
:
[
DatasetService
,
HttpClient
,
MockDataService
],
imports
:
[
CommonModule
],
templateUrl
:
'./kpi-widget.component.html'
,
})
export
class
KpiWidgetComponent
implements
OnInit
,
OnChanges
{
@
Input
()
kpiName
:
string
=
'New Hires'
;
// Default KPI
@
Input
()
config
:
any
;
export
class
KpiWidgetComponent
extends
BaseWidgetComponent
{
public
kpiData
:
any
=
{
value
:
0
,
trend
:
'neutral'
,
trendValue
:
''
};
// kpiData!: { value: number, trend: 'up' | 'down' | 'flat', percentage: number, unit: string, trendValue: string };
kpiData
:
any
constructor
(
private
mockDataService
:
MockDataService
)
{
}
ngOnInit
():
void
{
this
.
kpiData
=
this
.
mockDataService
.
getKpiData
(
this
.
kpiName
);
constructor
(
protected
override
dashboardStateService
:
DashboardStateService
)
{
super
(
dashboardStateService
);
}
ngOnChanges
(
changes
:
SimpleChanges
):
void
{
if
(
changes
[
'kpiName'
])
{
this
.
kpiData
=
this
.
mockDataService
.
getKpiData
(
this
.
kpiName
);
onDataUpdate
(
data
:
any
[]):
void
{
if
(
data
.
length
>
0
)
{
let
kpiValue
=
0
;
if
(
this
.
config
.
aggregation
===
'count'
)
{
kpiValue
=
data
.
length
;
}
else
if
(
this
.
config
.
aggregation
===
'sum'
)
{
kpiValue
=
data
.
reduce
((
sum
,
item
)
=>
sum
+
(
item
[
this
.
config
.
valueField
]
||
0
),
0
);
}
else
{
kpiValue
=
data
[
0
][
this
.
config
.
valueField
];
}
this
.
kpiData
=
{
value
:
kpiValue
.
toLocaleString
(),
unit
:
this
.
config
.
unit
||
''
,
trend
:
this
.
config
.
trend
||
'neutral'
,
trendValue
:
this
.
config
.
trendValue
||
''
};
}
}
onReset
():
void
{
this
.
title
=
'KPI (Default)'
;
this
.
kpiData
=
{
value
:
'12,345'
,
unit
:
'#'
,
trend
:
'up'
,
trendValue
:
'+5%'
};
}
}
src/app/DPU/widgets/quick-links-widget/quick-links-widget.component.html
View file @
bcf94449
<div
class=
"card h-100"
>
<div
class=
"card-header"
>
<h5
class=
"card-title"
>
Quick Links
</h5>
<h5
class=
"card-title"
>
{{ title }}
</h5>
</div>
<div
class=
"card-body"
>
<ul>
<!-- Loading State -->
<div
*
ngIf=
"isLoading"
class=
"flex justify-center items-center h-full"
>
<div
class=
"animate-spin rounded-full h-16 w-16 border-t-2 border-b-2 border-blue-500"
></div>
</div>
<!-- Error State -->
<div
*
ngIf=
"hasError"
class=
"flex flex-col justify-center items-center h-full text-red-500"
>
<i
class=
"bi bi-exclamation-triangle-fill text-4xl"
></i>
<p
class=
"mt-2"
>
{{ errorMessage }}
</p>
</div>
<!-- Content -->
<ul
*
ngIf=
"!isLoading && !hasError"
>
<li
*
ngFor=
"let link of quickLinks"
>
<a
[
href
]="
link
.
url
"
target=
"_blank"
class=
"text-blue-500 hover:underline"
>
{{ link.name }}
</a>
</li>
<li
*
ngIf=
"quickLinks.length === 0"
>
<span
class=
"text-gray-500"
>
No links available.
</span>
</li>
</ul>
</div>
</div>
src/app/DPU/widgets/quick-links-widget/quick-links-widget.component.ts
View file @
bcf94449
import
{
Component
,
Input
,
OnInit
,
OnChanges
,
SimpleChanges
}
from
'@angular/core'
;
import
{
Component
}
from
'@angular/core'
;
import
{
CommonModule
}
from
'@angular/common'
;
import
{
MockDataService
}
from
'../../common/mock-data.service'
;
import
{
DatasetService
}
from
'../../services/dataset.service'
;
import
{
HttpClient
,
HttpClientModule
}
from
'@angular/common/http'
;
import
{
DatasetModel
}
from
'../../models/widgets.model'
;
import
{
DashboardStateService
}
from
'../../services/dashboard-state.service'
;
import
{
BaseWidgetComponent
}
from
'../base-widget.component'
;
@
Component
({
selector
:
'app-quick-links-widget'
,
standalone
:
true
,
imports
:
[
CommonModule
,
HttpClientModule
],
providers
:
[
DatasetService
,
HttpClient
],
imports
:
[
CommonModule
],
templateUrl
:
'./quick-links-widget.component.html'
,
})
export
class
QuickLinksWidgetComponent
implements
OnInit
,
OnChanges
{
@
Input
()
links
:
{
name
:
string
,
url
:
string
}[]
|
undefined
;
// New input for links
@
Input
()
config
:
any
;
quickLinks
:
{
name
:
string
,
url
:
string
}[]
=
[];
export
class
QuickLinksWidgetComponent
extends
BaseWidgetComponent
{
public
quickLinks
:
{
name
:
string
,
url
:
string
}[]
=
[];
constructor
(
private
datasetService
:
DatasetService
,
private
http
:
HttpClient
)
{
}
ngOnInit
():
void
{
if
(
!
this
.
config
||
!
this
.
config
.
datasetId
)
{
this
.
quickLinks
=
[
{
name
:
'Google'
,
url
:
'https://www.google.com'
},
{
name
:
'Angular'
,
url
:
'https://angular.io'
},
];
}
constructor
(
protected
override
dashboardStateService
:
DashboardStateService
)
{
super
(
dashboardStateService
);
}
ngOnChanges
(
changes
:
SimpleChanges
):
void
{
if
(
changes
[
'config'
]
&&
this
.
config
&&
this
.
config
.
datasetId
)
{
this
.
loadData
();
}
else
if
(
changes
[
'config'
]
&&
(
!
this
.
config
||
!
this
.
config
.
datasetId
))
{
this
.
quickLinks
=
[
{
name
:
'Google'
,
url
:
'https://www.google.com'
},
{
name
:
'Angular'
,
url
:
'https://angular.io'
},
];
onDataUpdate
(
data
:
any
[]):
void
{
if
(
this
.
config
.
nameField
&&
this
.
config
.
urlField
)
{
this
.
quickLinks
=
data
.
map
(
item
=>
({
name
:
item
[
this
.
config
.
nameField
],
url
:
item
[
this
.
config
.
urlField
]
}));
}
}
loadData
():
void
{
if
(
this
.
config
.
datasetId
)
{
this
.
datasetService
.
getDatasetById
(
this
.
config
.
datasetId
).
subscribe
((
dataset
:
DatasetModel
|
undefined
)
=>
{
if
(
dataset
&&
dataset
.
url
)
{
this
.
http
.
get
<
any
[]
>
(
dataset
.
url
).
subscribe
(
data
=>
{
if
(
this
.
config
.
nameField
&&
this
.
config
.
urlField
)
{
this
.
quickLinks
=
data
.
map
(
item
=>
({
name
:
item
[
this
.
config
.
nameField
],
url
:
item
[
this
.
config
.
urlField
]
}));
}
});
}
});
}
onReset
():
void
{
this
.
title
=
'Quick Links (Default)'
;
this
.
quickLinks
=
[
{
name
:
'Google'
,
url
:
'https://www.google.com'
},
{
name
:
'Angular'
,
url
:
'https://angular.io'
},
{
name
:
'Syncfusion'
,
url
:
'https://www.syncfusion.com'
},
];
}
}
src/app/DPU/widgets/welcome-widget/welcome-widget.component.html
View file @
bcf94449
<div
class=
"card h-100"
>
<div
class=
"card-body flex flex-col justify-center items-center"
>
<h3
class=
"text-2xl font-bold text-gray-800"
>
{{ welcomeMessage }}
</h3>
<!-- Loading State -->
<div
*
ngIf=
"isLoading"
class=
"flex justify-center items-center h-full"
>
<div
class=
"animate-spin rounded-full h-16 w-16 border-t-2 border-b-2 border-blue-500"
></div>
</div>
<!-- Error State -->
<div
*
ngIf=
"hasError"
class=
"flex flex-col justify-center items-center h-full text-red-500"
>
<i
class=
"bi bi-exclamation-triangle-fill text-4xl"
></i>
<p
class=
"mt-2"
>
{{ errorMessage }}
</p>
</div>
<!-- Content -->
<h3
*
ngIf=
"!isLoading && !hasError"
class=
"text-2xl font-bold text-gray-800"
>
{{ welcomeMessage }}
</h3>
</div>
</div>
src/app/DPU/widgets/welcome-widget/welcome-widget.component.ts
View file @
bcf94449
import
{
Component
,
Input
,
OnInit
,
SimpleChanges
}
from
'@angular/core'
;
import
{
Component
}
from
'@angular/core'
;
import
{
CommonModule
}
from
'@angular/common'
;
import
{
MockDataService
}
from
'../../common/mock-data.service'
;
import
{
DatasetService
}
from
'../../services/dataset.service'
;
import
{
HttpClient
}
from
'@angular/common/http'
;
import
{
DatasetModel
}
from
'../../models/widgets.model'
;
import
{
DashboardStateService
}
from
'../../services/dashboard-state.service'
;
import
{
BaseWidgetComponent
}
from
'../base-widget.component'
;
@
Component
({
selector
:
'app-welcome-widget'
,
...
...
@@ -11,40 +9,23 @@ import { DatasetModel } from '../../models/widgets.model';
imports
:
[
CommonModule
],
templateUrl
:
'./welcome-widget.component.html'
,
})
export
class
WelcomeWidgetComponent
implements
OnInit
{
@
Input
()
config
:
any
;
@
Input
()
userName
:
string
=
'Admin'
;
// New input property
welcomeMessage
:
string
=
''
;
export
class
WelcomeWidgetComponent
extends
BaseWidgetComponent
{
public
welcomeMessage
:
string
=
''
;
constructor
(
private
datasetService
:
DatasetService
,
private
http
:
HttpClient
)
{
}
ngOnInit
():
void
{
if
(
!
this
.
config
||
!
this
.
config
.
datasetId
)
{
this
.
welcomeMessage
=
'Welcome, Admin!'
;
}
constructor
(
protected
override
dashboardStateService
:
DashboardStateService
)
{
super
(
dashboardStateService
);
}
ngOnChanges
(
changes
:
SimpleChanges
):
void
{
if
(
changes
[
'config'
]
&&
this
.
config
&&
this
.
config
.
datasetI
d
)
{
this
.
loadData
()
;
}
else
if
(
changes
[
'config'
]
&&
(
!
this
.
config
||
!
this
.
config
.
datasetId
))
{
this
.
welcomeMessage
=
'Welcome, Admin!'
;
onDataUpdate
(
data
:
any
[]
):
void
{
if
(
data
.
length
>
0
&&
this
.
config
.
messageFiel
d
)
{
this
.
welcomeMessage
=
data
[
0
][
this
.
config
.
messageField
]
;
}
else
{
this
.
onReset
()
;
}
}
loadData
():
void
{
if
(
this
.
config
.
datasetId
)
{
this
.
datasetService
.
getDatasetById
(
this
.
config
.
datasetId
).
subscribe
((
dataset
:
DatasetModel
|
undefined
)
=>
{
if
(
dataset
&&
dataset
.
url
)
{
this
.
http
.
get
<
any
[]
>
(
dataset
.
url
).
subscribe
(
data
=>
{
if
(
data
.
length
>
0
&&
this
.
config
.
messageField
)
{
this
.
welcomeMessage
=
data
[
0
][
this
.
config
.
messageField
];
}
else
{
this
.
welcomeMessage
=
'Welcome, Admin!'
;
}
});
}
});
}
onReset
():
void
{
this
.
title
=
''
;
// Welcome widget might not need a title
this
.
welcomeMessage
=
'Welcome, Admin!'
;
}
}
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