Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
63 commits
Select commit Hold shift + click to select a range
e403de3
ITC-3742 Repalce hardcoded 'idoit' and 'itop' with ExternalSystems Enum
nook24 Mar 19, 2026
a7fa0c1
ITC-3742 Repalce hardcoded 'idoit' and 'itop' with ExternalSystems Enum
nook24 Mar 19, 2026
c4df5a4
ITC-3742 Add Proxmox to external systems add list
nook24 Mar 23, 2026
6855b6b
Merge branch 'development' of https://github.com/openITCOCKPIT/openIT…
nook24 Mar 24, 2026
cd174ce
ITC-3742 Add Proxmox VE to import module
nook24 Mar 26, 2026
cc49ce6
ITC-3742 fix VM Status
nook24 Mar 26, 2026
225a0ec
ITC-3742 Import Module: Proxmox VE as data source (filter external sy…
ibering Mar 26, 2026
2341308
ITC-3742 Add classes to make svg images glow and update proxmox statu…
nook24 Mar 26, 2026
e928290
ITC-3742 Add Agent result
nook24 Mar 26, 2026
ed51751
ITC-3742 Store nodename and vmid
nook24 Mar 26, 2026
2aaad91
ITC-3742 Import Module: Proxmox VE as data source (view info cards ad…
ibering Mar 26, 2026
1023946
Merge branch 'ITC-3742' of https://github.com/openITCOCKPIT/openITCOC…
ibering Mar 26, 2026
f0727a6
ITC-3742 Add VM Actions
nook24 Mar 26, 2026
6c68dec
Merge
nook24 Mar 26, 2026
e7e2b41
ITC-3742 Import Module: Proxmox VE as data source (view info cards ad…
ibering Mar 26, 2026
06023e7
ITC-3742 Import Module: Proxmox VE as data source (merged conflicts)
ibering Mar 26, 2026
370b0be
ITC-3742 It's mswindows also add AlmaLinux and Debian examples to int…
nook24 Mar 26, 2026
fc26a22
ITC-3742 Add byte-to-human pipe
nook24 Mar 26, 2026
3ffa2cd
ITC-3742 Import Module: Proxmox VE as data source (show network infor…
ibering Mar 26, 2026
a285bbb
ITC-3742 Import Module: Proxmox VE as data source show network inform…
ibering Mar 26, 2026
c16a476
ITC-3742 implement VM actions
nook24 Mar 26, 2026
f2e7a53
Merge branch 'development' of https://github.com/openITCOCKPIT/openIT…
ibering Mar 27, 2026
0af162b
Merge branch 'development' of https://github.com/openITCOCKPIT/openIT…
nook24 Mar 27, 2026
a4c6d8a
ITC-3742 Add loader and confirm help text
nook24 Mar 27, 2026
9319f17
Merge branch 'ITC-3742' of https://github.com/openITCOCKPIT/openITCOC…
ibering Mar 27, 2026
147e145
ITC-3742 Implement auto reload and cancel old running HTTP requests i…
nook24 Mar 27, 2026
deedb1f
ITC-3742 Import Module: Proxmox VE as data source show network inform…
ibering Mar 27, 2026
e909dfa
ITC-3742 Import Module: Proxmox VE as data source show network inform…
ibering Mar 27, 2026
a640676
ITC-3742 Implement API endpoint to load graph data from Proxmox
nook24 Mar 27, 2026
7df07db
Merge branch 'ITC-3742' of https://github.com/openITCOCKPIT/openITCOC…
nook24 Mar 27, 2026
ba13487
ITC-3742 Add Proxmox Graph Component
nook24 Mar 27, 2026
1d725ef
ITC-3742 Import Module: Proxmox VE as data source show metrics as cha…
ibering Mar 27, 2026
4fcfbda
ITC-3742 Fix data types
nook24 Mar 30, 2026
7607d9c
ITC-3742 Add units and series name to tooltip
nook24 Mar 30, 2026
ff6c12c
ITC-3742 Import Module: Proxmox VE as data source show metrics as cha…
ibering Mar 30, 2026
f0c9b15
Merge branch 'ITC-3742' of https://github.com/openITCOCKPIT/openITCOC…
ibering Mar 30, 2026
8efcde6
ITC-3742 Import Module: Proxmox VE as data source show metrics as cha…
ibering Mar 30, 2026
27c971a
ITC-3742 Import Module: Proxmox VE as data source show metrics as cha…
ibering Mar 30, 2026
25e3ff8
ITC-3742 Import Module: Proxmox VE as data source show metrics as cha…
ibering Mar 30, 2026
a90f7d3
ITC-3742 Add new global confirm modal
nook24 Mar 30, 2026
643bced
Merge branch 'ITC-3742' of https://github.com/openITCOCKPIT/openITCOC…
nook24 Mar 30, 2026
7f1b6ca
ITC-3742 Import Module: Proxmox VE as data source (check connect stat…
ibering Mar 31, 2026
add1a07
ITC-3742 Import Module: Proxmox VE as data source (new image added)
ibering Mar 31, 2026
fcbc2a2
ITC-3742 Implement creation, rollback and deletion of qemu snapshots
nook24 Mar 31, 2026
5df13d5
Merge
nook24 Mar 31, 2026
14c6fe4
ITC-3742 Import Module: Proxmox VE as data source (UserTime: formated…
ibering Mar 31, 2026
b7e7f0c
Merge branch 'ITC-3742' of https://github.com/openITCOCKPIT/openITCOC…
ibering Mar 31, 2026
4107f12
ITC-3742 Import Module: Proxmox VE as data source show metrics as cha…
ibering Mar 31, 2026
80577a3
ITC-3742 Import Module: Proxmox VE as data source show metrics as cha…
ibering Mar 31, 2026
98a9bcc
ITC-3742 Remove all fields we do not use in the response to make the …
nook24 Mar 31, 2026
6db4919
Merge branch 'ITC-3742' of https://github.com/openITCOCKPIT/openITCOC…
nook24 Mar 31, 2026
6d59a09
ITC-3742 Import Module: Proxmox VE as data source show metrics as cha…
ibering Mar 31, 2026
ed14465
Merge branch 'ITC-3742' of https://github.com/openITCOCKPIT/openITCOC…
ibering Mar 31, 2026
244b5ad
ITC-3742 Import Module: Proxmox VE as data source show metrics as cha…
ibering Mar 31, 2026
0c689a1
ITC-3742 Add support for LXC Containers
nook24 Mar 31, 2026
aec9bfd
Merge branch 'ITC-3742' of https://github.com/openITCOCKPIT/openITCOC…
nook24 Mar 31, 2026
92d2c48
ITC-3742 Import Module: Proxmox VE as data source show metrics as cha…
ibering Apr 1, 2026
deddf7e
ITC-3742 Add external link
nook24 Apr 1, 2026
42a850c
ITC-3742 Import Module: Proxmox VE as data source show metrics as cha…
ibering Apr 1, 2026
5df352b
ITC-3742 Import Module: Proxmox VE as data source (Importers/External…
ibering Apr 1, 2026
a8e4281
ITC-3742 Import Module: Proxmox VE as data source (ExternalSystems/ad…
ibering Apr 1, 2026
9893621
ITC-3742 Import Module: Proxmox VE as data source (save polling inter…
ibering Apr 2, 2026
0e36528
ITC-3742 Import Module: Proxmox VE as data source (check connect stat…
ibering Apr 7, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions src/app/app.component.html
Original file line number Diff line number Diff line change
Expand Up @@ -44,3 +44,4 @@
<oitc-message-of-the-day-modal [messageOfTheDay]="messageOfTheDay"></oitc-message-of-the-day-modal>
}
</div>
<oitc-confirm-modal></oitc-confirm-modal>
4 changes: 3 additions & 1 deletion src/app/app.component.ts
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ import { SystemnameService } from './services/systemname.service';
import { PermissionsService } from './permissions/permissions.service';
import { TimezoneService } from './services/timezone.service';
import { TranslocoDirective } from '@jsverse/transloco';
import { ConfirmModalComponent } from './layouts/coreui/confirm-modal/confirm-modal.component';

@Component({
selector: 'oitc-root',
Expand All @@ -52,7 +53,8 @@ import { TranslocoDirective } from '@jsverse/transloco';
AsyncPipe,
NgClass,
MessageOfTheDayModalComponent,
TranslocoDirective
TranslocoDirective,
ConfirmModalComponent
],
templateUrl: './app.component.html',
styleUrl: './app.component.css',
Expand Down
Empty file.
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
<div class="px-2">
<div echarts class="w-100"
[style.min-height.vh]="minChartHeight()"
[options]="chartOption"
(chartInit)="onChartInit($event)"></div>
</div>
Empty file.
203 changes: 203 additions & 0 deletions src/app/components/charts/area-echarts/area-echarts.component.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,203 @@
import { ChangeDetectionStrategy, ChangeDetectorRef, Component, effect, inject, input, OnDestroy } from '@angular/core';
import { NgxEchartsDirective, provideEchartsCore } from 'ngx-echarts';
import * as echarts from 'echarts/core';
import { EChartsCoreOption } from 'echarts/core';
import { LineSeriesOption } from 'echarts';
import { Subscription } from 'rxjs';
import { LineChart } from 'echarts/charts';
import { GridComponent, LegendComponent, TitleComponent, ToolboxComponent, TooltipComponent } from 'echarts/components';
import { CanvasRenderer } from 'echarts/renderers';
import { LayoutService } from '../../../layouts/coreui/layout.service';
import { PerformanceData } from '../../popover-graph/popover-graph.interface';

echarts.use([LineChart, ToolboxComponent, GridComponent, LegendComponent, TitleComponent, TooltipComponent, CanvasRenderer]);

@Component({
selector: 'oitc-area-echarts',
imports: [
NgxEchartsDirective
],
providers: [
provideEchartsCore({echarts}),
],
templateUrl: './area-echarts.component.html',
styleUrl: './area-echarts.component.css',
changeDetection: ChangeDetectionStrategy.OnPush
})
export class AreaEchartsComponent implements OnDestroy {

public dataInput = input<PerformanceData[]>([]);
public max = input<number | undefined>(undefined);
public minChartHeight = input<number | undefined>(15); // in vh

// Count this up, to trigger a resize / chart update
public triggerResize = input<number>(0);

public theme: string = '';
public chartOption: EChartsCoreOption = {};
private readonly LayoutService = inject(LayoutService);

private cdr = inject(ChangeDetectorRef);

public echartsInstance: any;

private readonly subscriptions: Subscription = new Subscription();
public triggerUpdate = input<number>(0);

public onChartInit(ec: any): void {
this.echartsInstance = ec;//.setTheme(this.theme);
this.cdr.markForCheck();
}

public ngOnDestroy(): void {
this.subscriptions.unsubscribe();
}

constructor() {
// Subscribe to the color mode changes (drop down menu in header)
this.subscriptions.add(this.LayoutService.theme$.subscribe((theme) => {
//console.log('Change in theme detected', theme);
this.theme = theme;
if (this.dataInput().length > 0) {
this.renderChart(this.dataInput());
}
this.cdr.markForCheck();
}));

effect(() => {
this.renderChart(this.dataInput());
this.cdr.markForCheck();
});
}

private renderChart(perfdata: PerformanceData[]) {
let data: any[] = [];

// Data format for eCharts
// https://stackoverflow.com/a/68461548
// for (let isoTimestamp in gauge.data) {
// data.push([isoTimestamp, gauge.data[isoTimestamp]]);
// }

let series: LineSeriesOption[] = [];
let gradientStart = [
'rgba(59, 130, 246, 0.4)', 'rgba(245, 158, 11, 0.4)'
];

let gradientLineColor = [
'rgba(59, 130, 246, 1)', 'rgba(245, 158, 11, 1)'
];
let contrastColor = getComputedStyle(document.documentElement).getPropertyValue('--cui-medium-emphasis').trim();
let backgroundColor = getComputedStyle(document.documentElement).getPropertyValue('--cui-body-bg').trim();

if (this.theme === 'dark') {
gradientStart = [
'rgba(139, 92, 246, 0.4)', 'rgba(16, 185, 129, 0.4)'
];
gradientLineColor = [
'rgba(139, 92, 246, 1)', 'rgba(16, 185, 129, 1)'
];
}


perfdata.forEach((gauge, index) => {
data[index] = [];
for (let isoTimestamp in gauge.data) {
data[index].push([isoTimestamp, gauge.data[isoTimestamp]]);
}
series.push(
{
data: data[index],
type: 'line',
name: gauge.datasource.name,
symbolSize: 1,
lineStyle: {
width: 2
},
sampling: 'lttb',
//smooth: false,
itemStyle: {
color: gradientLineColor[index]
},
areaStyle: {
color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [
{
offset: 0,
color: gradientStart[index]
},
{
offset: 1,
color: 'transparent'
}
])
},
emphasis: {
focus: 'series'
}
}
);
});


this.chartOption = {
grid: {
top: 10,
left: 0, // Force align left edge
right: 0, // Force align right edge
bottom: 0,
containLabel: false // MUST be false to reproduce the truncation issue
},
tooltip: {
trigger: 'axis',
axisPointer: {
type: 'cross'
},
backgroundColor: backgroundColor,
textStyle: {
color: contrastColor
},
formatter: (params: any) => {
// params is an array when trigger: 'axis'
let result = `${params[0].axisValueLabel}<br/>`; // The header (usually x-axis value)

params.forEach((item: any) => {
const value = (Math.round(item.value[1] * 100) / 100).toFixed(2);
result += `${item.marker} ${item.seriesName}: <b>${value} ${perfdata[0].datasource.unit}</b><br/>`;
});

return result;
}
},

xAxis: {
type: 'time',
splitNumber: 5,
axisLabel: {
fontSize: 9,
color: contrastColor
},
axisLine: {
lineStyle: {
color: contrastColor
}
}
},
yAxis: {
type: 'value',
axisLabel: {
fontSize: 9,
color: contrastColor,
formatter: (value: any) => {
return `${value} ${perfdata[0].datasource.unit}`;
}
},
axisLine: {
lineStyle: {
color: contrastColor
}
}
},
series: series
}
}
}
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
4 changes: 4 additions & 0 deletions src/app/components/charts/charts.interface.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,3 +19,7 @@ export interface SparklineBarMetric {
text: string
}
}

export interface AreaChartMetric {
[key: string]: number
}
Empty file.
43 changes: 43 additions & 0 deletions src/app/layouts/coreui/confirm-modal/confirm-modal.component.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
<ng-container *transloco="let t">
<c-modal
#modal='cModal'
[keyboard]="true"
id="confirmModal"
size="lg"
>
<c-modal-header class="bg-warning">
<h5 cModalTitle>
{{ t('Confirm') }}
</h5>
<button (click)="no()" cButtonClose></button>
</c-modal-header>
<c-modal-body>
<c-row>
@if (this.ConfirmModalService.state().message == '') {
<c-col xs="12">
<strong>{{ t('Do you really want to do this action?') }}</strong>
</c-col>
}
@if (this.ConfirmModalService.state().message) {
<c-col xs="12">
<strong>{{ this.ConfirmModalService.state().message }}</strong>
</c-col>
}
@if (this.ConfirmModalService.state().helpMessage) {
<c-col class="help-block" xs="12">
{{ this.ConfirmModalService.state().helpMessage }}
</c-col>
}
</c-row>

</c-modal-body>
<c-modal-footer>
<button (click)="yes()" cButton class="ripple" color="primary">
{{ t('Yes') }}
</button>
<button (click)="no()" cButton class="ripple" color="default">
{{ t('Cancel') }}
</button>
</c-modal-footer>
</c-modal>
</ng-container>
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
import { ComponentFixture, TestBed } from '@angular/core/testing';

import { ConfirmModalComponent } from './confirm-modal.component';

describe('ConfirmModalComponent', () => {
let component: ConfirmModalComponent;
let fixture: ComponentFixture<ConfirmModalComponent>;

beforeEach(async () => {
await TestBed.configureTestingModule({
imports: [ConfirmModalComponent],
}).compileComponents();

fixture = TestBed.createComponent(ConfirmModalComponent);
component = fixture.componentInstance;
fixture.detectChanges();
});

it('should create', () => {
expect(component).toBeTruthy();
});
});
71 changes: 71 additions & 0 deletions src/app/layouts/coreui/confirm-modal/confirm-modal.component.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
import { ChangeDetectionStrategy, ChangeDetectorRef, Component, inject, ViewChild } from '@angular/core';
import {
ButtonCloseDirective,
ColComponent,
ModalBodyComponent,
ModalComponent,
ModalFooterComponent,
ModalHeaderComponent,
ModalService,
ModalTitleDirective,
RowComponent
} from '@coreui/angular';
import { TranslocoDirective } from '@jsverse/transloco';
import { XsButtonDirective } from '../xsbutton-directive/xsbutton.directive';
import { ConfirmModalService } from './confirm-modal.service';

@Component({
selector: 'oitc-confirm-modal',
imports: [
ModalComponent,
TranslocoDirective,
ModalHeaderComponent,
ModalTitleDirective,
ButtonCloseDirective,
ModalBodyComponent,
XsButtonDirective,
ModalFooterComponent,
ColComponent,
RowComponent
],
templateUrl: './confirm-modal.component.html',
styleUrl: './confirm-modal.component.css',
changeDetection: ChangeDetectionStrategy.OnPush,
})
export class ConfirmModalComponent {

/*
Use the ConfirmModalService Service to trigger this modal! Like so
this.ConfirmModalService.ask(confirmModalMessage, confirmModalHelpMessage, data).subscribe(confirmation => {
console.log(confirmation)
});
*/

public readonly ConfirmModalService = inject(ConfirmModalService);
private readonly modalService = inject(ModalService);
private cdr = inject(ChangeDetectorRef);
@ViewChild('modal') private modal!: ModalComponent;

public constructor() {
}

// Modal functions
public hideModal(): void {
this.cdr.markForCheck();
this.modalService.toggle({
show: false,
id: this.modal.id
});
}

public yes(): void {
this.ConfirmModalService.confirm(true);
this.hideModal();
}

public no(): void {
this.ConfirmModalService.confirm(false);
this.hideModal();
}

}
16 changes: 16 additions & 0 deletions src/app/layouts/coreui/confirm-modal/confirm-modal.service.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
import { TestBed } from '@angular/core/testing';

import { ConfirmModalService } from './confirm-modal.service';

describe('ConfirmModalService', () => {
let service: ConfirmModalService;

beforeEach(() => {
TestBed.configureTestingModule({});
service = TestBed.inject(ConfirmModalService);
});

it('should be created', () => {
expect(service).toBeTruthy();
});
});
Loading