diff --git a/projects/cobbler-api/src/lib/cobbler-api.service.spec.ts b/projects/cobbler-api/src/lib/cobbler-api.service.spec.ts index 5bdbed4d..846c6e58 100644 --- a/projects/cobbler-api/src/lib/cobbler-api.service.spec.ts +++ b/projects/cobbler-api/src/lib/cobbler-api.service.spec.ts @@ -1,7 +1,14 @@ import {TestBed} from '@angular/core/testing'; import {HttpClientTestingModule, HttpTestingController} from '@angular/common/http/testing'; -import {BackgroundBuildisoOptions, BackgroundImportOptions, BackgroundReplicateOptions} from 'cobbler-api'; -import {Event, ExtendedVersion, InstallationStatus} from './custom-types/misc'; +import {Distro, File, Image, Mgmgtclass, Package, Profile, Repo, System} from './custom-types/items'; +import { + BackgroundBuildisoOptions, + BackgroundImportOptions, + BackgroundReplicateOptions, + Event, + ExtendedVersion, + InstallationStatus +} from './custom-types/misc'; import {COBBLER_URL} from './lib.config'; import {AngularXmlrpcService} from 'typescript-xmlrpc'; @@ -338,44 +345,398 @@ describe('CobblerApiService', () => { expect(service).toBeFalsy(); }); - xit('should execute the get_distro action on the Cobbler Server', () => { - service.get_distro(''); - expect(service).toBeFalsy(); + it('should execute the get_distro action on the Cobbler Server', (done: DoneFn) => { + // eslint-disable-next-line max-len + const methodResponse = `parentdepth0ctime1721480439.039089mtime1721480439.039089uid12f034d6781946d1af0783e20684cbd4nametestcommentkernel_optionskernel_options_postautoinstall_metafetchable_filesboot_filestemplate_filesowners<<inherit>>mgmt_classesmgmt_parametersis_subobject0tree_build_time0.0archx86_64boot_loaders<<inherit>>breedinitrd/root/initrdkernel/root/kernelos_versionredhat_management_key<<inherit>>source_reposremote_boot_kernelremote_grub_kernelremote_boot_initrdremote_grub_initrdks_meta` + const result: Distro = { + ctime: 1721480439.039089, + depth: 0, + mtime: 1721480439.039089, + uid: "12f034d6781946d1af0783e20684cbd4", + source_repos: [], + tree_build_time: 0, + arch: "x86_64", + autoinstall_meta: {}, + boot_files: {}, + boot_loaders: "<>", + is_subobject: false, + parent: "", + breed: "", + comment: "", + fetchable_files: {}, + initrd: "/root/initrd", + kernel: "/root/kernel", + remote_boot_initrd: "", + remote_boot_kernel: "", + remote_grub_initrd: "", + remote_grub_kernel: "", + kernel_options: {}, + kernel_options_post: {}, + mgmt_classes: [], + mgmt_parameters: {}, + name: "test", + os_version: "", + owners: "<>", + redhat_management_key: "<>", + template_files: {}, + } + service.get_distro('', false, false, "").subscribe(value => { + expect(value).toEqual(result) + done() + }); + const mockRequest = httpTestingController.expectOne('http://localhost/cobbler_api'); + mockRequest.flush(methodResponse); }); - xit('should execute the get_profile action on the Cobbler Server', () => { - service.get_profile(''); - expect(service).toBeFalsy(); + it('should execute the get_profile action on the Cobbler Server', (done: DoneFn) => { + // eslint-disable-next-line max-len + const methodResponse = `parentdepth1ctime1721480439.3090012mtime1721480439.3090012uid5f01667614244fcd9c7ca7fa59c7def1nametestprofcommentkernel_options<<inherit>>kernel_options_post<<inherit>>autoinstall_meta<<inherit>>fetchable_files<<inherit>>boot_files<<inherit>>template_filesowners<<inherit>>mgmt_classes<<inherit>>mgmt_parameters<<inherit>>is_subobject0autoinstall<<inherit>>boot_loaders<<inherit>>dhcp_tagdistrotestenable_ipxe<<inherit>>enable_menu<<inherit>>name_serversname_servers_searchnext_server_v4<<inherit>>next_server_v6<<inherit>>filenameproxy<<inherit>>redhat_management_key<<inherit>>reposserver<<inherit>>menuvirt_auto_boot<<inherit>>virt_bridge<<inherit>>virt_cpus1virt_disk_driverrawvirt_file_size<<inherit>>virt_pathvirt_ram<<inherit>>virt_typexenpvkickstart<<inherit>>ks_meta<<inherit>>` + const result: Profile = { + name: "testprof", + depth: 1, + mtime: 1721480439.3090012, + is_subobject: false, + boot_loaders: "<>", + autoinstall_meta: "<>", + server: "<>", + distro: "test", + comment: "", + next_server_v4: "<>", + next_server_v6: "<>", + enable_ipxe: "<>", + parent: "", + owners: "<>", + autoinstall: "<>", + uid: "5f01667614244fcd9c7ca7fa59c7def1", + virt_ram: "<>", + boot_files: "<>", + mgmt_parameters: "<>", + name_servers: [], + enable_menu: "<>", + menu: "", + ctime: 1721480439.3090012, + fetchable_files: "<>", + mgmt_classes: "<>", + kernel_options: "<>", + virt_auto_boot: "<>", + kernel_options_post: "<>", + proxy: "<>", + filename: "", + dhcp_tag: "", + redhat_management_key: "<>", + repos: [], + template_files: {}, + virt_type: "xenpv", + virt_cpus: 1, + virt_bridge: "<>", + name_servers_search: [], + virt_path: "", + virt_file_size: "<>", + virt_disk_driver: "raw", + } + service.get_profile('', false, false, "").subscribe(value => { + expect(value).toEqual(result) + done() + }); + const mockRequest = httpTestingController.expectOne('http://localhost/cobbler_api'); + mockRequest.flush(methodResponse); }); - xit('should execute the get_system action on the Cobbler Server', () => { - service.get_system(''); - expect(service).toBeFalsy(); + it('should execute the get_system action on the Cobbler Server', (done: DoneFn) => { + // eslint-disable-next-line max-len + const methodResponse = `parentdepth2ctime1721480439.5932038mtime1721480439.5932038uida3320bc9105c44f1b92ab1743d460ed8nametestsyscommentkernel_options<<inherit>>kernel_options_post<<inherit>>autoinstall_meta<<inherit>>fetchable_files<<inherit>>boot_files<<inherit>>template_filesowners<<inherit>>mgmt_classes<<inherit>>mgmt_parameters<<inherit>>is_subobject0interfacesdefaultbonding_optsbridge_optscnamesconnected_mode0dhcp_tagdns_nameif_gatewayinterface_masterinterface_typenaip_addressipv6_addressipv6_default_gatewayipv6_mtuipv6_prefixipv6_secondariesipv6_static_routesmac_addressmanagement0mtunetmaskstatic0static_routesvirt_bridge<<inherit>>ipv6_autoconfiguration0repos_enabled0autoinstall<<inherit>>boot_loaders<<inherit>>enable_ipxe<<inherit>>gatewayhostnameimageipv6_default_devicename_serversname_servers_searchnetboot_enabled0next_server_v4<<inherit>>next_server_v6<<inherit>>filename<<inherit>>power_addresspower_idpower_passpower_typepower_userpower_optionspower_identity_fileprofiletestprofproxy<<inherit>>redhat_management_key<<inherit>>server<<inherit>>statusvirt_auto_boot<<inherit>>virt_cpus<<inherit>>virt_disk_driver<<inherit>>virt_file_size<<inherit>>virt_path<<inherit>>virt_pxe_boot0virt_ram<<inherit>>virt_type<<inherit>>serial_device-1serial_baud_rate-1kickstart<<inherit>>ks_meta<<inherit>>` + const result: System = { + ctime: 1721480439.5932038, + mtime: 1721480439.5932038, + name: "testsys", + depth: 2, + comment: "", + owners: "<>", + uid: "a3320bc9105c44f1b92ab1743d460ed8", + autoinstall: "<>", + boot_files: "<>", + boot_loaders: "<>", + parent: "", + is_subobject: false, + autoinstall_meta: "<>", + enable_ipxe: "<>", + fetchable_files: "<>", + filename: "<>", + gateway: "", + hostname: "", + image: "", + ipv6_autoconfiguration: false, + ipv6_default_device: "", + kernel_options: "<>", + kernel_options_post: "<>", + mgmt_classes: "<>", + mgmt_parameters: "<>", + name_servers: [], + name_servers_search: [], + netboot_enabled: false, + next_server_v4: "<>", + next_server_v6: "<>", + power_address: "", + power_id: "", + power_identity_file: "", + power_options: "", + power_pass: "", + power_type: "", + power_user: "", + profile: "testprof", + proxy: "<>", + redhat_management_key: "<>", + repos_enabled: false, + server: "<>", + serial_baud_rate: -1, + serial_device : -1, + status: "", + virt_auto_boot: "<>", + virt_disk_driver: "<>", + virt_path: "<>", + virt_ram: "<>", + virt_type: "<>", + virt_file_size: "<>", + virt_cpus: "<>", + virt_pxe_boot: false, + template_files: {}, + interfaces: { + default: { + bonding_opts: '', + bridge_opts: '', + cnames: [], + connected_mode: false, + dhcp_tag: '', + dns_name: '', + if_gateway: '', + interface_master: '', + interface_type: 'na', + ip_address: '', + ipv6_address: '', + ipv6_default_gateway: '', + ipv6_mtu: '', + ipv6_prefix: '', + ipv6_secondaries: [], + ipv6_static_routes: [], + mac_address: '', + management: false, + mtu: '', + netmask: '', + static: false, + static_routes: [], + virt_bridge: '<>', + } + }, + } + service.get_system('', false, false, "").subscribe(value => { + expect(value).toEqual(result) + done() + }); + const mockRequest = httpTestingController.expectOne('http://localhost/cobbler_api'); + mockRequest.flush(methodResponse); }); - xit('should execute the get_repo action on the Cobbler Server', () => { - service.get_repo(''); - expect(service).toBeFalsy(); + it('should execute the get_repo action on the Cobbler Server', (done: DoneFn) => { + // eslint-disable-next-line max-len + const methodResponse = `parentdepth0ctime1721480440.9711354mtime1721480440.9711354uid8b58f9b09a3e4d28965160d97a5de482nametestrepocommentkernel_optionskernel_options_postautoinstall_metafetchable_filesboot_filestemplate_filesowners<<inherit>>mgmt_classes<<inherit>>mgmt_parametersis_subobject0breednonearchnoneenvironmentyumoptsrsyncoptsmirror_typebaseurlapt_componentsapt_distscreaterepo_flags<<inherit>>keep_updated0mirrormirror_locally0priority0proxy<<inherit>>rpm_listos_versionks_meta` + const result: Repo = { + ctime: 1721480440.9711354, + mtime: 1721480440.9711354, + name: "testrepo", + depth: 0, + comment: "", + owners: "<>", + uid: "8b58f9b09a3e4d28965160d97a5de482", + fetchable_files: {}, + is_subobject: false, + parent: "", + kernel_options: {}, + kernel_options_post: {}, + mgmt_classes: "<>", + mgmt_parameters: {}, + arch: "none", + breed: "none", + apt_components: [], + apt_dists: [], + mirror: "", + rsyncopts: {}, + proxy: "<>", + createrepo_flags: "<>", + environment: {}, + keep_updated: false, + mirror_locally: false, + mirror_type: "baseurl", + priority: 0, + rpm_list: [], + yumopts: {}, + autoinstall_meta: {}, + boot_files: {}, + os_version: "", + template_files: {}, + } + service.get_repo('', false, false, "").subscribe(value => { + expect(value).toEqual(result) + done() + }); + const mockRequest = httpTestingController.expectOne('http://localhost/cobbler_api'); + mockRequest.flush(methodResponse); }); - xit('should execute the get_image action on the Cobbler Server', () => { - service.get_image(''); - expect(service).toBeFalsy(); + it('should execute the get_image action on the Cobbler Server', (done: DoneFn) => { + // eslint-disable-next-line max-len + const methodResponse = `parentdepth0ctime1721480441.493743mtime1721480441.493743uid911577c3691b4294acdf017e7f15f4cfnametestimagecommentkernel_optionskernel_options_postautoinstall_metafetchable_filesboot_filestemplate_filesowners<<inherit>>mgmt_classes<<inherit>>mgmt_parametersis_subobject0archx86_64autoinstall<<inherit>>breedfileimage_typedirectnetwork_count0os_versionboot_loadersmenuvirt_auto_boot0virt_bridge<<inherit>>virt_cpus1virt_disk_driverrawvirt_file_size<<inherit>>virt_pathvirt_ram<<inherit>>virt_type<<inherit>>kickstart<<inherit>>ks_meta` + const result: Image = { + ctime: 1721480441.493743, + mtime: 1721480441.493743, + name: "testimage", + depth: 0, + comment: "", + owners: "<>", + uid: "911577c3691b4294acdf017e7f15f4cf", + arch: "x86_64", + breed: "", + file: "", + fetchable_files: {}, + is_subobject: false, + parent: "", + kernel_options: {}, + kernel_options_post: {}, + mgmt_classes: "<>", + mgmt_parameters: {}, + autoinstall: "<>", + image_type: "direct", + network_count: 0, + os_version: "", + virt_auto_boot: false, + virt_bridge: "<>", + virt_cpus: 1, + virt_disk_driver: "raw", + virt_file_size: "<>", + virt_path: "", + virt_ram: "<>", + virt_type: "<>", + menu: "", + autoinstall_meta: {}, + boot_files: {}, + boot_loaders: [], + template_files: {}, + } + service.get_image('', false, false, "").subscribe(value => { + expect(value).toEqual(result) + done() + }); + const mockRequest = httpTestingController.expectOne('http://localhost/cobbler_api'); + mockRequest.flush(methodResponse); }); - xit('should execute the get_mgmtclass action on the Cobbler Server', () => { - service.get_mgmtclass(''); - expect(service).toBeFalsy(); + it('should execute the get_mgmtclass action on the Cobbler Server', (done: DoneFn) => { + // eslint-disable-next-line max-len + const methodResponse = `parentdepth0ctime1721480442.0213087mtime1721480442.0213087uid5a4898be6fca4d7884898fa60a64e6dcnametestmgmtclasscommentkernel_optionskernel_options_postautoinstall_metafetchable_filesboot_filestemplate_filesowners<<inherit>>mgmt_classes<<inherit>>mgmt_parametersis_subobject0is_definition0paramsclass_namefilespackagesks_meta` + const result: Mgmgtclass = { + ctime: 1721480442.0213087, + mtime: 1721480442.0213087, + name: "testmgmtclass", + depth: 0, + comment: "", + owners: "<>", + uid: "5a4898be6fca4d7884898fa60a64e6dc", + fetchable_files: {}, + is_subobject: false, + parent: "", + kernel_options: {}, + kernel_options_post: {}, + mgmt_classes: "<>", + mgmt_parameters: {}, + class_name: "", + files: [], + is_definition: false, + packages: [], + params: {}, + autoinstall_meta: {}, + boot_files: {}, + template_files: {}, + } + service.get_mgmtclass('', false, false, "").subscribe(value => { + expect(value).toEqual(result) + done() + }); + const mockRequest = httpTestingController.expectOne('http://localhost/cobbler_api'); + mockRequest.flush(methodResponse); }); - xit('should execute the get_package action on the Cobbler Server', () => { - service.get_package(''); - expect(service).toBeFalsy(); + it('should execute the get_package action on the Cobbler Server', (done: DoneFn) => { + // eslint-disable-next-line max-len + const methodResponse = `parentdepth0ctime1721480441.7595894mtime1721480441.7595894uida6d7ee9851d74f73b9f393f89efd4caenametestpackagecommentkernel_optionskernel_options_postautoinstall_metafetchable_filesboot_filestemplate_filesowners<<inherit>>mgmt_classes<<inherit>>mgmt_parametersis_subobject0actioncreatemodeownergrouppathtemplateinstallerversionks_meta` + const result: Package = { + ctime: 1721480441.7595894, + mtime: 1721480441.7595894, + name: "testpackage", + depth: 0, + comment: "", + owners: "<>", + uid: "a6d7ee9851d74f73b9f393f89efd4cae", + action: "create", + installer: "", + version: "", + mode: "", + group: "", + owner: "", + path: "", + template: "", + fetchable_files: {}, + is_subobject: false, + parent: "", + kernel_options: {}, + kernel_options_post: {}, + mgmt_classes: "<>", + mgmt_parameters: {}, + boot_files: {}, + autoinstall_meta: {}, + template_files: {}, + } + service.get_package('', false, false, "").subscribe(value => { + expect(value).toEqual(result) + done() + }); + const mockRequest = httpTestingController.expectOne('http://localhost/cobbler_api'); + mockRequest.flush(methodResponse); }); - xit('should execute the get_file action on the Cobbler Server', () => { - service.get_file(''); - expect(service).toBeFalsy(); + it('should execute the get_file action on the Cobbler Server', (done: DoneFn) => { + // eslint-disable-next-line max-len + const methodResponse = `parentdepth0ctime1721480443.0627294mtime1721480443.0627294uid650659dad2694598a14632f4a434c4a9nametestfilecommentkernel_optionskernel_options_postautoinstall_metafetchable_filesboot_filestemplate_filesowners<<inherit>>mgmt_classes<<inherit>>mgmt_parametersis_subobject0actioncreatemode0644ownerrootgrouprootpath/root/testfiletemplate/etc/cobbler/dhcp.templateis_dir0ks_meta` + const result: File = { + ctime: 1721480443.0627294, + mtime: 1721480443.0627294, + name: "testfile", + depth: 0, + comment: "", + owners: "<>", + uid: "650659dad2694598a14632f4a434c4a9", + owner: "root", + action: "create", + group: "root", + is_dir: false, + mode: "0644", + path: "/root/testfile", + template: "/etc/cobbler/dhcp.template", + fetchable_files: {}, + is_subobject: false, + kernel_options: {}, + kernel_options_post: {}, + mgmt_classes: "<>", + mgmt_parameters: {}, + template_files: {}, + autoinstall_meta: {}, + boot_files: {}, + parent: "", + } + service.get_file('', false, false, "").subscribe(value => { + expect(value).toEqual(result) + done() + }); + const mockRequest = httpTestingController.expectOne('http://localhost/cobbler_api'); + mockRequest.flush(methodResponse); }); xit('should execute the get_items action on the Cobbler Server', () => { @@ -383,49 +744,426 @@ describe('CobblerApiService', () => { expect(service).toBeFalsy(); }); - xit('should execute the get_item_names action on the Cobbler Server', () => { - service.get_item_names(''); - expect(service).toBeFalsy(); + it('should execute the get_item_names action on the Cobbler Server', (done: DoneFn) => { + // eslint-disable-next-line max-len + const methodResponse = `testdistro` + const result = ["testdistro"] + service.get_item_names('distro').subscribe(value => { + expect(value).toEqual(result) + done() + }); + const mockRequest = httpTestingController.expectOne('http://localhost/cobbler_api'); + mockRequest.flush(methodResponse); }); - xit('should execute the get_distros action on the Cobbler Server', () => { - service.get_distros(); - expect(service).toBeFalsy(); + it('should execute the get_distros action on the Cobbler Server', (done: DoneFn) => { + // eslint-disable-next-line max-len + const methodResponse = `parentdepth0ctime1721480439.039089mtime1721480439.039089uid12f034d6781946d1af0783e20684cbd4nametestcommentkernel_optionskernel_options_postautoinstall_metafetchable_filesboot_filestemplate_filesowners<<inherit>>mgmt_classesmgmt_parametersis_subobject0tree_build_time0.0archx86_64boot_loaders<<inherit>>breedinitrd/root/initrdkernel/root/kernelos_versionredhat_management_key<<inherit>>source_reposremote_boot_kernelremote_grub_kernelremote_boot_initrdremote_grub_initrdks_meta` + const result: Array = [ + { + ctime: 1721480439.039089, + depth: 0, + mtime: 1721480439.039089, + uid: "12f034d6781946d1af0783e20684cbd4", + source_repos: [], + tree_build_time: 0, + arch: "x86_64", + autoinstall_meta: {}, + boot_files: {}, + boot_loaders: "<>", + is_subobject: false, + parent: "", + breed: "", + comment: "", + fetchable_files: {}, + initrd: "/root/initrd", + kernel: "/root/kernel", + remote_boot_initrd: "", + remote_boot_kernel: "", + remote_grub_initrd: "", + remote_grub_kernel: "", + kernel_options: {}, + kernel_options_post: {}, + mgmt_classes: [], + mgmt_parameters: {}, + name: "test", + os_version: "", + owners: "<>", + redhat_management_key: "<>", + template_files: {} + } + ] + service.get_distros().subscribe(value => { + expect(value).toEqual(result) + done() + }); + const mockRequest = httpTestingController.expectOne('http://localhost/cobbler_api'); + mockRequest.flush(methodResponse); }); - xit('should execute the get_profiles action on the Cobbler Server', () => { - service.get_profiles(); - expect(service).toBeFalsy(); + it('should execute the get_profiles action on the Cobbler Server', (done: DoneFn) => { + // eslint-disable-next-line max-len + const methodResponse = `parentdepth1ctime1721480439.3090012mtime1721480439.3090012uid5f01667614244fcd9c7ca7fa59c7def1nametestprofcommentkernel_options<<inherit>>kernel_options_post<<inherit>>autoinstall_meta<<inherit>>fetchable_files<<inherit>>boot_files<<inherit>>template_filesowners<<inherit>>mgmt_classes<<inherit>>mgmt_parameters<<inherit>>is_subobject0autoinstall<<inherit>>boot_loaders<<inherit>>dhcp_tagdistrotestenable_ipxe<<inherit>>enable_menu<<inherit>>name_serversname_servers_searchnext_server_v4<<inherit>>next_server_v6<<inherit>>filenameproxy<<inherit>>redhat_management_key<<inherit>>reposserver<<inherit>>menuvirt_auto_boot<<inherit>>virt_bridge<<inherit>>virt_cpus1virt_disk_driverrawvirt_file_size<<inherit>>virt_pathvirt_ram<<inherit>>virt_typexenpvkickstart<<inherit>>ks_meta<<inherit>>` + const result: Array = [ + { + name: "testprof", + depth: 1, + mtime: 1721480439.3090012, + is_subobject: false, + boot_loaders: "<>", + autoinstall_meta: "<>", + server: "<>", + distro: "test", + comment: "", + next_server_v4: "<>", + next_server_v6: "<>", + enable_ipxe: "<>", + parent: "", + owners: "<>", + autoinstall: "<>", + uid: "5f01667614244fcd9c7ca7fa59c7def1", + virt_ram: "<>", + boot_files: "<>", + mgmt_parameters: "<>", + name_servers: [], + enable_menu: "<>", + menu: "", + ctime: 1721480439.3090012, + fetchable_files: "<>", + mgmt_classes: "<>", + kernel_options: "<>", + virt_auto_boot: "<>", + kernel_options_post: "<>", + proxy: "<>", + filename: "", + dhcp_tag: "", + redhat_management_key: "<>", + repos: [], + template_files: {}, + virt_type: "xenpv", + virt_cpus: 1, + virt_bridge: "<>", + name_servers_search: [], + virt_path: "", + virt_file_size: "<>", + virt_disk_driver: "raw", + } + ] + service.get_profiles().subscribe(value => { + expect(value).toEqual(result) + done() + }); + const mockRequest = httpTestingController.expectOne('http://localhost/cobbler_api'); + mockRequest.flush(methodResponse); }); - xit('should execute the get_systems action on the Cobbler Server', () => { - service.get_systems(); - expect(service).toBeFalsy(); + it('should execute the get_systems action on the Cobbler Server', (done: DoneFn) => { + // eslint-disable-next-line max-len + const methodResponse = `parentdepth2ctime1721480439.5932038mtime1721480439.5932038uida3320bc9105c44f1b92ab1743d460ed8nametestsyscommentkernel_options<<inherit>>kernel_options_post<<inherit>>autoinstall_meta<<inherit>>fetchable_files<<inherit>>boot_files<<inherit>>template_filesowners<<inherit>>mgmt_classes<<inherit>>mgmt_parameters<<inherit>>is_subobject0interfacesdefaultbonding_optsbridge_optscnamesconnected_mode0dhcp_tagdns_nameif_gatewayinterface_masterinterface_typenaip_addressipv6_addressipv6_default_gatewayipv6_mtuipv6_prefixipv6_secondariesipv6_static_routesmac_addressmanagement0mtunetmaskstatic0static_routesvirt_bridge<<inherit>>ipv6_autoconfiguration0repos_enabled0autoinstall<<inherit>>boot_loaders<<inherit>>enable_ipxe<<inherit>>gatewayhostnameimageipv6_default_devicename_serversname_servers_searchnetboot_enabled0next_server_v4<<inherit>>next_server_v6<<inherit>>filename<<inherit>>power_addresspower_idpower_passpower_typepower_userpower_optionspower_identity_fileprofiletestprofproxy<<inherit>>redhat_management_key<<inherit>>server<<inherit>>statusvirt_auto_boot<<inherit>>virt_cpus<<inherit>>virt_disk_driver<<inherit>>virt_file_size<<inherit>>virt_path<<inherit>>virt_pxe_boot0virt_ram<<inherit>>virt_type<<inherit>>serial_device-1serial_baud_rate-1kickstart<<inherit>>ks_meta<<inherit>>` + const result: Array = [ + { + ctime: 1721480439.5932038, + mtime: 1721480439.5932038, + name: "testsys", + depth: 2, + comment: "", + owners: "<>", + uid: "a3320bc9105c44f1b92ab1743d460ed8", + autoinstall: "<>", + boot_files: "<>", + boot_loaders: "<>", + parent: "", + is_subobject: false, + autoinstall_meta: "<>", + enable_ipxe: "<>", + fetchable_files: "<>", + filename: "<>", + gateway: "", + hostname: "", + image: "", + ipv6_autoconfiguration: false, + ipv6_default_device: "", + kernel_options: "<>", + kernel_options_post: "<>", + mgmt_classes: "<>", + mgmt_parameters: "<>", + name_servers: [], + name_servers_search: [], + netboot_enabled: false, + next_server_v4: "<>", + next_server_v6: "<>", + power_address: "", + power_id: "", + power_identity_file: "", + power_options: "", + power_pass: "", + power_type: "", + power_user: "", + profile: "testprof", + proxy: "<>", + redhat_management_key: "<>", + repos_enabled: false, + server: "<>", + serial_baud_rate: -1, + serial_device: -1, + status: "", + virt_auto_boot: "<>", + virt_disk_driver: "<>", + virt_path: "<>", + virt_ram: "<>", + virt_type: "<>", + virt_file_size: "<>", + virt_cpus: "<>", + virt_pxe_boot: false, + template_files: {}, + interfaces: { + default: { + bonding_opts: '', + bridge_opts: '', + cnames: [], + connected_mode: false, + dhcp_tag: '', + dns_name: '', + if_gateway: '', + interface_master: '', + interface_type: 'na', + ip_address: '', + ipv6_address: '', + ipv6_default_gateway: '', + ipv6_mtu: '', + ipv6_prefix: '', + ipv6_secondaries: [], + ipv6_static_routes: [], + mac_address: '', + management: false, + mtu: '', + netmask: '', + static: false, + static_routes: [], + virt_bridge: '<>', + } + } + } + ] + service.get_systems().subscribe(value => { + expect(value).toEqual(result) + done() + }); + const mockRequest = httpTestingController.expectOne('http://localhost/cobbler_api'); + mockRequest.flush(methodResponse); }); - xit('should execute the get_repos action on the Cobbler Server', () => { - service.get_repos(); - expect(service).toBeFalsy(); + it('should execute the get_repos action on the Cobbler Server', (done: DoneFn) => { + // eslint-disable-next-line max-len + const methodResponse = `parentdepth0ctime1721480440.9711354mtime1721480440.9711354uid8b58f9b09a3e4d28965160d97a5de482nametestrepocommentkernel_optionskernel_options_postautoinstall_metafetchable_filesboot_filestemplate_filesowners<<inherit>>mgmt_classes<<inherit>>mgmt_parametersis_subobject0breednonearchnoneenvironmentyumoptsrsyncoptsmirror_typebaseurlapt_componentsapt_distscreaterepo_flags<<inherit>>keep_updated0mirrormirror_locally0priority0proxy<<inherit>>rpm_listos_versionks_meta` + const result: Array = [ + { + ctime: 1721480440.9711354, + mtime: 1721480440.9711354, + name: "testrepo", + depth: 0, + comment: "", + owners: "<>", + uid: "8b58f9b09a3e4d28965160d97a5de482", + fetchable_files: {}, + is_subobject: false, + parent: "", + kernel_options: {}, + kernel_options_post: {}, + mgmt_classes: "<>", + mgmt_parameters: {}, + arch: "none", + breed: "none", + apt_components: [], + apt_dists: [], + mirror: "", + rsyncopts: {}, + proxy: "<>", + createrepo_flags: "<>", + environment: {}, + keep_updated: false, + mirror_locally: false, + mirror_type: "baseurl", + priority: 0, + rpm_list: [], + yumopts: {}, + autoinstall_meta: {}, + boot_files: {}, + os_version: "", + template_files: {}, + } + ] + service.get_repos().subscribe(value => { + expect(value).toEqual(result) + done() + }); + const mockRequest = httpTestingController.expectOne('http://localhost/cobbler_api'); + mockRequest.flush(methodResponse); }); - xit('should execute the get_images action on the Cobbler Server', () => { - service.get_images(); - expect(service).toBeFalsy(); + it('should execute the get_images action on the Cobbler Server', (done: DoneFn) => { + // eslint-disable-next-line max-len + const methodResponse = `parentdepth0ctime1721480441.493743mtime1721480441.493743uid911577c3691b4294acdf017e7f15f4cfnametestimagecommentkernel_optionskernel_options_postautoinstall_metafetchable_filesboot_filestemplate_filesowners<<inherit>>mgmt_classes<<inherit>>mgmt_parametersis_subobject0archx86_64autoinstall<<inherit>>breedfileimage_typedirectnetwork_count0os_versionboot_loadersmenuvirt_auto_boot0virt_bridge<<inherit>>virt_cpus1virt_disk_driverrawvirt_file_size<<inherit>>virt_pathvirt_ram<<inherit>>virt_type<<inherit>>kickstart<<inherit>>ks_meta` + const result: Array = [ + { + ctime: 1721480441.493743, + mtime: 1721480441.493743, + name: "testimage", + depth: 0, + comment: "", + owners: "<>", + uid: "911577c3691b4294acdf017e7f15f4cf", + arch: "x86_64", + breed: "", + file: "", + fetchable_files: {}, + is_subobject: false, + parent: "", + kernel_options: {}, + kernel_options_post: {}, + mgmt_classes: "<>", + mgmt_parameters: {}, + autoinstall: "<>", + image_type: "direct", + network_count: 0, + os_version: "", + virt_auto_boot: false, + virt_bridge: "<>", + virt_cpus: 1, + virt_disk_driver: "raw", + virt_file_size: "<>", + virt_path: "", + virt_ram: "<>", + virt_type: "<>", + menu: "", + autoinstall_meta: {}, + boot_files: {}, + boot_loaders: [], + template_files: {}, + } + ] + service.get_images().subscribe(value => { + expect(value).toEqual(result) + done() + }); + const mockRequest = httpTestingController.expectOne('http://localhost/cobbler_api'); + mockRequest.flush(methodResponse); }); - xit('should execute the get_mgmtclasses action on the Cobbler Server', () => { - service.get_mgmtclasses(); - expect(service).toBeFalsy(); + it('should execute the get_mgmtclasses action on the Cobbler Server', (done: DoneFn) => { + // eslint-disable-next-line max-len + const methodResponse = `parentdepth0ctime1721480442.0213087mtime1721480442.0213087uid5a4898be6fca4d7884898fa60a64e6dcnametestmgmtclasscommentkernel_optionskernel_options_postautoinstall_metafetchable_filesboot_filestemplate_filesowners<<inherit>>mgmt_classes<<inherit>>mgmt_parametersis_subobject0is_definition0paramsclass_namefilespackagesks_meta` + const result: Array = [ + { + ctime: 1721480442.0213087, + mtime: 1721480442.0213087, + name: "testmgmtclass", + depth: 0, + comment: "", + owners: "<>", + uid: "5a4898be6fca4d7884898fa60a64e6dc", + fetchable_files: {}, + is_subobject: false, + parent: "", + kernel_options: {}, + kernel_options_post: {}, + mgmt_classes: "<>", + mgmt_parameters: {}, + class_name: "", + files: [], + is_definition: false, + packages: [], + params: {}, + autoinstall_meta: {}, + boot_files: {}, + template_files: {}, + } + ] + service.get_mgmtclasses().subscribe(value => { + expect(value).toEqual(result) + done() + }); + const mockRequest = httpTestingController.expectOne('http://localhost/cobbler_api'); + mockRequest.flush(methodResponse); }); - xit('should execute the get_packages action on the Cobbler Server', () => { - service.get_packages(); - expect(service).toBeFalsy(); + it('should execute the get_packages action on the Cobbler Server', (done: DoneFn) => { + // eslint-disable-next-line max-len + const methodResponse = `parentdepth0ctime1721480441.7595894mtime1721480441.7595894uida6d7ee9851d74f73b9f393f89efd4caenametestpackagecommentkernel_optionskernel_options_postautoinstall_metafetchable_filesboot_filestemplate_filesowners<<inherit>>mgmt_classes<<inherit>>mgmt_parametersis_subobject0actioncreatemodeownergrouppathtemplateinstallerversionks_meta` + const result: Array = [ + { + ctime: 1721480441.7595894, + mtime: 1721480441.7595894, + name: "testpackage", + depth: 0, + comment: "", + owners: "<>", + uid: "a6d7ee9851d74f73b9f393f89efd4cae", + action: "create", + installer: "", + version: "", + mode: "", + group: "", + owner: "", + path: "", + template: "", + fetchable_files: {}, + is_subobject: false, + parent: "", + kernel_options: {}, + kernel_options_post: {}, + mgmt_classes: "<>", + mgmt_parameters: {}, + boot_files: {}, + autoinstall_meta: {}, + template_files: {}, + } + ] + service.get_packages().subscribe(value => { + expect(value).toEqual(result) + done() + }); + const mockRequest = httpTestingController.expectOne('http://localhost/cobbler_api'); + mockRequest.flush(methodResponse); }); - xit('should execute the get_files action on the Cobbler Server', () => { - service.get_files(); - expect(service).toBeFalsy(); + it('should execute the get_files action on the Cobbler Server', (done: DoneFn) => { + // eslint-disable-next-line max-len + const methodResponse = `parentdepth0ctime1721480443.0627294mtime1721480443.0627294uid650659dad2694598a14632f4a434c4a9nametestfilecommentkernel_optionskernel_options_postautoinstall_metafetchable_filesboot_filestemplate_filesowners<<inherit>>mgmt_classes<<inherit>>mgmt_parametersis_subobject0actioncreatemode0644ownerrootgrouprootpath/root/testfiletemplate/etc/cobbler/dhcp.templateis_dir0ks_meta` + const result: Array = [ + { + ctime: 1721480443.0627294, + mtime: 1721480443.0627294, + name: "testfile", + depth: 0, + comment: "", + owners: "<>", + uid: "650659dad2694598a14632f4a434c4a9", + owner: "root", + action: "create", + group: "root", + is_dir: false, + mode: "0644", + path: "/root/testfile", + template: "/etc/cobbler/dhcp.template", + fetchable_files: {}, + is_subobject: false, + kernel_options: {}, + kernel_options_post: {}, + mgmt_classes: "<>", + mgmt_parameters: {}, + template_files: {}, + autoinstall_meta: {}, + boot_files: {}, + parent: "", + } + ] + service.get_files().subscribe(value => { + expect(value).toEqual(result) + done() + }); + const mockRequest = httpTestingController.expectOne('http://localhost/cobbler_api'); + mockRequest.flush(methodResponse); }); xit('should execute the find_items action on the Cobbler Server', () => { @@ -488,44 +1226,100 @@ describe('CobblerApiService', () => { expect(service).toBeFalsy(); }); - xit('should execute the get_distro_handle action on the Cobbler Server', () => { - service.get_distro_handle('', ''); - expect(service).toBeFalsy(); + it('should execute the get_distro_handle action on the Cobbler Server', (done: DoneFn) => { + // eslint-disable-next-line max-len + const methodResponse = `distro::test` + const result = "distro::test" + service.get_distro_handle("", "").subscribe(value => { + expect(value).toEqual(result) + done() + }); + const mockRequest = httpTestingController.expectOne('http://localhost/cobbler_api'); + mockRequest.flush(methodResponse); }); - xit('should execute the get_profile_handle action on the Cobbler Server', () => { - service.get_profile_handle('', ''); - expect(service).toBeFalsy(); + it('should execute the get_profile_handle action on the Cobbler Server', (done: DoneFn) => { + // eslint-disable-next-line max-len + const methodResponse = `profile::testprof` + const result = "profile::testprof" + service.get_profile_handle("", "").subscribe(value => { + expect(value).toEqual(result) + done() + }); + const mockRequest = httpTestingController.expectOne('http://localhost/cobbler_api'); + mockRequest.flush(methodResponse); }); - xit('should execute the get_system_handle action on the Cobbler Server', () => { - service.get_system_handle('', ''); - expect(service).toBeFalsy(); + it('should execute the get_system_handle action on the Cobbler Server', (done: DoneFn) => { + // eslint-disable-next-line max-len + const methodResponse = `distro::testdistro` + const result = "distro::testdistro" + service.get_system_handle("", "").subscribe(value => { + expect(value).toEqual(result) + done() + }); + const mockRequest = httpTestingController.expectOne('http://localhost/cobbler_api'); + mockRequest.flush(methodResponse); }); - xit('should execute the get_repo_handle action on the Cobbler Server', () => { - service.get_repo_handle('', ''); - expect(service).toBeFalsy(); + it('should execute the get_repo_handle action on the Cobbler Server', (done: DoneFn) => { + // eslint-disable-next-line max-len + const methodResponse = `repo::testrepo` + const result = "repo::testrepo" + service.get_repo_handle("", "").subscribe(value => { + expect(value).toEqual(result) + done() + }); + const mockRequest = httpTestingController.expectOne('http://localhost/cobbler_api'); + mockRequest.flush(methodResponse); }); - xit('should execute the get_image_handle action on the Cobbler Server', () => { - service.get_image_handle('', ''); - expect(service).toBeFalsy(); + it('should execute the get_image_handle action on the Cobbler Server', (done: DoneFn) => { + // eslint-disable-next-line max-len + const methodResponse = `image::testimage` + const result = "image::testimage" + service.get_image_handle("", "").subscribe(value => { + expect(value).toEqual(result) + done() + }); + const mockRequest = httpTestingController.expectOne('http://localhost/cobbler_api'); + mockRequest.flush(methodResponse); }); - xit('should execute the get_mgmtclass_handle action on the Cobbler Server', () => { - service.get_mgmtclass_handle('', ''); - expect(service).toBeFalsy(); + it('should execute the get_mgmtclass_handle action on the Cobbler Server', (done: DoneFn) => { + // eslint-disable-next-line max-len + const methodResponse = `mgmtclass::testmgmtclass` + const result = "mgmtclass::testmgmtclass" + service.get_mgmtclass_handle("", "").subscribe(value => { + expect(value).toEqual(result) + done() + }); + const mockRequest = httpTestingController.expectOne('http://localhost/cobbler_api'); + mockRequest.flush(methodResponse); }); - xit('should execute the get_package_handle action on the Cobbler Server', () => { - service.get_package_handle('', ''); - expect(service).toBeFalsy(); + it('should execute the get_package_handle action on the Cobbler Server', (done: DoneFn) => { + // eslint-disable-next-line max-len + const methodResponse = `package::testpackage` + const result = "package::testpackage" + service.get_package_handle("", "").subscribe(value => { + expect(value).toEqual(result) + done() + }); + const mockRequest = httpTestingController.expectOne('http://localhost/cobbler_api'); + mockRequest.flush(methodResponse); }); - xit('should execute the get_file_handle action on the Cobbler Server', () => { - service.get_file_handle('', ''); - expect(service).toBeFalsy(); + it('should execute the get_file_handle action on the Cobbler Server', (done: DoneFn) => { + // eslint-disable-next-line max-len + const methodResponse = `file::testfile` + const result = "file::testfile" + service.get_file_handle("", "").subscribe(value => { + expect(value).toEqual(result) + done() + }); + const mockRequest = httpTestingController.expectOne('http://localhost/cobbler_api'); + mockRequest.flush(methodResponse); }); xit('should execute the remove_item action on the Cobbler Server', () => { @@ -533,44 +1327,100 @@ describe('CobblerApiService', () => { expect(service).toBeFalsy(); }); - xit('should execute the remove_distro action on the Cobbler Server', () => { - service.remove_distro('', '', true); - expect(service).toBeFalsy(); + it('should execute the remove_distro action on the Cobbler Server', (done: DoneFn) => { + // eslint-disable-next-line max-len + const methodResponse = `1` + const result = true + service.remove_distro("", "", false).subscribe(value => { + expect(value).toEqual(result) + done() + }); + const mockRequest = httpTestingController.expectOne('http://localhost/cobbler_api'); + mockRequest.flush(methodResponse); }); - xit('should execute the remove_profile action on the Cobbler Server', () => { - service.remove_profile('', '', true); - expect(service).toBeFalsy(); + it('should execute the remove_profile action on the Cobbler Server', (done: DoneFn) => { + // eslint-disable-next-line max-len + const methodResponse = `1` + const result = true + service.remove_profile("", "", false).subscribe(value => { + expect(value).toEqual(result) + done() + }); + const mockRequest = httpTestingController.expectOne('http://localhost/cobbler_api'); + mockRequest.flush(methodResponse); }); - xit('should execute the remove_system action on the Cobbler Server', () => { - service.remove_system('', '', true); - expect(service).toBeFalsy(); + it('should execute the remove_system action on the Cobbler Server', (done: DoneFn) => { + // eslint-disable-next-line max-len + const methodResponse = `1` + const result = true + service.remove_system("", "", false).subscribe(value => { + expect(value).toEqual(result) + done() + }); + const mockRequest = httpTestingController.expectOne('http://localhost/cobbler_api'); + mockRequest.flush(methodResponse); }); - xit('should execute the remove_repo action on the Cobbler Server', () => { - service.remove_repo('', '', true); - expect(service).toBeFalsy(); + it('should execute the remove_repo action on the Cobbler Server', (done: DoneFn) => { + // eslint-disable-next-line max-len + const methodResponse = `1` + const result = true + service.remove_repo("", "", false).subscribe(value => { + expect(value).toEqual(result) + done() + }); + const mockRequest = httpTestingController.expectOne('http://localhost/cobbler_api'); + mockRequest.flush(methodResponse); }); - xit('should execute the remove_image action on the Cobbler Server', () => { - service.remove_image('', '', true); - expect(service).toBeFalsy(); + it('should execute the remove_image action on the Cobbler Server', (done: DoneFn) => { + // eslint-disable-next-line max-len + const methodResponse = `1` + const result = true + service.remove_image("", "", false).subscribe(value => { + expect(value).toEqual(result) + done() + }); + const mockRequest = httpTestingController.expectOne('http://localhost/cobbler_api'); + mockRequest.flush(methodResponse); }); - xit('should execute the remove_mgmtclass action on the Cobbler Server', () => { - service.remove_mgmtclass('', '', true); - expect(service).toBeFalsy(); + it('should execute the remove_mgmtclass action on the Cobbler Server', (done: DoneFn) => { + // eslint-disable-next-line max-len + const methodResponse = `1` + const result = true + service.remove_mgmtclass("", "", false).subscribe(value => { + expect(value).toEqual(result) + done() + }); + const mockRequest = httpTestingController.expectOne('http://localhost/cobbler_api'); + mockRequest.flush(methodResponse); }); - xit('should execute the remove_package action on the Cobbler Server', () => { - service.remove_package('', '', true); - expect(service).toBeFalsy(); + it('should execute the remove_package action on the Cobbler Server', (done: DoneFn) => { + // eslint-disable-next-line max-len + const methodResponse = `1` + const result = true + service.remove_package("", "", false).subscribe(value => { + expect(value).toEqual(result) + done() + }); + const mockRequest = httpTestingController.expectOne('http://localhost/cobbler_api'); + mockRequest.flush(methodResponse); }); - xit('should execute the remove_file action on the Cobbler Server', () => { - service.remove_file('', '', true); - expect(service).toBeFalsy(); + it('should execute the remove_file action on the Cobbler Server', (done: DoneFn) => { + // eslint-disable-next-line max-len + const methodResponse = `1` + const result = true + service.remove_file("", "", false).subscribe(value => { + expect(value).toEqual(result) + done() + }); + const mockRequest = httpTestingController.expectOne('http://localhost/cobbler_api'); + mockRequest.flush(methodResponse); }); xit('should execute the copy_item action on the Cobbler Server', () => { @@ -578,44 +1428,100 @@ describe('CobblerApiService', () => { expect(service).toBeFalsy(); }); - xit('should execute the copy_distro action on the Cobbler Server', () => { - service.copy_distro('', '', ''); - expect(service).toBeFalsy(); + it('should execute the copy_distro action on the Cobbler Server', (done: DoneFn) => { + // eslint-disable-next-line max-len + const methodResponse = `1` + const result = true + service.copy_distro("", "", "").subscribe(value => { + expect(value).toEqual(result) + done() + }); + const mockRequest = httpTestingController.expectOne('http://localhost/cobbler_api'); + mockRequest.flush(methodResponse); }); - xit('should execute the copy_profile action on the Cobbler Server', () => { - service.copy_profile('', '', ''); - expect(service).toBeFalsy(); + it('should execute the copy_profile action on the Cobbler Server', (done: DoneFn) => { + // eslint-disable-next-line max-len + const methodResponse = `1` + const result = true + service.copy_profile("", "", "").subscribe(value => { + expect(value).toEqual(result) + done() + }); + const mockRequest = httpTestingController.expectOne('http://localhost/cobbler_api'); + mockRequest.flush(methodResponse); }); - xit('should execute the copy_system action on the Cobbler Server', () => { - service.copy_system('', '', ''); - expect(service).toBeFalsy(); + it('should execute the copy_system action on the Cobbler Server', (done: DoneFn) => { + // eslint-disable-next-line max-len + const methodResponse = `1` + const result = true + service.copy_system("", "", "").subscribe(value => { + expect(value).toEqual(result) + done() + }); + const mockRequest = httpTestingController.expectOne('http://localhost/cobbler_api'); + mockRequest.flush(methodResponse); }); - xit('should execute the copy_repo action on the Cobbler Server', () => { - service.copy_repo('', '', ''); - expect(service).toBeFalsy(); + it('should execute the copy_repo action on the Cobbler Server', (done: DoneFn) => { + // eslint-disable-next-line max-len + const methodResponse = `1` + const result = true + service.copy_repo("", "", "").subscribe(value => { + expect(value).toEqual(result) + done() + }); + const mockRequest = httpTestingController.expectOne('http://localhost/cobbler_api'); + mockRequest.flush(methodResponse); }); - xit('should execute the copy_image action on the Cobbler Server', () => { - service.copy_image('', '', ''); - expect(service).toBeFalsy(); + it('should execute the copy_image action on the Cobbler Server', (done: DoneFn) => { + // eslint-disable-next-line max-len + const methodResponse = `1` + const result = true + service.copy_image("", "", "").subscribe(value => { + expect(value).toEqual(result) + done() + }); + const mockRequest = httpTestingController.expectOne('http://localhost/cobbler_api'); + mockRequest.flush(methodResponse); }); - xit('should execute the copy_mgmtclass action on the Cobbler Server', () => { - service.copy_mgmtclass('', '', ''); - expect(service).toBeFalsy(); + it('should execute the copy_mgmtclass action on the Cobbler Server', (done: DoneFn) => { + // eslint-disable-next-line max-len + const methodResponse = `1` + const result = true + service.copy_mgmtclass("", "", "").subscribe(value => { + expect(value).toEqual(result) + done() + }); + const mockRequest = httpTestingController.expectOne('http://localhost/cobbler_api'); + mockRequest.flush(methodResponse); }); - xit('should execute the copy_package action on the Cobbler Server', () => { - service.copy_package('', '', ''); - expect(service).toBeFalsy(); + it('should execute the copy_package action on the Cobbler Server', (done: DoneFn) => { + // eslint-disable-next-line max-len + const methodResponse = `1` + const result = true + service.copy_package("", "", "").subscribe(value => { + expect(value).toEqual(result) + done() + }); + const mockRequest = httpTestingController.expectOne('http://localhost/cobbler_api'); + mockRequest.flush(methodResponse); }); - xit('should execute the copy_file action on the Cobbler Server', () => { - service.copy_file('', '', ''); - expect(service).toBeFalsy(); + it('should execute the copy_file action on the Cobbler Server', (done: DoneFn) => { + // eslint-disable-next-line max-len + const methodResponse = `1` + const result = true + service.copy_file("", "", "").subscribe(value => { + expect(value).toEqual(result) + done() + }); + const mockRequest = httpTestingController.expectOne('http://localhost/cobbler_api'); + mockRequest.flush(methodResponse); }); xit('should execute the rename_item action on the Cobbler Server', () => { @@ -623,44 +1529,100 @@ describe('CobblerApiService', () => { expect(service).toBeFalsy(); }); - xit('should execute the rename_distro action on the Cobbler Server', () => { - service.rename_distro('', '', ''); - expect(service).toBeFalsy(); + it('should execute the rename_distro action on the Cobbler Server', (done: DoneFn) => { + // eslint-disable-next-line max-len + const methodResponse = `1` + const result = true + service.rename_distro("", "", "").subscribe(value => { + expect(value).toEqual(result) + done() + }); + const mockRequest = httpTestingController.expectOne('http://localhost/cobbler_api'); + mockRequest.flush(methodResponse); }); - xit('should execute the rename_profile action on the Cobbler Server', () => { - service.rename_profile('', '', ''); - expect(service).toBeFalsy(); + it('should execute the rename_profile action on the Cobbler Server', (done: DoneFn) => { + // eslint-disable-next-line max-len + const methodResponse = `1` + const result = true + service.rename_profile("", "", "").subscribe(value => { + expect(value).toEqual(result) + done() + }); + const mockRequest = httpTestingController.expectOne('http://localhost/cobbler_api'); + mockRequest.flush(methodResponse); }); - xit('should execute the rename_system action on the Cobbler Server', () => { - service.rename_system('', '', ''); - expect(service).toBeFalsy(); + it('should execute the rename_system action on the Cobbler Server', (done: DoneFn) => { + // eslint-disable-next-line max-len + const methodResponse = `1` + const result = true + service.rename_system("", "", "").subscribe(value => { + expect(value).toEqual(result) + done() + }); + const mockRequest = httpTestingController.expectOne('http://localhost/cobbler_api'); + mockRequest.flush(methodResponse); }); - xit('should execute the rename_repo action on the Cobbler Server', () => { - service.rename_repo('', '', ''); - expect(service).toBeFalsy(); + it('should execute the rename_repo action on the Cobbler Server', (done: DoneFn) => { + // eslint-disable-next-line max-len + const methodResponse = `1` + const result = true + service.rename_repo("", "", "").subscribe(value => { + expect(value).toEqual(result) + done() + }); + const mockRequest = httpTestingController.expectOne('http://localhost/cobbler_api'); + mockRequest.flush(methodResponse); }); - xit('should execute the rename_image action on the Cobbler Server', () => { - service.rename_image('', '', ''); - expect(service).toBeFalsy(); + it('should execute the rename_image action on the Cobbler Server', (done: DoneFn) => { + // eslint-disable-next-line max-len + const methodResponse = `1` + const result = true + service.rename_image("", "", "").subscribe(value => { + expect(value).toEqual(result) + done() + }); + const mockRequest = httpTestingController.expectOne('http://localhost/cobbler_api'); + mockRequest.flush(methodResponse); }); - xit('should execute the rename_mgmtclass action on the Cobbler Server', () => { - service.rename_mgmtclass('', '', ''); - expect(service).toBeFalsy(); + it('should execute the rename_mgmtclass action on the Cobbler Server', (done: DoneFn) => { + // eslint-disable-next-line max-len + const methodResponse = `1` + const result = true + service.rename_mgmtclass("", "", "").subscribe(value => { + expect(value).toEqual(result) + done() + }); + const mockRequest = httpTestingController.expectOne('http://localhost/cobbler_api'); + mockRequest.flush(methodResponse); }); - xit('should execute the rename_package action on the Cobbler Server', () => { - service.rename_package('', '', ''); - expect(service).toBeFalsy(); + it('should execute the rename_package action on the Cobbler Server', (done: DoneFn) => { + // eslint-disable-next-line max-len + const methodResponse = `1` + const result = true + service.rename_package("", "", "").subscribe(value => { + expect(value).toEqual(result) + done() + }); + const mockRequest = httpTestingController.expectOne('http://localhost/cobbler_api'); + mockRequest.flush(methodResponse); }); - xit('should execute the rename_file action on the Cobbler Server', () => { - service.rename_file('', '', ''); - expect(service).toBeFalsy(); + it('should execute the rename_file action on the Cobbler Server', (done: DoneFn) => { + // eslint-disable-next-line max-len + const methodResponse = `1` + const result = true + service.rename_file("", "", "").subscribe(value => { + expect(value).toEqual(result) + done() + }); + const mockRequest = httpTestingController.expectOne('http://localhost/cobbler_api'); + mockRequest.flush(methodResponse); }); xit('should execute the new_item action on the Cobbler Server', () => { @@ -819,14 +1781,28 @@ describe('CobblerApiService', () => { expect(service).toBeFalsy(); }); - xit('should execute the get_autoinstall_templates action on the Cobbler Server', () => { - service.get_autoinstall_templates(''); - expect(service).toBeFalsy(); + it('should execute the get_autoinstall_templates action on the Cobbler Server', () => { + // eslint-disable-next-line max-len + const methodResponse = `default.ksesxi4-ks.cfgesxi5-ks.cfglegacy.kspowerkvm.kspxerescue.kssample.kssample.seedsample_autoyast.xmlsample_esxi4.kssample_esxi5.kssample_esxi6.kssample_esxi7.kssample_legacy.kssample_old.seedwin.ks` + // eslint-disable-next-line max-len + const result = ["default.ks", "esxi4-ks.cfg", "esxi5-ks.cfg", "legacy.ks", "powerkvm.ks", "pxerescue.ks", "sample.ks", "sample.seed", "sample_autoyast.xml", "sample_esxi4.ks", "sample_esxi5.ks", "sample_esxi6.ks", "sample_esxi7.ks", "sample_legacy.ks", "sample_old.seed", "win.ks"] + service.get_autoinstall_templates("").subscribe(value => { + expect(value).toEqual(result) + }); + const mockRequest = httpTestingController.expectOne('http://localhost/cobbler_api'); + mockRequest.flush(methodResponse); }); - xit('should execute the get_autoinstall_snippets action on the Cobbler Server', () => { - service.get_autoinstall_snippets(''); - expect(service).toBeFalsy(); + it('should execute the get_autoinstall_snippets action on the Cobbler Server', () => { + // eslint-disable-next-line max-len + const methodResponse = `addons.xmlautoinstall_doneautoinstall_startcobbler_registerdownload_config_filesdownload_config_files_debhosts.xmlkdump.xmlkeep_cfengine_keyskeep_fileskeep_rhn_keyskeep_rudder_keyskeep_rudder_uuidkeep_ssh_host_keyskoan_environmentlate_apt_repo_configlog_ks_postlog_ks_post_nochrootlog_ks_premain_partition_selectnetwork_confignetwork_config_esxnetwork_config_esxinetworking.xmlpartition_selectpost_anamonpost_install_kernel_optionspost_install_network_configpost_install_network_config_debpost_koan_add_reinstall_entrypost_run_debpre_anamonpre_install_network_configpre_partition_selectpreseed_apt_repo_configproxy.xmlpuppet_install_if_enabledpuppet_register_if_enabledredhat_registerrestore_boot_devicesave_boot_devicesuse_scriptwrapper.xml` + // eslint-disable-next-line max-len + const result = ['addons.xml', 'autoinstall_done', 'autoinstall_start', 'cobbler_register', 'download_config_files', 'download_config_files_deb', 'hosts.xml', 'kdump.xml', 'keep_cfengine_keys', 'keep_files', 'keep_rhn_keys', 'keep_rudder_keys', 'keep_rudder_uuid', 'keep_ssh_host_keys', 'koan_environment', 'late_apt_repo_config', 'log_ks_post', 'log_ks_post_nochroot', 'log_ks_pre', 'main_partition_select', 'network_config', 'network_config_esx', 'network_config_esxi', 'networking.xml', 'partition_select', 'post_anamon', 'post_install_kernel_options', 'post_install_network_config', 'post_install_network_config_deb', 'post_koan_add_reinstall_entry', 'post_run_deb', 'pre_anamon', 'pre_install_network_config', 'pre_partition_select', 'preseed_apt_repo_config', 'proxy.xml', 'puppet_install_if_enabled', 'puppet_register_if_enabled', 'redhat_register', 'restore_boot_device', 'save_boot_device', 'suse_scriptwrapper.xml'] + service.get_autoinstall_snippets("").subscribe(value => { + expect(value).toEqual(result) + }); + const mockRequest = httpTestingController.expectOne('http://localhost/cobbler_api'); + mockRequest.flush(methodResponse); }); xit('should execute the is_autoinstall_in_use action on the Cobbler Server', () => { @@ -1191,34 +2167,82 @@ describe('CobblerApiService', () => { mockRequest.flush(methodResponse); }); - xit('should execute the read_autoinstall_template action on the Cobbler Server', () => { - service.read_autoinstall_template('', ''); - expect(service).toBeFalsy(); + it('should execute the read_autoinstall_template action on the Cobbler Server', (done: DoneFn) => { + // eslint-disable-next-line max-len + const methodResponse = `sample content` + const result = "sample content"; + service.read_autoinstall_template('', '').subscribe( + value => { + expect(value).toEqual(result); + done(); + }); + const mockRequest = httpTestingController.expectOne('http://localhost/cobbler_api'); + mockRequest.flush(methodResponse); }); - xit('should execute the write_autoinstall_template action on the Cobbler Server', () => { - service.write_autoinstall_template('', '', ''); - expect(service).toBeFalsy(); + it('should execute the write_autoinstall_template action on the Cobbler Server', (done: DoneFn) => { + // eslint-disable-next-line max-len + const methodResponse = `1` + const result = true; + service.write_autoinstall_template('', '', '').subscribe( + value => { + expect(value).toEqual(result); + done(); + }); + const mockRequest = httpTestingController.expectOne('http://localhost/cobbler_api'); + mockRequest.flush(methodResponse); }); - xit('should execute the remove_autoinstall_template action on the Cobbler Server', () => { - service.remove_autoinstall_template('', ''); - expect(service).toBeFalsy(); + it('should execute the remove_autoinstall_template action on the Cobbler Server', (done: DoneFn) => { + // eslint-disable-next-line max-len + const methodResponse = `1` + const result = true; + service.remove_autoinstall_template('', '').subscribe( + value => { + expect(value).toEqual(result); + done(); + }); + const mockRequest = httpTestingController.expectOne('http://localhost/cobbler_api'); + mockRequest.flush(methodResponse); }); - xit('should execute the read_autoinstall_snippet action on the Cobbler Server', () => { - service.read_autoinstall_snippet('', ''); - expect(service).toBeFalsy(); + it('should execute the read_autoinstall_snippet action on the Cobbler Server', (done: DoneFn) => { + // eslint-disable-next-line max-len + const methodResponse = `sample content` + const result = "sample content"; + service.read_autoinstall_snippet('', '',).subscribe( + value => { + expect(value).toEqual(result); + done(); + }); + const mockRequest = httpTestingController.expectOne('http://localhost/cobbler_api'); + mockRequest.flush(methodResponse); }); - xit('should execute the write_autoinstall_snippet action on the Cobbler Server', () => { - service.write_autoinstall_snippet('', '', ''); - expect(service).toBeFalsy(); + it('should execute the write_autoinstall_snippet action on the Cobbler Server', (done: DoneFn) => { + // eslint-disable-next-line max-len + const methodResponse = `1` + const result = true; + service.write_autoinstall_snippet('', '', '').subscribe( + value => { + expect(value).toEqual(result); + done(); + }); + const mockRequest = httpTestingController.expectOne('http://localhost/cobbler_api'); + mockRequest.flush(methodResponse); }); - xit('should execute the remove_autoinstall_snippet action on the Cobbler Server', () => { - service.remove_autoinstall_snippet('', ''); - expect(service).toBeFalsy(); + it('should execute the remove_autoinstall_snippet action on the Cobbler Server', (done: DoneFn) => { + // eslint-disable-next-line max-len + const methodResponse = `1` + const result = true; + service.remove_autoinstall_snippet('', '').subscribe( + value => { + expect(value).toEqual(result); + done(); + }); + const mockRequest = httpTestingController.expectOne('http://localhost/cobbler_api'); + mockRequest.flush(methodResponse); }); xit('should execute the get_config_data action on the Cobbler Server', () => { diff --git a/projects/cobbler-api/src/lib/cobbler-api.service.ts b/projects/cobbler-api/src/lib/cobbler-api.service.ts index a7e2f170..8189dd0e 100644 --- a/projects/cobbler-api/src/lib/cobbler-api.service.ts +++ b/projects/cobbler-api/src/lib/cobbler-api.service.ts @@ -454,6 +454,27 @@ export class CobblerApiService { ); } + private rebuildItem(xmlrpcStruct: XmlRpcStruct): object { + const result = {} + xmlrpcStruct.members.forEach(value => { + if (value.name === "ks_meta" || value.name === "kickstart") { + // Skip legacy keys + return; + } + if (AngularXmlrpcService.instanceOfXmlRpcArray(value.value)) { + result[value.name] = this.convertXmlRpcArrayToTypeScriptArray(value.value) + } else if (AngularXmlrpcService.instanceOfXmlRpcStruct(value.value)) { + result[value.name] = this.convertXmlRpcStructToTypeScriptObject(value.value) + } else if (value.value === "<<inherit>>") { + // FIXME: Maybe we need to XML encode this as other strings potentially also could need encoding + result[value.name] = "<>" + } else { + result[value.name] = value.value + } + }) + return result + } + // TODO: Create casting magic to output the right item type get_item(what: string, name: string, flatten: boolean = false): Observable { return this.client @@ -470,14 +491,17 @@ export class CobblerApiService { ); } - get_distro(name: string, flatten: boolean = false): Observable { + get_distro(name: string, flatten: boolean = false, resolved: boolean = false, token: string): Observable { return this.client - .methodCall('get_distro', [name, flatten]) + .methodCall('get_distro', [name, flatten, resolved, token]) .pipe( map((data: MethodResponse | MethodFault) => { if (AngularXmlrpcService.instanceOfMethodResponse(data)) { - // FIXME: Make the cast without the unknown possible - return data.value as unknown as Distro; + if (!AngularXmlrpcService.instanceOfXmlRpcStruct(data.value)) { + throw new Error("Expected XML-RPC Struct not something else!") + } + const result = this.rebuildItem(data.value) + return result as Distro; } else if (AngularXmlrpcService.instanceOfMethodFault(data)) { throw new Error('Getting the requested distro failed with code "' + data.faultCode + '" and error message "' + data.faultString + '"'); @@ -486,14 +510,17 @@ export class CobblerApiService { ); } - get_profile(name: string, flatten: boolean = false): Observable { + get_profile(name: string, flatten: boolean = false, resolved: boolean = false, token: string): Observable { return this.client - .methodCall('get_profile', [name, flatten]) + .methodCall('get_profile', [name, flatten, resolved, token]) .pipe( map((data: MethodResponse | MethodFault) => { if (AngularXmlrpcService.instanceOfMethodResponse(data)) { - // FIXME: Make the cast without the unknown possible - return data.value as unknown as Profile; + if (!AngularXmlrpcService.instanceOfXmlRpcStruct(data.value)) { + throw new Error("Expected XML-RPC Struct not something else!") + } + const result = this.rebuildItem(data.value) + return result as Profile; } else if (AngularXmlrpcService.instanceOfMethodFault(data)) { throw new Error('Getting the requested profile failed with code "' + data.faultCode + '" and error message "' + data.faultString + '"'); @@ -502,14 +529,17 @@ export class CobblerApiService { ); } - get_system(name: string, flatten: boolean = false): Observable { + get_system(name: string, flatten: boolean = false, resolved: boolean = false, token: string): Observable { return this.client - .methodCall('get_system', [name, flatten]) + .methodCall('get_system', [name, flatten, resolved, token]) .pipe( map((data: MethodResponse | MethodFault) => { if (AngularXmlrpcService.instanceOfMethodResponse(data)) { - // FIXME: Make the cast without the unknown possible - return data.value as unknown as System; + if (!AngularXmlrpcService.instanceOfXmlRpcStruct(data.value)) { + throw new Error("Expected XML-RPC Struct not something else!") + } + const result = this.rebuildItem(data.value) + return result as System; } else if (AngularXmlrpcService.instanceOfMethodFault(data)) { throw new Error('Getting the requested system failed with code "' + data.faultCode + '" and error message "' + data.faultString + '"'); @@ -518,14 +548,17 @@ export class CobblerApiService { ); } - get_repo(name: string, flatten: boolean = false): Observable { + get_repo(name: string, flatten: boolean = false, resolved: boolean = false, token: string): Observable { return this.client - .methodCall('get_repo', [name, flatten]) + .methodCall('get_repo', [name, flatten, resolved, token]) .pipe( map((data: MethodResponse | MethodFault) => { if (AngularXmlrpcService.instanceOfMethodResponse(data)) { - // FIXME: Make the cast without the unknown possible - return data.value as unknown as Repo; + if (!AngularXmlrpcService.instanceOfXmlRpcStruct(data.value)) { + throw new Error("Expected XML-RPC Struct not something else!") + } + const result = this.rebuildItem(data.value) + return result as Repo; } else if (AngularXmlrpcService.instanceOfMethodFault(data)) { throw new Error('Getting the requested repository failed with code "' + data.faultCode + '" and error message "' + data.faultString + '"'); @@ -534,14 +567,17 @@ export class CobblerApiService { ); } - get_image(name: string, flatten: boolean = false): Observable { + get_image(name: string, flatten: boolean = false, resolved: boolean = false, token: string): Observable { return this.client - .methodCall('get_repo', [name, flatten]) + .methodCall('get_image', [name, flatten, resolved, token]) .pipe( map((data: MethodResponse | MethodFault) => { if (AngularXmlrpcService.instanceOfMethodResponse(data)) { - // FIXME: Make the cast without the unknown possible - return data.value as unknown as Image; + if (!AngularXmlrpcService.instanceOfXmlRpcStruct(data.value)) { + throw new Error("Expected XML-RPC Struct not something else!") + } + const result = this.rebuildItem(data.value) + return result as Image; } else if (AngularXmlrpcService.instanceOfMethodFault(data)) { throw new Error('Getting the requested image failed with code "' + data.faultCode + '" and error message "' + data.faultString + '"'); @@ -550,14 +586,22 @@ export class CobblerApiService { ); } - get_mgmtclass(name: string, flatten: boolean = false): Observable { + get_mgmtclass( + name: string, + flatten: boolean = false, + resolved: boolean = false, + token: string + ): Observable { return this.client - .methodCall('get_repo', [name, flatten]) + .methodCall('get_mgmtclass', [name, flatten, resolved, token]) .pipe( map((data: MethodResponse | MethodFault) => { if (AngularXmlrpcService.instanceOfMethodResponse(data)) { - // FIXME: Make the cast without the unknown possible - return data.value as unknown as Mgmgtclass; + if (!AngularXmlrpcService.instanceOfXmlRpcStruct(data.value)) { + throw new Error("Expected XML-RPC Struct not something else!") + } + const result = this.rebuildItem(data.value) + return result as Mgmgtclass; } else if (AngularXmlrpcService.instanceOfMethodFault(data)) { throw new Error('Getting the requested management class failed with code "' + data.faultCode + '" and error message "' + data.faultString + '"'); @@ -566,14 +610,17 @@ export class CobblerApiService { ); } - get_package(name: string, flatten: boolean = false): Observable { + get_package(name: string, flatten: boolean = false, resolved: boolean = false, token: string): Observable { return this.client - .methodCall('get_repo', [name, flatten]) + .methodCall('get_package', [name, flatten, resolved, token]) .pipe( map((data: MethodResponse | MethodFault) => { if (AngularXmlrpcService.instanceOfMethodResponse(data)) { - // FIXME: Make the cast without the unknown possible - return data.value as unknown as Package; + if (!AngularXmlrpcService.instanceOfXmlRpcStruct(data.value)) { + throw new Error("Expected XML-RPC Struct not something else!") + } + const result = this.rebuildItem(data.value) + return result as Package; } else if (AngularXmlrpcService.instanceOfMethodFault(data)) { throw new Error('Getting the requested package failed with code "' + data.faultCode + '" and error message "' + data.faultString + '"'); @@ -582,14 +629,17 @@ export class CobblerApiService { ); } - get_file(name: string, flatten: boolean = false): Observable { + get_file(name: string, flatten: boolean = false, resolved: boolean = false, token: string): Observable { return this.client - .methodCall('get_repo', [name, flatten]) + .methodCall('get_file', [name, flatten, resolved, token]) .pipe( map((data: MethodResponse | MethodFault) => { if (AngularXmlrpcService.instanceOfMethodResponse(data)) { - // FIXME: Make the cast without the unknown possible - return data.value as unknown as File; + if (!AngularXmlrpcService.instanceOfXmlRpcStruct(data.value)) { + throw new Error("Expected XML-RPC Struct not something else!") + } + const result = this.rebuildItem(data.value) + return result as File; } else if (AngularXmlrpcService.instanceOfMethodFault(data)) { throw new Error('Getting the requested file failed with code "' + data.faultCode + '" and error message "' + data.faultString + '"'); @@ -623,8 +673,10 @@ export class CobblerApiService { .pipe( map>((data: MethodResponse | MethodFault) => { if (AngularXmlrpcService.instanceOfMethodResponse(data)) { - // FIXME: Make the cast without the unknown possible - return data.value as unknown as Array; + if (!AngularXmlrpcService.instanceOfXmlRpcArray(data.value)) { + throw new Error("Expected XML-RPC Array but got something else!") + } + return data.value.data as Array; } else if (AngularXmlrpcService.instanceOfMethodFault(data)) { throw new Error('Getting the item names failed with code "' + data.faultCode + '" and error message "' + data.faultString + '"'); @@ -639,8 +691,17 @@ export class CobblerApiService { .pipe( map>((data: MethodResponse | MethodFault) => { if (AngularXmlrpcService.instanceOfMethodResponse(data)) { - // FIXME: Make the cast without the unknown possible - return data.value as unknown as Array; + if (!AngularXmlrpcService.instanceOfXmlRpcArray(data.value)) { + throw new Error("Expected XML-RPC Array!") + } + const result = [] + data.value.data.forEach(value => { + if (!AngularXmlrpcService.instanceOfXmlRpcStruct(value)) { + throw new Error("Expected XML-RPC Struct!") + } + result.push(this.rebuildItem(value)) + }) + return result as Array; } else if (AngularXmlrpcService.instanceOfMethodFault(data)) { throw new Error('Getting all distros failed with code "' + data.faultCode + '" and error message "' + data.faultString + '"'); @@ -655,8 +716,17 @@ export class CobblerApiService { .pipe( map>((data: MethodResponse | MethodFault) => { if (AngularXmlrpcService.instanceOfMethodResponse(data)) { - // FIXME: Make the cast without the unknown possible - return data.value as unknown as Array; + if (!AngularXmlrpcService.instanceOfXmlRpcArray(data.value)) { + throw new Error("Expected XML-RPC Array!") + } + const result = [] + data.value.data.forEach(value => { + if (!AngularXmlrpcService.instanceOfXmlRpcStruct(value)) { + throw new Error("Expected XML-RPC Struct!") + } + result.push(this.rebuildItem(value)) + }) + return result as Array; } else if (AngularXmlrpcService.instanceOfMethodFault(data)) { throw new Error('Getting all profiles failed with code "' + data.faultCode + '" and error message "' + data.faultString + '"'); @@ -671,8 +741,17 @@ export class CobblerApiService { .pipe( map>((data: MethodResponse | MethodFault) => { if (AngularXmlrpcService.instanceOfMethodResponse(data)) { - // FIXME: Make the cast without the unknown possible - return data.value as unknown as Array; + if (!AngularXmlrpcService.instanceOfXmlRpcArray(data.value)) { + throw new Error("Expected XML-RPC Array!") + } + const result = [] + data.value.data.forEach(value => { + if (!AngularXmlrpcService.instanceOfXmlRpcStruct(value)) { + throw new Error("Expected XML-RPC Struct!") + } + result.push(this.rebuildItem(value)) + }) + return result as Array; } else if (AngularXmlrpcService.instanceOfMethodFault(data)) { throw new Error('Getting the systems failed with code "' + data.faultCode + '" and error message "' + data.faultString + '"'); @@ -687,8 +766,17 @@ export class CobblerApiService { .pipe( map>((data: MethodResponse | MethodFault) => { if (AngularXmlrpcService.instanceOfMethodResponse(data)) { - // FIXME: Make the cast without the unknown possible - return data.value as unknown as Array; + if (!AngularXmlrpcService.instanceOfXmlRpcArray(data.value)) { + throw new Error("Expected XML-RPC Array!") + } + const result = [] + data.value.data.forEach(value => { + if (!AngularXmlrpcService.instanceOfXmlRpcStruct(value)) { + throw new Error("Expected XML-RPC Struct!") + } + result.push(this.rebuildItem(value)) + }) + return result as Array; } else if (AngularXmlrpcService.instanceOfMethodFault(data)) { throw new Error('Getting the repositories failed with code "' + data.faultCode + '" and error message "' + data.faultString + '"'); @@ -703,8 +791,17 @@ export class CobblerApiService { .pipe( map>((data: MethodResponse | MethodFault) => { if (AngularXmlrpcService.instanceOfMethodResponse(data)) { - // FIXME: Make the cast without the unknown possible - return data.value as unknown as Array; + if (!AngularXmlrpcService.instanceOfXmlRpcArray(data.value)) { + throw new Error("Expected XML-RPC Array!") + } + const result = [] + data.value.data.forEach(value => { + if (!AngularXmlrpcService.instanceOfXmlRpcStruct(value)) { + throw new Error("Expected XML-RPC Struct!") + } + result.push(this.rebuildItem(value)) + }) + return result as Array; } else if (AngularXmlrpcService.instanceOfMethodFault(data)) { throw new Error('Getting the images failed with code "' + data.faultCode + '" and error message "' + data.faultString + '"'); @@ -719,8 +816,17 @@ export class CobblerApiService { .pipe( map>((data: MethodResponse | MethodFault) => { if (AngularXmlrpcService.instanceOfMethodResponse(data)) { - // FIXME: Make the cast without the unknown possible - return data.value as unknown as Array; + if (!AngularXmlrpcService.instanceOfXmlRpcArray(data.value)) { + throw new Error("Expected XML-RPC Array!") + } + const result = [] + data.value.data.forEach(value => { + if (!AngularXmlrpcService.instanceOfXmlRpcStruct(value)) { + throw new Error("Expected XML-RPC Struct!") + } + result.push(this.rebuildItem(value)) + }) + return result as Array; } else if (AngularXmlrpcService.instanceOfMethodFault(data)) { throw new Error('Getting the management classes failed with code "' + data.faultCode + '" and error message "' + data.faultString + '"'); @@ -735,8 +841,17 @@ export class CobblerApiService { .pipe( map>((data: MethodResponse | MethodFault) => { if (AngularXmlrpcService.instanceOfMethodResponse(data)) { - // FIXME: Make the cast without the unknown possible - return data.value as unknown as Array; + if (!AngularXmlrpcService.instanceOfXmlRpcArray(data.value)) { + throw new Error("Expected XML-RPC Array!") + } + const result = [] + data.value.data.forEach(value => { + if (!AngularXmlrpcService.instanceOfXmlRpcStruct(value)) { + throw new Error("Expected XML-RPC Struct!") + } + result.push(this.rebuildItem(value)) + }) + return result as Array; } else if (AngularXmlrpcService.instanceOfMethodFault(data)) { throw new Error('Getting the packages failed with code "' + data.faultCode + '" and error message "' + data.faultString + '"'); @@ -751,8 +866,17 @@ export class CobblerApiService { .pipe( map>((data: MethodResponse | MethodFault) => { if (AngularXmlrpcService.instanceOfMethodResponse(data)) { - // FIXME: Make the cast without the unknown possible - return data.value as unknown as Array; + if (!AngularXmlrpcService.instanceOfXmlRpcArray(data.value)) { + throw new Error("Expected XML-RPC Array!") + } + const result = [] + data.value.data.forEach(value => { + if (!AngularXmlrpcService.instanceOfXmlRpcStruct(value)) { + throw new Error("Expected XML-RPC Struct!") + } + result.push(this.rebuildItem(value)) + }) + return result as Array; } else if (AngularXmlrpcService.instanceOfMethodFault(data)) { throw new Error('Getting the files failed with code "' + data.faultCode + '" and error message "' + data.faultString + '"'); @@ -1948,13 +2072,16 @@ export class CobblerApiService { ); } - get_autoinstall_templates(token: string): Observable> { + get_autoinstall_templates(token: string): Observable> { return this.client .methodCall('get_autoinstall_templates', [token]) .pipe( map>((data: MethodResponse | MethodFault) => { if (AngularXmlrpcService.instanceOfMethodResponse(data)) { - return data.value as unknown as Array; + if (!AngularXmlrpcService.instanceOfXmlRpcArray(data.value)) { + throw new Error("Exepcted XML-RPC Array!") + } + return this.convertXmlRpcArrayToTypeScriptArray(data.value); } else if (AngularXmlrpcService.instanceOfMethodFault(data)) { throw new Error('Getting the requested auto-installation templates failed with code "' + data.faultCode + '" and error message "' + data.faultString + '"'); @@ -1963,13 +2090,16 @@ export class CobblerApiService { ); } - get_autoinstall_snippets(token: string): Observable> { + get_autoinstall_snippets(token: string): Observable> { return this.client - .methodCall('get_autoinstall_templates', [token]) + .methodCall('get_autoinstall_snippets', [token]) .pipe( map>((data: MethodResponse | MethodFault) => { if (AngularXmlrpcService.instanceOfMethodResponse(data)) { - return data.value as unknown as Array; + if (!AngularXmlrpcService.instanceOfXmlRpcArray(data.value)) { + throw new Error("Expected XML-RPC Array!") + } + return this.convertXmlRpcArrayToTypeScriptArray(data.value); } else if (AngularXmlrpcService.instanceOfMethodFault(data)) { throw new Error('Getting the requested auto-installation snippets failed with code "' + data.faultCode + '" and error message "' + data.faultString + '"'); @@ -2106,6 +2236,9 @@ export class CobblerApiService { value = this.convertXmlRpcArrayToTypeScriptArray(member.value); } else if (AngularXmlrpcService.instanceOfXmlRpcStruct(member.value)) { value = this.convertXmlRpcStructToTypeScriptObject(member.value); + } else if (member.value === "<<inherit>>") { + // FIXME: Maybe we need to XML encode this as other strings potentially also could need encoding + value = "<>" } else { value = member.value; } @@ -2121,6 +2254,9 @@ export class CobblerApiService { resultArray.push(this.convertXmlRpcArrayToTypeScriptArray(value)); } else if (AngularXmlrpcService.instanceOfXmlRpcStruct(value)) { resultArray.push(this.convertXmlRpcStructToTypeScriptObject(value)); + } else if (value === "<<inherit>>") { + // FIXME: Maybe we need to XML encode this as other strings potentially also could need encoding + resultArray.push("<>") } else { resultArray.push(value); } diff --git a/projects/cobbler-api/src/lib/custom-types/items.ts b/projects/cobbler-api/src/lib/custom-types/items.ts index 76efed68..c6206c5c 100644 --- a/projects/cobbler-api/src/lib/custom-types/items.ts +++ b/projects/cobbler-api/src/lib/custom-types/items.ts @@ -6,90 +6,129 @@ export interface Item { } export interface Distro extends Item { - source_repos: Array; - tree_build_time: string; + is_subobject: boolean; + source_repos: Array; + tree_build_time: number; arch: string; autoinstall_meta: object; - boot_files: Array; - boot_loader: string; + boot_files: string | object; + boot_loaders: string | Array; breed: string; comment: string; - fetchable_files: Array; + parent: string; + fetchable_files: string | object; initrd: string; kernel: string; remote_boot_initrd: string; remote_boot_kernel: string; - kernel_options: object; - kernel_options_post: object; - mgmt_classes: Array; + remote_grub_initrd: string; + remote_grub_kernel: string; + kernel_options: string | object; + kernel_options_post: string | object; + mgmt_classes: string | Array; + mgmt_parameters: object | string; name: string; os_version: string; - owners: Array; + owners: string | Array; redhat_management_key: string; template_files: object; } export interface Profile extends Item { + is_subobject: boolean; + boot_loaders: string | Array; autoinstall: string; - autoinstall_meta: object; - boot_files: Array; + autoinstall_meta: string | object; + boot_files: string | Array; comment: string; dhcp_tag: string; distro: string; - enable_gpxe: boolean; - enable_menu: boolean; - fetchable_files: object; - kernel_options: object; - kernel_options_post: object; - mgmt_classes: Array; - mgmt_parameters: string; + enable_ipxe: string | boolean; + enable_menu: string | boolean; + menu: string, + fetchable_files: string | object; + kernel_options: string | object; + kernel_options_post: string | object; + mgmt_classes: string | Array; + mgmt_parameters: object | string; name: string; name_servers: Array; name_servers_search: Array; - next_server: string; + next_server_v4: string; + next_server_v6: string; filename: string; - owners: Array; + owners: string | Array; parent: string; proxy: string; redhat_management_key: string; repos: Array; server: string; template_files: object; - virt_auto_boot: boolean; + virt_auto_boot: string | boolean; virt_bridge: string; - virt_cpus: number; + virt_cpus: string | number; virt_disk_driver: string; - virt_file_size: number; + virt_file_size: string | number; virt_path: string; - virt_ram: number; + virt_ram: string | number; virt_type: string; } +export interface NetworkInterface { + bonding_opts: string; + bridge_opts: string; + cnames: Array; + connected_mode: false, + dhcp_tag: string; + dns_name: string; + if_gateway: string; + interface_master: string; + interface_type: string; + ip_address: string; + ipv6_address: string; + ipv6_default_gateway: string; + ipv6_mtu: string; + ipv6_prefix: string; + ipv6_secondaries: Array; + ipv6_static_routes: Array; + mac_address: string; + management: boolean; + mtu: string; + netmask: string; + static: boolean; + static_routes: Array; + virt_bridge: string; +} + export interface System extends Item { ipv6_autoconfiguration: boolean; - repos_enabled: false; + repos_enabled: boolean; autoinstall: string; - autoinstall_meta: object; - boot_files: Array; - boot_loader: string; + interfaces: { [k: string]: NetworkInterface }; + autoinstall_meta: string | object; + boot_files: string | Array; + boot_loaders: string | Array; comment: string; - enable_ipxe: boolean; - fetchable_files: object; + parent: string; + is_subobject: boolean; + enable_ipxe: string | boolean; + fetchable_files: string | object; gateway: string; hostname: string; image: string; ipv6_default_device: string; - kernel_options: object; - kernel_options_post: object; - mgmt_classes: Array; - mgmt_parameters: string; + kernel_options: string | object; + kernel_options_post: string | object; + mgmt_classes: string | Array; + mgmt_parameters: object | string; name: string; name_servers: Array; name_servers_search: Array; netboot_enabled: boolean; - next_server: string; + next_server_v4: string; + next_server_v6: string; filename: string; - owners: Array; + owners: string | Array; power_address: string; power_id: string; power_pass: string; @@ -103,33 +142,45 @@ export interface System extends Item { server: string; status: string; template_files: object; - virt_auto_boot: boolean; - virt_cpus: number; + virt_auto_boot: string | boolean; + virt_cpus: string | number; virt_disk_driver: string; - virt_file_size: number; + virt_file_size: string | number; virt_path: string; virt_pxe_boot: boolean; - virt_ram: number; + virt_ram: string | number; virt_type: string; serial_device: number; serial_baud_rate: number; } export interface Repo extends Item { + // Base Item attributes (we actually don't want them) + kernel_options: string | object; + kernel_options_post: string | object; + mgmt_classes: string | Array; + mgmt_parameters: object | string; + is_subobject: boolean; + fetchable_files: string | object; + autoinstall_meta: object; + boot_files: string | object; + template_files: object; + os_version: string; + // Real attributes parent: string; apt_components: Array; apt_dists: Array; arch: string; breed: string; comment: string; - createrepo_flags: object; + createrepo_flags: string; environment: object; keep_updated: boolean; mirror: string; mirror_type: string; mirror_locally: boolean; name: string; - owners: Array; + owners: string | Array; priority: number; proxy: string; rpm_list: Array; @@ -138,6 +189,18 @@ export interface Repo extends Item { } export interface File extends Item { + // Base Item attributes (we actually don't want them) + kernel_options: string | object; + kernel_options_post: string | object; + mgmt_classes: string | Array; + mgmt_parameters: object | string; + is_subobject: boolean; + fetchable_files: string | object; + parent: string; + autoinstall_meta: object; + boot_files: string | object; + template_files: object; + // Real attributes action: string; comment: string; group: string; @@ -145,12 +208,25 @@ export interface File extends Item { mode: string; name: string; owner: string; - owners: Array; + owners: string | Array; path: string; template: string; } export interface Image extends Item { + // Base Item attributes (we actually don't want them) + kernel_options: string | object; + kernel_options_post: string | object; + mgmt_classes: string | Array; + mgmt_parameters: object | string; + is_subobject: boolean; + fetchable_files: string | object; + autoinstall_meta: string | object; + boot_files: string | object; + template_files: object; + boot_loaders: string | Array; + menu: string; + // Real attributes parent: string; arch: string; autoinstall: string; @@ -161,33 +237,62 @@ export interface Image extends Item { name: string; network_count: number; os_version: string; - owners: Array; - virt_auto_boot: boolean; + owners: string | Array; + virt_auto_boot: string | boolean; virt_bridge: string; - virt_cpus: number; + virt_cpus: string | number; virt_disk_driver: string; - virt_file_size: number; + virt_file_size: string | number; virt_path: string; - virt_ram: number; + virt_ram: string | number; virt_type: string; } export interface Mgmgtclass extends Item { + // Base Item attributes (we actually don't want them) + parent: string; + kernel_options: string | object; + kernel_options_post: string | object; + mgmt_classes: string | Array; + mgmt_parameters: object | string; + is_subobject: boolean; + fetchable_files: string | object; + autoinstall_meta: object; + boot_files: string | object; + template_files: object; + // Real attributes is_definition: boolean; class_name: string; comment: string; files: Array; name: string; - owners: Array; + owners: string | Array; packages: Array; params: object; } export interface Package extends Item { + // Base Item attributes (we actually don't want them) + parent: string; + kernel_options: string | object; + kernel_options_post: string | object; + mgmt_classes: string | Array; + mgmt_parameters: object | string; + is_subobject: boolean; + fetchable_files: string | object; + autoinstall_meta: object; + boot_files: string | object; + template_files: object; + // Real attributes + mode: string; + owner: string; + group: string; + path: string; + template: string; action: string; comment: string; installer: string; name: string; - owners: Array; + owners: string | Array; version: string; } diff --git a/projects/cobbler-frontend/src/app/actions/check-sys/check-sys.component.css b/projects/cobbler-frontend/src/app/actions/check-sys/check-sys.component.scss similarity index 100% rename from projects/cobbler-frontend/src/app/actions/check-sys/check-sys.component.css rename to projects/cobbler-frontend/src/app/actions/check-sys/check-sys.component.scss diff --git a/projects/cobbler-frontend/src/app/actions/check-sys/check-sys.component.ts b/projects/cobbler-frontend/src/app/actions/check-sys/check-sys.component.ts index 64f365c3..7bafa129 100644 --- a/projects/cobbler-frontend/src/app/actions/check-sys/check-sys.component.ts +++ b/projects/cobbler-frontend/src/app/actions/check-sys/check-sys.component.ts @@ -14,7 +14,7 @@ import {UserService} from '../../services/user.service'; @Component({ selector: 'cobbler-check-sys', templateUrl: './check-sys.component.html', - styleUrls: ['./check-sys.component.css'], + styleUrls: ['./check-sys.component.scss'], standalone: true, imports: [ RouterOutlet, diff --git a/projects/cobbler-frontend/src/app/app-routing.module.ts b/projects/cobbler-frontend/src/app/app-routing.module.ts index f2f4aff7..0637e6db 100644 --- a/projects/cobbler-frontend/src/app/app-routing.module.ts +++ b/projects/cobbler-frontend/src/app/app-routing.module.ts @@ -11,16 +11,26 @@ import { SyncComponent } from './actions/sync/sync.component'; import {ValidateAutoinstallsComponent} from './actions/validate-autoinstalls/validate-autoinstalls.component'; import { AppEventsComponent } from './app-events/app-events.component'; import { AppManageComponent } from './appManage'; -import { DistrosComponent } from './items/distros/distros.component'; -import { FilesComponent } from './items/files/files.component'; -import { ImagesComponent } from './items/images/images.component'; -import { ManagementClassesComponent } from './items/management-classes/management-classes.component'; -import { PackagesComponent } from './items/packages/packages.component'; -import { ProfilesComponent } from './items/profiles/profiles.component'; -import { ReposComponent } from './items/repos/repos.component'; -import { SnippetsComponent } from './items/snippets/snippets.component'; -import { SystemsComponent } from './items/systems/systems.component'; -import { TemplatesComponent } from './items/templates/templates.component'; +import {DistroEditComponent} from './items/distro/edit/distro-edit.component'; +import { DistrosOverviewComponent } from './items/distro/overview/distros-overview.component'; +import {FileEditComponent} from './items/file/edit/file-edit.component'; +import { FileOverviewComponent } from './items/file/overview/file-overview.component'; +import {ImageEditComponent} from './items/image/edit/image-edit.component'; +import { ImageOverviewComponent } from './items/image/overview/image-overview.component'; +import {ManagementClassEditComponent} from './items/management-class/edit/management-class-edit.component'; +import {ManagementClassOverviewComponent} from './items/management-class/overview/management-class-overview.component'; +import {PackageEditComponent} from './items/package/edit/package-edit.component'; +import { PackageOverviewComponent } from './items/package/overview/package-overview.component'; +import {ProfileEditComponent} from './items/profile/edit/profile-edit.component'; +import { ProfileOverviewComponent } from './items/profile/overview/profile-overview.component'; +import {RepositoryEditComponent} from './items/repository/edit/repository-edit.component'; +import { RepositoryOverviewComponent } from './items/repository/overview/repository-overview.component'; +import {SnippetEditComponent} from './items/snippet/edit/snippet-edit.component'; +import { SnippetOverviewComponent } from './items/snippet/overview/snippet-overview.component'; +import {SystemEditComponent} from './items/system/edit/system-edit.component'; +import { SystemOverviewComponent } from './items/system/overview/system-overview.component'; +import {TemplateEditComponent} from './items/template/edit/template-edit.component'; +import { TemplateOverviewComponent } from './items/template/overview/template-overview.component'; import { LogInFormComponent } from './login/login.component'; import { NotFoundComponent } from './not-found/not-found.component'; import { AuthGuardService } from './services/auth-guard.service'; @@ -36,17 +46,92 @@ export const routes: Routes = [ {path: '', pathMatch: 'full', redirectTo: '/login' }, {path: 'unauthorized', component: UnauthorizedComponent}, {path: 'manage', component: AppManageComponent, canActivate: [AuthGuardService]}, - {path: 'distros', component: DistrosComponent, canActivate: [AuthGuardService]}, - {path: 'profiles', component: ProfilesComponent, canActivate: [AuthGuardService]}, - {path: 'systems', component: SystemsComponent, canActivate: [AuthGuardService]}, - {path: 'repos', component: ReposComponent, canActivate: [AuthGuardService]}, - {path: 'images', component: ImagesComponent, canActivate: [AuthGuardService]}, - {path: 'templates', component: TemplatesComponent, canActivate: [AuthGuardService]}, - {path: 'snippets', component: SnippetsComponent, canActivate: [AuthGuardService]}, - {path: 'management-classes', component: ManagementClassesComponent, canActivate: [AuthGuardService]}, + { + path: 'items', + children: [ + { + path: 'distro', + component: DistrosOverviewComponent, + canActivate: [AuthGuardService], + children: [ + {path: ':name', component: DistroEditComponent, canActivate: [AuthGuardService]}, + ] + }, + { + path: 'profile', + component: ProfileOverviewComponent, + canActivate: [AuthGuardService], + children: [ + {path: ':name', component: ProfileEditComponent, canActivate: [AuthGuardService]}, + ] + }, + { + path: 'system', + component: SystemOverviewComponent, + canActivate: [AuthGuardService], + children: [ + {path: ':name', component: SystemEditComponent, canActivate: [AuthGuardService]}, + ] + }, + { + path: 'repository', + component: RepositoryOverviewComponent, + canActivate: [AuthGuardService], + children: [ + {path: ':name', component: RepositoryEditComponent, canActivate: [AuthGuardService]}, + ] + }, + { + path: 'image', + component: ImageOverviewComponent, + canActivate: [AuthGuardService], + children: [ + {path: ':name', component: ImageEditComponent, canActivate: [AuthGuardService]}, + ] + }, + { + path: 'template', + component: TemplateOverviewComponent, + canActivate: [AuthGuardService], + children: [ + {path: ':name', component: TemplateEditComponent, canActivate: [AuthGuardService]}, + ] + }, + { + path: 'snippet', + component: SnippetOverviewComponent, + canActivate: [AuthGuardService], + children: [ + {path: ':name', component: SnippetEditComponent, canActivate: [AuthGuardService]}, + ] + }, + { + path: 'management-class', + component: ManagementClassOverviewComponent, + canActivate: [AuthGuardService], + children: [ + {path: ':name', component: ManagementClassEditComponent, canActivate: [AuthGuardService]}, + ] + }, + { + path: 'package', + component: PackageOverviewComponent, + canActivate: [AuthGuardService], + children: [ + {path: ':name', component: PackageEditComponent, canActivate: [AuthGuardService]}, + ] + }, + { + path: 'file', + component: FileOverviewComponent, + canActivate: [AuthGuardService], + children: [ + {path: ':name', component: FileEditComponent, canActivate: [AuthGuardService]}, + ] + }, + ] + }, {path: 'settings', component: SettingsViewComponent, canActivate: [AuthGuardService]}, - {path: 'packages', component: PackagesComponent, canActivate: [AuthGuardService]}, - {path: 'app-files', component: FilesComponent, canActivate: [AuthGuardService]}, {path: 'import', component: ImportDVDComponent, canActivate: [AuthGuardService]}, {path: 'sync', component: SyncComponent, canActivate: [AuthGuardService]}, {path: 'reposync', component: RepoSyncComponent, canActivate: [AuthGuardService]}, diff --git a/projects/cobbler-frontend/src/app/common/dialog-text-input/dialog-text-input.component.html b/projects/cobbler-frontend/src/app/common/dialog-text-input/dialog-text-input.component.html new file mode 100644 index 00000000..793ab6c5 --- /dev/null +++ b/projects/cobbler-frontend/src/app/common/dialog-text-input/dialog-text-input.component.html @@ -0,0 +1,11 @@ +

Add new Option:

+ + + New Option + + + + + + + diff --git a/projects/cobbler-frontend/src/app/items/distros/distros.component.css b/projects/cobbler-frontend/src/app/common/dialog-text-input/dialog-text-input.component.scss similarity index 100% rename from projects/cobbler-frontend/src/app/items/distros/distros.component.css rename to projects/cobbler-frontend/src/app/common/dialog-text-input/dialog-text-input.component.scss diff --git a/projects/cobbler-frontend/src/app/common/dialog-text-input/dialog-text-input.component.spec.ts b/projects/cobbler-frontend/src/app/common/dialog-text-input/dialog-text-input.component.spec.ts new file mode 100644 index 00000000..4fda9a8d --- /dev/null +++ b/projects/cobbler-frontend/src/app/common/dialog-text-input/dialog-text-input.component.spec.ts @@ -0,0 +1,39 @@ +import { ComponentFixture, TestBed } from '@angular/core/testing'; +import {MAT_DIALOG_DATA, MatDialogModule, MatDialogRef} from '@angular/material/dialog'; +import {NoopAnimationsModule} from '@angular/platform-browser/animations'; + +import { DialogTextInputComponent } from './dialog-text-input.component'; + +describe('DialogTextInputComponent', () => { + let component: DialogTextInputComponent; + let fixture: ComponentFixture; + + beforeEach(async () => { + await TestBed.configureTestingModule({ + imports: [ + DialogTextInputComponent, + MatDialogModule, + NoopAnimationsModule, + ], + providers: [ + { + provide: MatDialogRef, + useValue: {} + }, + { + provide: MAT_DIALOG_DATA, + useValue: {text: ""} + } + ] + }) + .compileComponents(); + + fixture = TestBed.createComponent(DialogTextInputComponent); + component = fixture.componentInstance; + fixture.detectChanges(); + }); + + it('should create', () => { + expect(component).toBeTruthy(); + }); +}); diff --git a/projects/cobbler-frontend/src/app/common/dialog-text-input/dialog-text-input.component.ts b/projects/cobbler-frontend/src/app/common/dialog-text-input/dialog-text-input.component.ts new file mode 100644 index 00000000..5c4fc9ee --- /dev/null +++ b/projects/cobbler-frontend/src/app/common/dialog-text-input/dialog-text-input.component.ts @@ -0,0 +1,45 @@ +import {Component, inject, model} from '@angular/core'; +import {FormsModule} from '@angular/forms'; +import {MatButton} from '@angular/material/button'; +import { + MAT_DIALOG_DATA, + MatDialogActions, + MatDialogClose, + MatDialogContent, MatDialogRef, + MatDialogTitle +} from '@angular/material/dialog'; +import {MatFormField, MatLabel} from '@angular/material/form-field'; +import {MatInput} from '@angular/material/input'; + +export interface DialogTextInputData { + text: string; +} + + +@Component({ + selector: 'cobbler-dialog-text-input', + standalone: true, + imports: [ + MatDialogContent, + MatDialogTitle, + MatFormField, + MatDialogActions, + MatButton, + MatDialogClose, + MatInput, + MatLabel, + FormsModule, + ], + templateUrl: './dialog-text-input.component.html', + styleUrl: './dialog-text-input.component.scss' +}) +export class DialogTextInputComponent { + readonly dialogRef = inject(MatDialogRef); + readonly data = inject(MAT_DIALOG_DATA); + readonly dialogCloseSignal = model(this.data.text) + + onNoClick(): void { + this.dialogRef.close(); + } + +} diff --git a/projects/cobbler-frontend/src/app/common/key-value-editor/key-value-editor.component.html b/projects/cobbler-frontend/src/app/common/key-value-editor/key-value-editor.component.html new file mode 100644 index 00000000..8ffd05f4 --- /dev/null +++ b/projects/cobbler-frontend/src/app/common/key-value-editor/key-value-editor.component.html @@ -0,0 +1,24 @@ + + + {{label}} + + @if (Object.keys(this.keyValueOptions).length === 0) { +

Empty list of options

+ } @else { +
+ @for (key of keyOrder; track key) { +
+ + + +  =  + + + + + +
+ } +
+ } +
diff --git a/projects/cobbler-frontend/src/app/common/key-value-editor/key-value-editor.component.scss b/projects/cobbler-frontend/src/app/common/key-value-editor/key-value-editor.component.scss new file mode 100644 index 00000000..ee119b33 --- /dev/null +++ b/projects/cobbler-frontend/src/app/common/key-value-editor/key-value-editor.component.scss @@ -0,0 +1,51 @@ +.example-list { + width: 80%; + max-width: 100%; + border: solid 1px #ccc; + min-height: 60px; + display: block; + background: white; + border-radius: 4px; + overflow: hidden; +} + +.example-box { + margin: 20px 10px; + padding: 10px; + border: solid 1px #ccc; + color: rgba(0, 0, 0, 0.87); + display: flex; + flex-direction: row; + align-items: center; + justify-content: space-between; + box-sizing: border-box; + cursor: move; + background: white; + font-size: 14px; +} + +.cdk-drag-preview { + border: none; + box-sizing: border-box; + border-radius: 4px; + box-shadow: 0 5px 5px -3px rgba(0, 0, 0, 0.2), + 0 8px 10px 1px rgba(0, 0, 0, 0.14), + 0 3px 14px 2px rgba(0, 0, 0, 0.12); +} + +.cdk-drag-placeholder { + opacity: 0; +} + +.cdk-drag-animating { + transition: transform 250ms cubic-bezier(0, 0, 0.2, 1); +} + +.example-box:last-child { + border: none; +} + +.example-list.cdk-drop-list-dragging .example-box:not(.cdk-drag-placeholder) { + transition: transform 250ms cubic-bezier(0, 0, 0.2, 1); +} + diff --git a/projects/cobbler-frontend/src/app/common/key-value-editor/key-value-editor.component.spec.ts b/projects/cobbler-frontend/src/app/common/key-value-editor/key-value-editor.component.spec.ts new file mode 100644 index 00000000..9d13fe28 --- /dev/null +++ b/projects/cobbler-frontend/src/app/common/key-value-editor/key-value-editor.component.spec.ts @@ -0,0 +1,23 @@ +import { ComponentFixture, TestBed } from '@angular/core/testing'; + +import { KeyValueEditorComponent } from './key-value-editor.component'; + +describe('KeyValueEditorComponent', () => { + let component: KeyValueEditorComponent; + let fixture: ComponentFixture; + + beforeEach(async () => { + await TestBed.configureTestingModule({ + imports: [KeyValueEditorComponent] + }) + .compileComponents(); + + fixture = TestBed.createComponent(KeyValueEditorComponent); + component = fixture.componentInstance; + fixture.detectChanges(); + }); + + it('should create', () => { + expect(component).toBeTruthy(); + }); +}); diff --git a/projects/cobbler-frontend/src/app/common/key-value-editor/key-value-editor.component.ts b/projects/cobbler-frontend/src/app/common/key-value-editor/key-value-editor.component.ts new file mode 100644 index 00000000..8f9c72a7 --- /dev/null +++ b/projects/cobbler-frontend/src/app/common/key-value-editor/key-value-editor.component.ts @@ -0,0 +1,110 @@ +import {CdkDrag, CdkDragDrop, CdkDropList, moveItemInArray} from '@angular/cdk/drag-drop'; +import {Component, Input, OnInit} from '@angular/core'; +import { + AbstractControl, + ControlValueAccessor, FormControl, FormGroup, + NG_VALIDATORS, + NG_VALUE_ACCESSOR, ReactiveFormsModule, + ValidationErrors, + Validator +} from '@angular/forms'; +import {MatIconButton} from '@angular/material/button'; +import {MatCard, MatCardHeader, MatCardTitle} from '@angular/material/card'; +import {MatFormField} from '@angular/material/form-field'; +import {MatIcon} from '@angular/material/icon'; +import {MatInput} from '@angular/material/input'; + +@Component({ + selector: 'cobbler-key-value-editor', + standalone: true, + imports: [ + MatCard, + MatCardHeader, + MatCardTitle, + CdkDropList, + CdkDrag, + MatFormField, + MatInput, + MatIconButton, + MatIcon, + ReactiveFormsModule, + ], + providers: [ + { + provide: NG_VALUE_ACCESSOR, + multi: true, + useExisting: KeyValueEditorComponent, + }, + { + provide: NG_VALIDATORS, + multi: true, + useExisting: KeyValueEditorComponent + }, + ], + templateUrl: './key-value-editor.component.html', + styleUrl: './key-value-editor.component.scss' +}) +export class KeyValueEditorComponent implements ControlValueAccessor, Validator{ + @Input() label = ""; + @Input() keyValueOptions = {} + onChange = (options: string[]) => {}; + onTouched = (options: string[]) => {}; + keyOrder = Object.keys(this.keyValueOptions); + keyOrderFormGroup = new FormGroup({}) + isDisabled = true; + + registerOnChange(fn: any): void { + this.onChange = fn; + } + + registerOnTouched(fn: any): void { + this.onTouched = fn; + } + + registerOnValidatorChange(fn: () => void): void { + } + + setDisabledState(isDisabled: boolean): void { + this.isDisabled = isDisabled; + this.setFormGroupDisabledState(isDisabled) + } + + setFormGroupDisabledState(isDisabled: boolean): void { + if (isDisabled) { + this.keyOrderFormGroup.disable(); + } else { + this.keyOrderFormGroup.enable(); + } + } + + validate(control: AbstractControl): ValidationErrors | null { + return undefined; + } + + writeValue(obj: any): void { + this.keyValueOptions = obj + this.keyOrder = Object.keys(this.keyValueOptions); + this.buildFormGroup() + } + + buildFormGroup(): void { + for (let key of this.keyOrder) { + const formGroupControls = { + key: new FormControl({value: key, disabled: true}), + value: new FormControl({value: this.keyValueOptions[key], disabled: true}), + } + this.keyOrderFormGroup.addControl(key + "FormGroup", new FormGroup(formGroupControls)) + } + this.setFormGroupDisabledState(this.isDisabled) + } + + deleteKey(key: string): void { + // TODO: Delete key + } + + drop(event: CdkDragDrop) { + moveItemInArray(this.keyOrder, event.previousIndex, event.currentIndex); + } + + protected readonly Object = Object; +} diff --git a/projects/cobbler-frontend/src/app/common/multi-select/multi-select.component.html b/projects/cobbler-frontend/src/app/common/multi-select/multi-select.component.html new file mode 100644 index 00000000..af674549 --- /dev/null +++ b/projects/cobbler-frontend/src/app/common/multi-select/multi-select.component.html @@ -0,0 +1,19 @@ + + + {{label}} + + @if (multiSelectOptions.length === 0) { +

Empty list of options

+ } @else { + + + {{option}} + + } + +
diff --git a/projects/cobbler-frontend/src/app/items/images/images.component.css b/projects/cobbler-frontend/src/app/common/multi-select/multi-select.component.scss similarity index 100% rename from projects/cobbler-frontend/src/app/items/images/images.component.css rename to projects/cobbler-frontend/src/app/common/multi-select/multi-select.component.scss diff --git a/projects/cobbler-frontend/src/app/common/multi-select/multi-select.component.spec.ts b/projects/cobbler-frontend/src/app/common/multi-select/multi-select.component.spec.ts new file mode 100644 index 00000000..a3dfb41a --- /dev/null +++ b/projects/cobbler-frontend/src/app/common/multi-select/multi-select.component.spec.ts @@ -0,0 +1,23 @@ +import { ComponentFixture, TestBed } from '@angular/core/testing'; + +import { MultiSelectComponent } from './multi-select.component'; + +describe('MultiSelectComponent', () => { + let component: MultiSelectComponent; + let fixture: ComponentFixture; + + beforeEach(async () => { + await TestBed.configureTestingModule({ + imports: [MultiSelectComponent] + }) + .compileComponents(); + + fixture = TestBed.createComponent(MultiSelectComponent); + component = fixture.componentInstance; + fixture.detectChanges(); + }); + + it('should create', () => { + expect(component).toBeTruthy(); + }); +}); diff --git a/projects/cobbler-frontend/src/app/common/multi-select/multi-select.component.ts b/projects/cobbler-frontend/src/app/common/multi-select/multi-select.component.ts new file mode 100644 index 00000000..08cec709 --- /dev/null +++ b/projects/cobbler-frontend/src/app/common/multi-select/multi-select.component.ts @@ -0,0 +1,145 @@ +import {AsyncPipe, NgForOf} from '@angular/common'; +import {ChangeDetectionStrategy, Component, forwardRef, inject, Input, OnInit, signal} from '@angular/core'; +import { + AbstractControl, + ControlValueAccessor, + FormControl, FormGroup, NG_VALIDATORS, NG_VALUE_ACCESSOR, + ReactiveFormsModule, + ValidationErrors, + Validator +} from '@angular/forms'; +import {MatButton, MatFabButton, MatIconButton} from '@angular/material/button'; +import {MatCard, MatCardHeader, MatCardTitle} from '@angular/material/card'; +import {MatCheckbox, MatCheckboxChange} from '@angular/material/checkbox'; +import {MatDialog} from '@angular/material/dialog'; +import {MatFormFieldModule, MatLabel} from '@angular/material/form-field'; +import {MatIcon} from '@angular/material/icon'; +import {MatInput} from '@angular/material/input'; +import {MatListItem} from '@angular/material/list'; +import {MatOption, MatSelectModule} from '@angular/material/select'; +import {DialogTextInputComponent} from '../dialog-text-input/dialog-text-input.component'; + + + +@Component({ + selector: 'cobbler-multi-select', + standalone: true, + imports: [ + MatFormFieldModule, + MatSelectModule, + MatOption, + MatLabel, + ReactiveFormsModule, + AsyncPipe, + MatListItem, + NgForOf, + MatCheckbox, + MatButton, + MatIconButton, + MatIcon, + MatCard, + MatCardHeader, + MatCardTitle, + MatFabButton, + MatInput, + ], + providers: [ + { + provide: NG_VALUE_ACCESSOR, + multi: true, + useExisting: MultiSelectComponent, + }, + { + provide: NG_VALIDATORS, + multi: true, + useExisting: MultiSelectComponent + } + ], + templateUrl: './multi-select.component.html', + styleUrl: './multi-select.component.scss' +}) +export class MultiSelectComponent implements OnInit, ControlValueAccessor, Validator { + @Input() multiSelectOptions: Array = []; + @Input() label = ""; + matSelectOptionsFormGroup: FormGroup<{}> = new FormGroup({}) + onChange = (options: string[]) => {}; + onTouched = (options: string[]) => {}; + readonly dialog = inject(MatDialog); + readonly optionSignal = signal(''); + isDisabled = true; + + ngOnInit(): void { + this.buildFormGroup(this.multiSelectOptions) + } + + buildFormGroup(options: string[], checked = false): void { + options.forEach(value => { + this.matSelectOptionsFormGroup.addControl(value, new FormControl({value: checked, disabled: this.isDisabled})) + }) + } + + updateFormGroup(options: string[], checked = false): void { + options.forEach(value => { + this.matSelectOptionsFormGroup.get(value).setValue(checked) + }) + } + + registerOnChange(fn: any): void { + this.onChange = fn; + } + + registerOnTouched(fn: any): void { + this.onTouched = fn; + } + + setDisabledState(isDisabled: boolean): void { + this.isDisabled = isDisabled; + if (this.isDisabled) { + this.matSelectOptionsFormGroup.disable(); + } else { + this.matSelectOptionsFormGroup.enable(); + } + } + + writeValue(obj: string[]): void { + this.buildFormGroup(obj) + this.updateFormGroup(obj, true) + } + + registerOnValidatorChange(fn: () => void): void { + } + + validate(control: AbstractControl): ValidationErrors | null { + return undefined; + } + + changeValues(e: MatCheckboxChange) { + let options: string[] = [] + Object.keys(this.matSelectOptionsFormGroup.controls).forEach(key => { + const control = this.matSelectOptionsFormGroup.get(key) + if (control instanceof FormControl) { + if (control.value) { + options.push(key) + } + } + }) + + this.onTouched(options) + this.onChange(options) + } + + addOption(): void { + const dialogRef = this.dialog.open(DialogTextInputComponent, { + data: {data: this.optionSignal()}, + }); + + dialogRef.afterClosed().subscribe(result => { + if (result !== undefined) { + this.optionSignal.set(result); + this.multiSelectOptions.push(result) + this.buildFormGroup(this.multiSelectOptions) + } + }); + } + +} diff --git a/projects/cobbler-frontend/src/app/items/distro/edit/distro-edit.component.html b/projects/cobbler-frontend/src/app/items/distro/edit/distro-edit.component.html new file mode 100644 index 00000000..66439413 --- /dev/null +++ b/projects/cobbler-frontend/src/app/items/distro/edit/distro-edit.component.html @@ -0,0 +1,144 @@ +
+
+

Name: {{ name }}

+ + + + + + + + + + + + +
+
+ +
+ + Name + + + + UID + + + + Last modified time + + + + Creation time + + + + Depth + + + + Architecture + + + Is Subobject? + + Tree Build Time + + + + + Inherited + + + + Inherited + + + + Inherited + + + Breed + + + + Comment + + + + + Inherited + + + kernel + + + + initrd + + + + Remote Boot Initrd + + + + Remote Boot Kernel + + + + Remote GRUB Initrd + + + + Remote GRUB Kernel + + + + + Inherited + + + + Inherited + + + + Inherited + + + Operating System Version + + + + + Inherited + + + RedHat Management Key + + + + + Inherited + + @if (isEditMode) { + + } +
diff --git a/projects/cobbler-frontend/src/app/items/distro/edit/distro-edit.component.scss b/projects/cobbler-frontend/src/app/items/distro/edit/distro-edit.component.scss new file mode 100644 index 00000000..2a9efa5d --- /dev/null +++ b/projects/cobbler-frontend/src/app/items/distro/edit/distro-edit.component.scss @@ -0,0 +1,30 @@ +.title-table { + display: table; + width: 100%; +} + +.title-row { + display: table-cell; + width: 100%; +} + +.title-cell-text { + display: table-cell; + width: 100%; + vertical-align: middle; +} + +.title-cell-button { + display: table-cell; +} + +.form-replicate { + min-width: 150px; + max-width: 600px; + width: 100%; +} + +.form-field-full-width { + width: 100%; +} + diff --git a/projects/cobbler-frontend/src/app/items/distro/edit/distro-edit.component.spec.ts b/projects/cobbler-frontend/src/app/items/distro/edit/distro-edit.component.spec.ts new file mode 100644 index 00000000..21384468 --- /dev/null +++ b/projects/cobbler-frontend/src/app/items/distro/edit/distro-edit.component.spec.ts @@ -0,0 +1,50 @@ +import {provideHttpClient} from '@angular/common/http'; +import {provideHttpClientTesting} from '@angular/common/http/testing'; +import { ComponentFixture, TestBed } from '@angular/core/testing'; +import {NoopAnimationsModule} from '@angular/platform-browser/animations'; +import {ActivatedRoute, provideRouter} from '@angular/router'; +import {COBBLER_URL} from 'cobbler-api'; + +import { DistroEditComponent } from './distro-edit.component'; + +describe('DistroEditComponent', () => { + let component: DistroEditComponent; + let fixture: ComponentFixture; + + beforeEach(async () => { + await TestBed.configureTestingModule({ + imports: [ + DistroEditComponent, + NoopAnimationsModule, + ], + providers: [ + provideRouter([]), + provideHttpClient(), + provideHttpClientTesting(), + { + provide: COBBLER_URL, + useValue: new URL('http://localhost/cobbler_api') + }, + { + provide: ActivatedRoute, + useValue: { + snapshot: { + paramMap: { + get: () => "testdistro" + }, + }, + }, + }, + ] + }) + .compileComponents(); + + fixture = TestBed.createComponent(DistroEditComponent); + component = fixture.componentInstance; + fixture.detectChanges(); + }); + + it('should create', () => { + expect(component).toBeTruthy(); + }); +}); diff --git a/projects/cobbler-frontend/src/app/items/distro/edit/distro-edit.component.ts b/projects/cobbler-frontend/src/app/items/distro/edit/distro-edit.component.ts new file mode 100644 index 00000000..06b0b5b7 --- /dev/null +++ b/projects/cobbler-frontend/src/app/items/distro/edit/distro-edit.component.ts @@ -0,0 +1,272 @@ +import {Component, inject, OnInit} from '@angular/core'; +import {FormBuilder, FormControl, FormsModule, ReactiveFormsModule} from '@angular/forms'; +import {MatButton, MatIconButton} from '@angular/material/button'; +import {MatCheckbox} from '@angular/material/checkbox'; +import {MatFormField, MatLabel} from '@angular/material/form-field'; +import {MatIcon} from '@angular/material/icon'; +import {MatInput} from '@angular/material/input'; +import {MatOption, MatSelect} from '@angular/material/select'; +import {MatSnackBar} from '@angular/material/snack-bar'; +import {MatTooltip} from '@angular/material/tooltip'; +import {ActivatedRoute, Router} from '@angular/router'; +import {CobblerApiService, Distro} from 'cobbler-api'; +import {KeyValueEditorComponent} from '../../../common/key-value-editor/key-value-editor.component'; +import {MultiSelectComponent} from '../../../common/multi-select/multi-select.component'; +import {UserService} from '../../../services/user.service'; + +@Component({ + selector: 'cobbler-edit', + standalone: true, + imports: [ + MatIcon, + MatIconButton, + ReactiveFormsModule, + MatFormField, + MatInput, + MatLabel, + FormsModule, + MatTooltip, + MatButton, + MatCheckbox, + MatSelect, + MatOption, + MultiSelectComponent, + KeyValueEditorComponent, + ], + templateUrl: './distro-edit.component.html', + styleUrl: './distro-edit.component.scss' +}) +export class DistroEditComponent implements OnInit{ + name: string; + distro: Distro; + private readonly _formBuilder = inject(FormBuilder); + distroFormGroup = this._formBuilder.group({ + name: new FormControl({value: "", disabled: true}), + uid: new FormControl({value: "", disabled: true}), + mtime: new FormControl({value: "", disabled: true}), + ctime: new FormControl({value: "", disabled: true}), + depth: new FormControl({value: 0, disabled: true}), + arch: new FormControl({value: "", disabled: true}), + is_subobject: new FormControl({value: false, disabled: true}), + tree_build_time: new FormControl({value: "", disabled: true}), + breed: new FormControl({value: "", disabled: true}), + comment: new FormControl({value: "", disabled: true}), + kernel: new FormControl({value: "", disabled: true}), + initrd: new FormControl({value: "", disabled: true}), + remote_boot_initrd: new FormControl({value: "", disabled: true}), + remote_boot_kernel: new FormControl({value: "", disabled: true}), + remote_grub_initrd: new FormControl({value: "", disabled: true}), + remote_grub_kernel: new FormControl({value: "", disabled: true}), + os_version: new FormControl({value: "", disabled: true}), + redhat_management_key: new FormControl({value: "", disabled: true}), + boot_loaders: new FormControl({value: [], disabled: true}), + bootloader_inherited: new FormControl({value: false, disabled: true}), + owners: new FormControl({value: [], disabled: true}), + owners_inherited: new FormControl({value: false, disabled: true}), + mgmt_classes: new FormControl({value: [], disabled: true}), + mgmt_classes_inherited: new FormControl({value: false, disabled: true}), + autoinstall_meta: new FormControl({value: {}, disabled: true}), + autoinstall_meta_inherited: new FormControl({value: false, disabled: true}), + boot_files: new FormControl({value: {}, disabled: true}), + boot_files_inherited: new FormControl({value: false, disabled: true}), + fetchable_files: new FormControl({value: {}, disabled: true}), + fetchable_files_inherited: new FormControl({value: false, disabled: true}), + kernel_options: new FormControl({value: {}, disabled: true}), + kernel_options_inherited: new FormControl({value: false, disabled: true}), + kernel_options_post: new FormControl({value: {}, disabled: true}), + kernel_options_post_inherited: new FormControl({value: false, disabled: true}), + template_files: new FormControl({value: {}, disabled: true}), + template_files_inherited: new FormControl({value: false, disabled: true}), + }); + isEditMode: boolean = false; + + constructor( + private route: ActivatedRoute, + private userService: UserService, + private cobblerApiService: CobblerApiService, + private _snackBar: MatSnackBar, + private router: Router, + ) { + this.name = this.route.snapshot.paramMap.get("name"); + } + + ngOnInit(): void { + this.refreshData() + } + + refreshData(): void { + this.cobblerApiService.get_distro(this.name, false, false, this.userService.token).subscribe(value => { + this.distro = value + this.distroFormGroup.controls.name.setValue(this.distro.name) + this.distroFormGroup.controls.uid.setValue(this.distro.uid) + this.distroFormGroup.controls.mtime.setValue(new Date(this.distro.mtime * 1000).toString()) + this.distroFormGroup.controls.ctime.setValue(new Date(this.distro.ctime * 1000).toString()) + this.distroFormGroup.controls.depth.setValue(this.distro.depth) + this.distroFormGroup.controls.arch.setValue(this.distro.arch) + this.distroFormGroup.controls.is_subobject.setValue(this.distro.is_subobject) + this.distroFormGroup.controls.tree_build_time.setValue(new Date(this.distro.tree_build_time * 1000).toString()) + this.distroFormGroup.controls.breed.setValue(this.distro.breed) + this.distroFormGroup.controls.comment.setValue(this.distro.comment) + this.distroFormGroup.controls.kernel.setValue(this.distro.kernel) + this.distroFormGroup.controls.initrd.setValue(this.distro.initrd) + this.distroFormGroup.controls.remote_boot_initrd.setValue(this.distro.remote_boot_initrd) + this.distroFormGroup.controls.remote_boot_kernel.setValue(this.distro.remote_boot_kernel) + this.distroFormGroup.controls.remote_grub_initrd.setValue(this.distro.remote_grub_initrd) + this.distroFormGroup.controls.remote_grub_kernel.setValue(this.distro.remote_grub_kernel) + this.distroFormGroup.controls.os_version.setValue(this.distro.os_version) + this.distroFormGroup.controls.redhat_management_key.setValue(this.distro.redhat_management_key) + if (typeof this.distro.boot_loaders === "string") { + this.distroFormGroup.controls.bootloader_inherited.setValue(true) + } else { + this.distroFormGroup.controls.bootloader_inherited.setValue(false) + this.distroFormGroup.controls.boot_loaders.setValue(this.distro.boot_loaders) + } + if (typeof this.distro.owners === "string") { + this.distroFormGroup.controls.owners_inherited.setValue(true) + } else { + this.distroFormGroup.controls.owners_inherited.setValue(false) + this.distroFormGroup.controls.owners.setValue(this.distro.owners) + } + if (typeof this.distro.autoinstall_meta === "string") { + this.distroFormGroup.controls.autoinstall_meta_inherited.setValue(true) + } else { + this.distroFormGroup.controls.autoinstall_meta_inherited.setValue(false) + this.distroFormGroup.controls.autoinstall_meta.setValue(this.distro.autoinstall_meta) + } + if (typeof this.distro.fetchable_files === "string") { + this.distroFormGroup.controls.fetchable_files_inherited.setValue(true) + } else { + this.distroFormGroup.controls.fetchable_files_inherited.setValue(false) + this.distroFormGroup.controls.fetchable_files.setValue(this.distro.fetchable_files) + } + if (typeof this.distro.kernel_options === "string") { + this.distroFormGroup.controls.kernel_options_inherited.setValue(true) + } else { + this.distroFormGroup.controls.kernel_options_inherited.setValue(false) + this.distroFormGroup.controls.kernel_options.setValue(this.distro.kernel_options) + } + if (typeof this.distro.kernel_options_post === "string") { + this.distroFormGroup.controls.kernel_options_post_inherited.setValue(true) + } else { + this.distroFormGroup.controls.kernel_options_post_inherited.setValue(false) + this.distroFormGroup.controls.kernel_options_post.setValue(this.distro.kernel_options_post) + } + if (typeof this.distro.template_files === "string") { + this.distroFormGroup.controls.template_files_inherited.setValue(true) + } else { + this.distroFormGroup.controls.template_files_inherited.setValue(false) + this.distroFormGroup.controls.template_files.setValue(this.distro.template_files) + } + }, error => { + // HTML encode the error message since it originates from XML + this._snackBar.open(this.toHTML(error.message), 'Close'); + }) + } + + removeDistro(): void { + this.cobblerApiService.remove_distro(this.name, this.userService.token, false).subscribe(value => { + if (value) { + this.router.navigate(["/items", "distro"]) + } + // HTML encode the error message since it originates from XML + this._snackBar.open("Delete failed! Check server logs for more information.", 'Close'); + }, error => { + // HTML encode the error message since it originates from XML + this._snackBar.open(this.toHTML(error.message), 'Close'); + }) + } + + editDistro(): void { + // TODO + this._snackBar.open("Not implemented at the moment!", "Close") + } + + copyDistro(): void { + this.cobblerApiService.copy_distro("", "", this.userService.token) + .subscribe(value => { + // TODO + }, error => { + // HTML encode the error message since it originates from XML + this._snackBar.open(this.toHTML(error.message), 'Close'); + }) + } + + saveDistro(): void { + // TODO + } + + get distroOwners(): string[] { + if (this.distro && this.distro.owners) { + const ownersResult = this.distro.owners + if (typeof ownersResult !== 'string') { + return ownersResult; + } + } + return [] + } + + get distroAutoinstallMeta(): object { + if (this.distro && this.distro.autoinstall_meta) { + const autoinstallMetaResult = this.distro.autoinstall_meta + if (typeof autoinstallMetaResult !== 'string') { + return autoinstallMetaResult + } + } + return {} + } + + get distroBootFiles(): object { + if (this.distro && this.distro.boot_files) { + const bootFilesResult = this.distro.boot_files + if (typeof bootFilesResult !== 'string') { + return bootFilesResult + } + } + return {} + } + + get distroFetchableFiles(): object { + if (this.distro && this.distro.fetchable_files) { + const fetchableFilesResult = this.distro.fetchable_files + if (typeof fetchableFilesResult !== 'string') { + return fetchableFilesResult + } + } + return {} + } + + get distroKernelOptions(): object { + if (this.distro && this.distro.kernel_options) { + const kernelOptionsResult = this.distro.kernel_options + if (typeof kernelOptionsResult !== 'string') { + return kernelOptionsResult + } + } + return {} + } + + get distroKernelOptionsPost(): object { + if (this.distro && this.distro.kernel_options_post) { + const kernelOptionsPostResult = this.distro.kernel_options_post + if (typeof kernelOptionsPostResult !== 'string') { + return kernelOptionsPostResult + } + } + return {} + } + + get distroTemplateFiles(): object { + if (this.distro && this.distro.template_files) { + const templateFilesResult = this.distro.template_files + if (typeof templateFilesResult !== 'string') { + return templateFilesResult + } + } + return {} + } + + toHTML(input: string): any { + // FIXME: Deduplicate method + return new DOMParser().parseFromString(input, 'text/html').documentElement.textContent; + } +} diff --git a/projects/cobbler-frontend/src/app/items/management-classes/management-classes.component.css b/projects/cobbler-frontend/src/app/items/distro/overview/distros-overview.component.css similarity index 100% rename from projects/cobbler-frontend/src/app/items/management-classes/management-classes.component.css rename to projects/cobbler-frontend/src/app/items/distro/overview/distros-overview.component.css diff --git a/projects/cobbler-frontend/src/app/items/distro/overview/distros-overview.component.html b/projects/cobbler-frontend/src/app/items/distro/overview/distros-overview.component.html new file mode 100644 index 00000000..dfa12d74 --- /dev/null +++ b/projects/cobbler-frontend/src/app/items/distro/overview/distros-overview.component.html @@ -0,0 +1,46 @@ +

DISTROS

+ + + + + + + + + + + + + + + + + + + + + + + + + + + +
Name{{element.name}}Breed{{element.breed}}Operating System Version{{element.os_version}} + + + + + + +
+ diff --git a/projects/cobbler-frontend/src/app/items/distros/distros.component.spec.ts b/projects/cobbler-frontend/src/app/items/distro/overview/distros-overview.component.spec.ts similarity index 60% rename from projects/cobbler-frontend/src/app/items/distros/distros.component.spec.ts rename to projects/cobbler-frontend/src/app/items/distro/overview/distros-overview.component.spec.ts index 50f29164..d701f1a4 100644 --- a/projects/cobbler-frontend/src/app/items/distros/distros.component.spec.ts +++ b/projects/cobbler-frontend/src/app/items/distro/overview/distros-overview.component.spec.ts @@ -1,3 +1,5 @@ +import {provideHttpClient} from '@angular/common/http'; +import {provideHttpClientTesting} from '@angular/common/http/testing'; import { ComponentFixture, TestBed } from '@angular/core/testing'; import { MatButtonModule } from '@angular/material/button'; import { MatFormFieldModule } from '@angular/material/form-field'; @@ -6,13 +8,14 @@ import { MatTableModule } from '@angular/material/table'; import { MatTabsModule } from '@angular/material/tabs'; import { NoopAnimationsModule } from '@angular/platform-browser/animations'; import {provideRouter} from '@angular/router'; +import {COBBLER_URL} from 'cobbler-api'; -import { DistrosComponent } from './distros.component'; +import { DistrosOverviewComponent } from './distros-overview.component'; -describe('DistrosComponent', () => { - let component: DistrosComponent; - let fixture: ComponentFixture; +describe('DistroOverviewComponent', () => { + let component: DistrosOverviewComponent; + let fixture: ComponentFixture; beforeEach(async () => { await TestBed.configureTestingModule({ @@ -23,16 +26,22 @@ describe('DistrosComponent', () => { MatTabsModule, MatTableModule, NoopAnimationsModule, - DistrosComponent, + DistrosOverviewComponent, ], providers: [ provideRouter([]), + provideHttpClient(), + provideHttpClientTesting(), + { + provide: COBBLER_URL, + useValue: new URL('http://localhost/cobbler_api') + }, ] }).compileComponents(); }); beforeEach(() => { - fixture = TestBed.createComponent(DistrosComponent); + fixture = TestBed.createComponent(DistrosOverviewComponent); component = fixture.componentInstance; fixture.detectChanges(); }); diff --git a/projects/cobbler-frontend/src/app/items/distro/overview/distros-overview.component.ts b/projects/cobbler-frontend/src/app/items/distro/overview/distros-overview.component.ts new file mode 100644 index 00000000..6f422c29 --- /dev/null +++ b/projects/cobbler-frontend/src/app/items/distro/overview/distros-overview.component.ts @@ -0,0 +1,93 @@ +import {Component, OnInit, ViewChild} from '@angular/core'; +import {MatButton, MatIconButton} from '@angular/material/button'; +import {MatIcon} from '@angular/material/icon'; +import {MatMenu, MatMenuItem, MatMenuTrigger} from '@angular/material/menu'; +import {MatSnackBar} from '@angular/material/snack-bar'; +import { + MatCell, + MatCellDef, + MatColumnDef, + MatHeaderCell, + MatHeaderCellDef, + MatHeaderRow, MatHeaderRowDef, MatRow, MatRowDef, + MatTable +} from '@angular/material/table'; +import {Router} from '@angular/router'; +import {CobblerApiService, Distro} from 'cobbler-api'; +import {UserService} from '../../../services/user.service'; + +@Component({ + selector: 'cobbler-distros', + templateUrl: './distros-overview.component.html', + styleUrls: ['./distros-overview.component.css'], + + standalone: true, + imports: [ + MatButton, + MatTable, + MatHeaderCell, + MatCell, + MatColumnDef, + MatHeaderCellDef, + MatCellDef, + MatHeaderRow, + MatRow, + MatRowDef, + MatHeaderRowDef, + MatIcon, + MatIconButton, + MatMenu, + MatMenuItem, + MatMenuTrigger + ], +}) +export class DistrosOverviewComponent implements OnInit{ + displayedColumns: string[] = ['name', "breed", "os_version", "actions"]; + dataSource: Array = []; + + @ViewChild(MatTable) table: MatTable; + + constructor( + public userService: UserService, + private cobblerApiService: CobblerApiService, + private _snackBar: MatSnackBar, + private router: Router, + ) { + } + + ngOnInit(): void { + this.retrieveDistros() + } + + private retrieveDistros(): void { + this.cobblerApiService.get_distros().subscribe(value => { + this.dataSource = value + }, error => { + // HTML encode the error message since it originates from XML + this._snackBar.open(this.toHTML(error.message), 'Close'); + }) + } + + showDistro(uid: string, name: string): void { + this.router.navigate(["/items", "distro", name]) + } + + editDistro(uid: string, name: string): void { + // TODO + } + + deleteDistro(uid: string, name: string): void { + this.cobblerApiService.remove_distro(name, this.userService.token, false).subscribe(value => { + this.retrieveDistros() + }, error => { + // HTML encode the error message since it originates from XML + this._snackBar.open(this.toHTML(error.message), 'Close'); + }) + } + + toHTML(input: string): any { + // FIXME: Deduplicate method + return new DOMParser().parseFromString(input, 'text/html').documentElement.textContent; + } + +} diff --git a/projects/cobbler-frontend/src/app/items/distros/distros.component.html b/projects/cobbler-frontend/src/app/items/distros/distros.component.html deleted file mode 100644 index 92106f9b..00000000 --- a/projects/cobbler-frontend/src/app/items/distros/distros.component.html +++ /dev/null @@ -1,170 +0,0 @@ - - -
-

DISTROS

- - - -

Editing a Distro

-

Name: {{datatable[14][5]}}

-
- - -
-
-
- - Owners - - -
-
- - Kernel - - -
-
- - Initrd - - -
-
- - Kernel Options - - -
-
- - Kernel Options post-install - - -
-
- - Auto-install template metadata - - -
-
- - Architecture - - -
-
- - Breed - - -
-
- - OS Version - - -
-
- - Boot Loader - - -
-
- - Comment - - -
-
-
CAUTION: Tab navigation will EXIT edit mode
-
- - - - - - - - - - - - - - - - - - - - - - - - -
No. {{i + 1}}Item{{datatable[i][0]}}Description{{datatable[i][5]}}
-
-
- - - - - - - - - - - - - - - - - - - - - - - - - -
No. {{i + 1}}Type{{datatable[0][1]}}Version{{datatable[15][1]}} Update - - - - -
-
-
- -
diff --git a/projects/cobbler-frontend/src/app/items/distros/distros.component.spec.js b/projects/cobbler-frontend/src/app/items/distros/distros.component.spec.js deleted file mode 100644 index ac8d14dd..00000000 --- a/projects/cobbler-frontend/src/app/items/distros/distros.component.spec.js +++ /dev/null @@ -1,66 +0,0 @@ -"use strict"; -var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { - function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } - return new (P || (P = Promise))(function (resolve, reject) { - function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } - function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } - function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } - step((generator = generator.apply(thisArg, _arguments || [])).next()); - }); -}; -var __generator = (this && this.__generator) || function (thisArg, body) { - var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g; - return g = { next: verb(0), "throw": verb(1), "return": verb(2) }, typeof Symbol === "function" && (g[Symbol.iterator] = function() { return this; }), g; - function verb(n) { return function (v) { return step([n, v]); }; } - function step(op) { - if (f) throw new TypeError("Generator is already executing."); - while (_) try { - if (f = 1, y && (t = op[0] & 2 ? y["return"] : op[0] ? y["throw"] || ((t = y["return"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t; - if (y = 0, t) op = [op[0] & 2, t.value]; - switch (op[0]) { - case 0: case 1: t = op; break; - case 4: _.label++; return { value: op[1], done: false }; - case 5: _.label++; y = op[1]; op = [0]; continue; - case 7: op = _.ops.pop(); _.trys.pop(); continue; - default: - if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; } - if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; } - if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; } - if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; } - if (t[2]) _.ops.pop(); - _.trys.pop(); continue; - } - op = body.call(thisArg, _); - } catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; } - if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true }; - } -}; -Object.defineProperty(exports, "__esModule", { value: true }); -var testing_1 = require("@angular/core/testing"); -var distros_component_1 = require("./distros.component"); -describe('DistrosComponent', function () { - var component; - var fixture; - beforeEach(function () { return __awaiter(void 0, void 0, void 0, function () { - return __generator(this, function (_a) { - switch (_a.label) { - case 0: return [4 /*yield*/, testing_1.TestBed.configureTestingModule({ - declarations: [distros_component_1.DistrosComponent] - }) - .compileComponents()]; - case 1: - _a.sent(); - return [2 /*return*/]; - } - }); - }); }); - beforeEach(function () { - fixture = testing_1.TestBed.createComponent(distros_component_1.DistrosComponent); - component = fixture.componentInstance; - fixture.detectChanges(); - }); - it('should create', function () { - expect(component).toBeTruthy(); - }); -}); -//# sourceMappingURL=distros.component.spec.js.map \ No newline at end of file diff --git a/projects/cobbler-frontend/src/app/items/distros/distros.component.spec.js.map b/projects/cobbler-frontend/src/app/items/distros/distros.component.spec.js.map deleted file mode 100644 index f2e6edf2..00000000 --- a/projects/cobbler-frontend/src/app/items/distros/distros.component.spec.js.map +++ /dev/null @@ -1 +0,0 @@ -{"version":3,"file":"distros.component.spec.js","sourceRoot":"","sources":["distros.component.spec.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA,iDAAkE;AAElE,yDAAuD;AAEvD,QAAQ,CAAC,kBAAkB,EAAE;IAC3B,IAAI,SAA2B,CAAC;IAChC,IAAI,OAA2C,CAAC;IAEhD,UAAU,CAAC;;;wBACT,qBAAM,iBAAO,CAAC,sBAAsB,CAAC;wBACnC,YAAY,EAAE,CAAE,oCAAgB,CAAE;qBACnC,CAAC;yBACD,iBAAiB,EAAE,EAAA;;oBAHpB,SAGoB,CAAC;;;;SACtB,CAAC,CAAC;IAEH,UAAU,CAAC;QACT,OAAO,GAAG,iBAAO,CAAC,eAAe,CAAC,oCAAgB,CAAC,CAAC;QACpD,SAAS,GAAG,OAAO,CAAC,iBAAiB,CAAC;QACtC,OAAO,CAAC,aAAa,EAAE,CAAC;IAC1B,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,eAAe,EAAE;QAClB,MAAM,CAAC,SAAS,CAAC,CAAC,UAAU,EAAE,CAAC;IACjC,CAAC,CAAC,CAAC;AACL,CAAC,CAAC,CAAC"} \ No newline at end of file diff --git a/projects/cobbler-frontend/src/app/items/distros/distros.component.ts b/projects/cobbler-frontend/src/app/items/distros/distros.component.ts deleted file mode 100644 index 51eb6885..00000000 --- a/projects/cobbler-frontend/src/app/items/distros/distros.component.ts +++ /dev/null @@ -1,95 +0,0 @@ -import {Component} from '@angular/core'; -import {DataDistroService} from '../../services/data-distro.service'; -import { RouterOutlet } from '@angular/router'; -import { MatFormFieldModule } from '@angular/material/form-field'; -import { MatTabsModule } from '@angular/material/tabs'; -import {MatInputModule} from "@angular/material/input"; -import {MatTableModule} from "@angular/material/table"; -import {MatButtonModule} from "@angular/material/button"; - -@Component({ - selector: 'cobbler-distros', - templateUrl: './distros.component.html', - styleUrls: ['./distros.component.css'], - - standalone: true, - imports: [RouterOutlet, MatFormFieldModule, MatTabsModule, MatInputModule, MatTableModule, MatButtonModule], -}) -export class DistrosComponent { - // Distro object contains [0-5] not editable - // [6-24] items below - // There can be more than one distro object - arch = []; - autoinstall = []; - bFiles = []; - bLoader = []; - breed = []; - comment = []; - fFiles = []; - initrd = []; - kernel = []; - reboInitrd = []; - reboKernel = []; - kernelOptions = []; - kOptPost = []; - mngClass = []; - name = []; - osVersion = []; - owners = []; - rhMngKey = []; - tmpltFiles = []; - // persistant use items: - datatable = []; - ActiveElement = 'description'; - displayedColumns = ['position', 'type', 'version','update'] - displayedColumns2 = ['position', 'item', 'description'] - - constructor(service: DataDistroService) { - /*USE - -------- - for items of tabledata[i]: - [0] = python variable name - [1] = data about this item - [2] = number = 0 - [3] = description - [4] = boolean | True - [5] = use case - [6] = function call | 0 - [7] = data type - -------- - Example: - to get and display arch type: - {{datatable[0][7]}} - */ - // Linter throws errors on these variable names. - // These variable names are set in the data, but can be changed for linter purposes - this.arch = service.get_item('arch'); // 0 - this.autoinstall = service.get_item('autoinstall'); // 1 - this.bFiles = service.get_item('b_files'); // 2 - this.bLoader = service.get_item('b_loader'); // 3 - this.breed = service.get_item('breed'); // 4 - this.comment = service.get_item('comment'); // 5 - this.fFiles = service.get_item('f_files'); // 6 - this.initrd = service.get_item('initrd'); // 7 - this.kernel = service.get_item('kernel'); // 8 - this.reboInitrd = service.get_item('rebo_initrd'); // 9 - this.reboKernel = service.get_item('rebo_kernel'); // 10 - this.kernelOptions = service.get_item('kernel_options'); // 11 - this.kOptPost = service.get_item('k_opt_post'); // 12 - this.mngClass = service.get_item('mng_class'); // 13 - this.name = service.get_item('name'); // 14 - this.osVersion = service.get_item('os_version'); // 15 - this.owners = service.get_item('owners'); // 16 - this.rhMngKey = service.get_item('rh_mng_key'); // 17 - this.tmpltFiles = service.get_item('tmplt_files'); // 18 - - this.datatable = [this.arch, this.autoinstall, this.bFiles, this.bLoader, this.breed, this.comment, this.fFiles, - this.initrd, this.kernel, this.reboInitrd, this.reboKernel, this.kernelOptions, this.kOptPost, - this.mngClass, this.name, this.osVersion, this.owners, this.rhMngKey, this.tmpltFiles]; - } - - show(name: string): void { - this.ActiveElement = name; - // console.log(this.ActiveElement) - } -} diff --git a/projects/cobbler-frontend/src/app/items/file/edit/file-edit.component.html b/projects/cobbler-frontend/src/app/items/file/edit/file-edit.component.html new file mode 100644 index 00000000..dfa5d4bf --- /dev/null +++ b/projects/cobbler-frontend/src/app/items/file/edit/file-edit.component.html @@ -0,0 +1,90 @@ +
+
+

Name: {{ name }}

+ + + + + + + + + + + + +
+
+ +
+ + Name + + + + UID + + + + Last modified time + + + + Creation time + + + + Depth + + + Is Subobject? + + Comment + + + + Action + + + + Group + + + + Mode + + + + Owner + + + + Path + + + + Template + + + Is Directory? + @if (isEditMode) { + + } +
+ diff --git a/projects/cobbler-frontend/src/app/items/file/edit/file-edit.component.scss b/projects/cobbler-frontend/src/app/items/file/edit/file-edit.component.scss new file mode 100644 index 00000000..2a9efa5d --- /dev/null +++ b/projects/cobbler-frontend/src/app/items/file/edit/file-edit.component.scss @@ -0,0 +1,30 @@ +.title-table { + display: table; + width: 100%; +} + +.title-row { + display: table-cell; + width: 100%; +} + +.title-cell-text { + display: table-cell; + width: 100%; + vertical-align: middle; +} + +.title-cell-button { + display: table-cell; +} + +.form-replicate { + min-width: 150px; + max-width: 600px; + width: 100%; +} + +.form-field-full-width { + width: 100%; +} + diff --git a/projects/cobbler-frontend/src/app/items/file/edit/file-edit.component.spec.ts b/projects/cobbler-frontend/src/app/items/file/edit/file-edit.component.spec.ts new file mode 100644 index 00000000..e6a33533 --- /dev/null +++ b/projects/cobbler-frontend/src/app/items/file/edit/file-edit.component.spec.ts @@ -0,0 +1,50 @@ +import {provideHttpClient} from '@angular/common/http'; +import {provideHttpClientTesting} from '@angular/common/http/testing'; +import { ComponentFixture, TestBed } from '@angular/core/testing'; +import {NoopAnimationsModule} from '@angular/platform-browser/animations'; +import {ActivatedRoute, provideRouter} from '@angular/router'; +import {COBBLER_URL} from 'cobbler-api'; + +import { FileEditComponent } from './file-edit.component'; + +describe('FileEditComponent', () => { + let component: FileEditComponent; + let fixture: ComponentFixture; + + beforeEach(async () => { + await TestBed.configureTestingModule({ + imports: [ + FileEditComponent, + NoopAnimationsModule, + ], + providers: [ + provideRouter([]), + provideHttpClient(), + provideHttpClientTesting(), + { + provide: COBBLER_URL, + useValue: new URL('http://localhost/cobbler_api') + }, + { + provide: ActivatedRoute, + useValue: { + snapshot: { + paramMap: { + get: () => "testfile" + }, + }, + }, + }, + ] + }) + .compileComponents(); + + fixture = TestBed.createComponent(FileEditComponent); + component = fixture.componentInstance; + fixture.detectChanges(); + }); + + it('should create', () => { + expect(component).toBeTruthy(); + }); +}); diff --git a/projects/cobbler-frontend/src/app/items/file/edit/file-edit.component.ts b/projects/cobbler-frontend/src/app/items/file/edit/file-edit.component.ts new file mode 100644 index 00000000..1de269af --- /dev/null +++ b/projects/cobbler-frontend/src/app/items/file/edit/file-edit.component.ts @@ -0,0 +1,131 @@ +import {Component, inject, OnInit} from '@angular/core'; +import {FormBuilder, FormControl, FormsModule, ReactiveFormsModule} from '@angular/forms'; +import {MatOption} from '@angular/material/autocomplete'; +import {MatButton, MatIconButton} from '@angular/material/button'; +import {MatCheckbox} from '@angular/material/checkbox'; +import {MatFormField, MatLabel} from '@angular/material/form-field'; +import {MatIcon} from '@angular/material/icon'; +import {MatInput} from '@angular/material/input'; +import {MatSelect} from '@angular/material/select'; +import {MatSnackBar} from '@angular/material/snack-bar'; +import {MatTooltip} from '@angular/material/tooltip'; +import {ActivatedRoute, Router} from '@angular/router'; +import {CobblerApiService, File} from 'cobbler-api'; +import {UserService} from '../../../services/user.service'; + +@Component({ + selector: 'cobbler-edit', + standalone: true, + imports: [ + FormsModule, + MatButton, + MatCheckbox, + MatFormField, + MatIcon, + MatIconButton, + MatInput, + MatLabel, + MatOption, + MatSelect, + MatTooltip, + ReactiveFormsModule + ], + templateUrl: './file-edit.component.html', + styleUrl: './file-edit.component.scss' +}) +export class FileEditComponent implements OnInit { + name: string; + file: File; + private readonly _formBuilder = inject(FormBuilder); + fileFormGroup = this._formBuilder.group({ + name: new FormControl({value: "", disabled: true}), + uid: new FormControl({value: "", disabled: true}), + mtime: new FormControl({value: "", disabled: true}), + ctime: new FormControl({value: "", disabled: true}), + depth: new FormControl({value: 0, disabled: true}), + is_subobject: new FormControl({value: false, disabled: true}), + is_dir: new FormControl({value: false, disabled: true}), + comment: new FormControl({value: "", disabled: true}), + redhat_management_key: new FormControl({value: "", disabled: true}), + action: new FormControl({value: "", disabled: true}), + group: new FormControl({value: "", disabled: true}), + mode: new FormControl({value: "", disabled: true}), + owner: new FormControl({value: "", disabled: true}), + path: new FormControl({value: "", disabled: true}), + template: new FormControl({value: "", disabled: true}), + }); + isEditMode: boolean = false; + + constructor( + private route: ActivatedRoute, + private userService: UserService, + private cobblerApiService: CobblerApiService, + private _snackBar: MatSnackBar, + private router: Router, + ) { + this.name = this.route.snapshot.paramMap.get("name"); + } + + ngOnInit(): void { + this.refreshData() + } + + refreshData(): void { + this.cobblerApiService.get_file(this.name, false, false, this.userService.token).subscribe(value => { + this.file = value + this.fileFormGroup.controls.name.setValue(this.file.name) + this.fileFormGroup.controls.uid.setValue(this.file.uid) + this.fileFormGroup.controls.mtime.setValue(new Date(this.file.mtime * 1000).toString()) + this.fileFormGroup.controls.ctime.setValue(new Date(this.file.ctime * 1000).toString()) + this.fileFormGroup.controls.depth.setValue(this.file.depth) + this.fileFormGroup.controls.is_subobject.setValue(this.file.is_subobject) + this.fileFormGroup.controls.comment.setValue(this.file.comment) + this.fileFormGroup.controls.action.setValue(this.file.action) + this.fileFormGroup.controls.group.setValue(this.file.group) + this.fileFormGroup.controls.mode.setValue(this.file.mode) + this.fileFormGroup.controls.owner.setValue(this.file.owner) + this.fileFormGroup.controls.path.setValue(this.file.path) + this.fileFormGroup.controls.template.setValue(this.file.template) + }, error => { + // HTML encode the error message since it originates from XML + this._snackBar.open(this.toHTML(error.message), 'Close'); + }); + } + + removeFile(): void { + this.cobblerApiService.remove_file(this.name, this.userService.token, false).subscribe(value => { + if (value) { + this.router.navigate(["/items", "file"]) + } + // HTML encode the error message since it originates from XML + this._snackBar.open("Delete failed! Check server logs for more information.", 'Close'); + }, error => { + // HTML encode the error message since it originates from XML + this._snackBar.open(this.toHTML(error.message), 'Close'); + }) + } + + editFile(): void { + // TODO + this._snackBar.open("Not implemented at the moment!", "Close") + } + + copyFile(): void { + this.cobblerApiService.copy_file("", "", this.userService.token) + .subscribe(value => { + // TODO + }, error => { + // HTML encode the error message since it originates from XML + this._snackBar.open(this.toHTML(error.message), 'Close'); + }) + } + + saveFile(): void { + // TODO + } + + toHTML(input: string): any { + // FIXME: Deduplicate method + return new DOMParser().parseFromString(input, 'text/html').documentElement.textContent; + } +} diff --git a/projects/cobbler-frontend/src/app/items/file/overview/file-overview.component.html b/projects/cobbler-frontend/src/app/items/file/overview/file-overview.component.html new file mode 100644 index 00000000..8dbcee25 --- /dev/null +++ b/projects/cobbler-frontend/src/app/items/file/overview/file-overview.component.html @@ -0,0 +1,46 @@ +

FILES

+ + + + + + + + + + + + + + + + + + + + + + + + + + + +
Name{{element.name}}Action{{element.action}}Path{{element.path}} + + + + + + +
+ diff --git a/projects/cobbler-frontend/src/app/items/packages/packages.component.css b/projects/cobbler-frontend/src/app/items/file/overview/file-overview.component.scss similarity index 100% rename from projects/cobbler-frontend/src/app/items/packages/packages.component.css rename to projects/cobbler-frontend/src/app/items/file/overview/file-overview.component.scss diff --git a/projects/cobbler-frontend/src/app/items/file/overview/file-overview.component.spec.ts b/projects/cobbler-frontend/src/app/items/file/overview/file-overview.component.spec.ts new file mode 100644 index 00000000..4460c2c5 --- /dev/null +++ b/projects/cobbler-frontend/src/app/items/file/overview/file-overview.component.spec.ts @@ -0,0 +1,35 @@ +import {provideHttpClient} from '@angular/common/http'; +import {provideHttpClientTesting} from '@angular/common/http/testing'; +import { ComponentFixture, TestBed } from '@angular/core/testing'; +import {provideRouter} from '@angular/router'; +import {COBBLER_URL} from 'cobbler-api'; + +import { FileOverviewComponent } from './file-overview.component'; + +describe('FileOverviewComponent', () => { + let component: FileOverviewComponent; + let fixture: ComponentFixture; + + beforeEach(async () => { + await TestBed.configureTestingModule({ + imports: [FileOverviewComponent], + providers: [ + provideHttpClient(), + provideHttpClientTesting(), + { + provide: COBBLER_URL, + useValue: new URL('http://localhost/cobbler_api') + }, + ] + }) + .compileComponents(); + + fixture = TestBed.createComponent(FileOverviewComponent); + component = fixture.componentInstance; + fixture.detectChanges(); + }); + + it('should create', () => { + expect(component).toBeTruthy(); + }); +}); diff --git a/projects/cobbler-frontend/src/app/items/file/overview/file-overview.component.ts b/projects/cobbler-frontend/src/app/items/file/overview/file-overview.component.ts new file mode 100644 index 00000000..44bacd9b --- /dev/null +++ b/projects/cobbler-frontend/src/app/items/file/overview/file-overview.component.ts @@ -0,0 +1,90 @@ +import {Component, OnInit, ViewChild} from '@angular/core'; +import {MatIconButton} from '@angular/material/button'; +import {MatIcon} from '@angular/material/icon'; +import {MatMenu, MatMenuItem, MatMenuTrigger} from '@angular/material/menu'; +import {MatSnackBar} from '@angular/material/snack-bar'; +import { + MatCell, + MatCellDef, + MatColumnDef, + MatHeaderCell, MatHeaderCellDef, + MatHeaderRow, + MatHeaderRowDef, + MatRow, MatRowDef, MatTable +} from '@angular/material/table'; +import {Router} from '@angular/router'; +import {CobblerApiService, File} from 'cobbler-api'; +import {UserService} from '../../../services/user.service'; + +@Component({ + selector: 'cobbler-overview', + standalone: true, + imports: [ + MatCell, + MatCellDef, + MatColumnDef, + MatHeaderCell, + MatHeaderRow, + MatHeaderRowDef, + MatIcon, + MatIconButton, + MatMenu, + MatMenuItem, + MatRow, + MatRowDef, + MatTable, + MatMenuTrigger, + MatHeaderCellDef + ], + templateUrl: './file-overview.component.html', + styleUrl: './file-overview.component.scss' +}) +export class FileOverviewComponent implements OnInit{ + displayedColumns: string[] = ['name', "action", "path", "actions"]; + dataSource: Array = []; + + @ViewChild(MatTable) table: MatTable; + + constructor( + public userService: UserService, + private cobblerApiService: CobblerApiService, + private _snackBar: MatSnackBar, + private router: Router, + ) { + } + + ngOnInit(): void { + this.retrieveFiles() + } + + private retrieveFiles(): void { + this.cobblerApiService.get_files().subscribe(value => { + this.dataSource = value + }, error => { + // HTML encode the error message since it originates from XML + this._snackBar.open(this.toHTML(error.message), 'Close'); + }) + } + + showDistro(uid: string, name: string): void { + this.router.navigate(["/items", "file", name]) + } + + editFile(uid: string, name: string): void { + // TODO + } + + deleteFile(uid: string, name: string): void { + this.cobblerApiService.remove_file(name, this.userService.token, false).subscribe(value => { + this.retrieveFiles() + }, error => { + // HTML encode the error message since it originates from XML + this._snackBar.open(this.toHTML(error.message), 'Close'); + }) + } + + toHTML(input: string): any { + // FIXME: Deduplicate method + return new DOMParser().parseFromString(input, 'text/html').documentElement.textContent; + } +} diff --git a/projects/cobbler-frontend/src/app/items/files/files.component.css b/projects/cobbler-frontend/src/app/items/files/files.component.css deleted file mode 100644 index e8018244..00000000 --- a/projects/cobbler-frontend/src/app/items/files/files.component.css +++ /dev/null @@ -1,4 +0,0 @@ -.profiles-form{ - display:flex; - flex-direction: column; -} \ No newline at end of file diff --git a/projects/cobbler-frontend/src/app/items/files/files.component.html b/projects/cobbler-frontend/src/app/items/files/files.component.html deleted file mode 100644 index 0df8f634..00000000 --- a/projects/cobbler-frontend/src/app/items/files/files.component.html +++ /dev/null @@ -1,24 +0,0 @@ - -
-
-

FILES

-
- - -
-
- @for(item of data;track item){ - - {{ item[0] }} - - - } -
-
-
diff --git a/projects/cobbler-frontend/src/app/items/files/files.component.spec.js b/projects/cobbler-frontend/src/app/items/files/files.component.spec.js deleted file mode 100644 index 68978efe..00000000 --- a/projects/cobbler-frontend/src/app/items/files/files.component.spec.js +++ /dev/null @@ -1,66 +0,0 @@ -"use strict"; -var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { - function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } - return new (P || (P = Promise))(function (resolve, reject) { - function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } - function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } - function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } - step((generator = generator.apply(thisArg, _arguments || [])).next()); - }); -}; -var __generator = (this && this.__generator) || function (thisArg, body) { - var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g; - return g = { next: verb(0), "throw": verb(1), "return": verb(2) }, typeof Symbol === "function" && (g[Symbol.iterator] = function() { return this; }), g; - function verb(n) { return function (v) { return step([n, v]); }; } - function step(op) { - if (f) throw new TypeError("Generator is already executing."); - while (_) try { - if (f = 1, y && (t = op[0] & 2 ? y["return"] : op[0] ? y["throw"] || ((t = y["return"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t; - if (y = 0, t) op = [op[0] & 2, t.value]; - switch (op[0]) { - case 0: case 1: t = op; break; - case 4: _.label++; return { value: op[1], done: false }; - case 5: _.label++; y = op[1]; op = [0]; continue; - case 7: op = _.ops.pop(); _.trys.pop(); continue; - default: - if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; } - if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; } - if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; } - if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; } - if (t[2]) _.ops.pop(); - _.trys.pop(); continue; - } - op = body.call(thisArg, _); - } catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; } - if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true }; - } -}; -Object.defineProperty(exports, "__esModule", { value: true }); -var testing_1 = require("@angular/core/testing"); -var app_files_component_1 = require("./app-files.component"); -describe('AppFilesComponent', function () { - var component; - var fixture; - beforeEach(function () { return __awaiter(void 0, void 0, void 0, function () { - return __generator(this, function (_a) { - switch (_a.label) { - case 0: return [4 /*yield*/, testing_1.TestBed.configureTestingModule({ - declarations: [app_files_component_1.FilesComponent] - }) - .compileComponents()]; - case 1: - _a.sent(); - return [2 /*return*/]; - } - }); - }); }); - beforeEach(function () { - fixture = testing_1.TestBed.createComponent(app_files_component_1.FilesComponent); - component = fixture.componentInstance; - fixture.detectChanges(); - }); - it('should create', function () { - expect(component).toBeTruthy(); - }); -}); -//# sourceMappingURL=app-files.component.spec.js.map diff --git a/projects/cobbler-frontend/src/app/items/files/files.component.spec.js.map b/projects/cobbler-frontend/src/app/items/files/files.component.spec.js.map deleted file mode 100644 index 9ec19b33..00000000 --- a/projects/cobbler-frontend/src/app/items/files/files.component.spec.js.map +++ /dev/null @@ -1 +0,0 @@ -{"version":3,"file":"app-files.component.spec.js","sourceRoot":"","sources":["app-files.component.spec.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA,iDAAkE;AAElE,6DAA0D;AAE1D,QAAQ,CAAC,mBAAmB,EAAE;IAC5B,IAAI,SAA4B,CAAC;IACjC,IAAI,OAA4C,CAAC;IAEjD,UAAU,CAAC;;;wBACT,qBAAM,iBAAO,CAAC,sBAAsB,CAAC;wBACnC,YAAY,EAAE,CAAE,uCAAiB,CAAE;qBACpC,CAAC;yBACD,iBAAiB,EAAE,EAAA;;oBAHpB,SAGoB,CAAC;;;;SACtB,CAAC,CAAC;IAEH,UAAU,CAAC;QACT,OAAO,GAAG,iBAAO,CAAC,eAAe,CAAC,uCAAiB,CAAC,CAAC;QACrD,SAAS,GAAG,OAAO,CAAC,iBAAiB,CAAC;QACtC,OAAO,CAAC,aAAa,EAAE,CAAC;IAC1B,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,eAAe,EAAE;QAClB,MAAM,CAAC,SAAS,CAAC,CAAC,UAAU,EAAE,CAAC;IACjC,CAAC,CAAC,CAAC;AACL,CAAC,CAAC,CAAC"} \ No newline at end of file diff --git a/projects/cobbler-frontend/src/app/items/files/files.component.spec.ts b/projects/cobbler-frontend/src/app/items/files/files.component.spec.ts deleted file mode 100644 index d2965396..00000000 --- a/projects/cobbler-frontend/src/app/items/files/files.component.spec.ts +++ /dev/null @@ -1,50 +0,0 @@ -import {HttpClientTestingModule, HttpTestingController} from '@angular/common/http/testing'; -import { ComponentFixture, TestBed } from '@angular/core/testing'; -import { MatButtonModule } from '@angular/material/button'; -import { MatFormFieldModule } from '@angular/material/form-field'; -import { MatInputModule } from '@angular/material/input'; -import { NoopAnimationsModule } from '@angular/platform-browser/animations'; -import {provideRouter} from '@angular/router'; -import {COBBLER_URL} from 'cobbler-api'; - -import { FilesComponent } from './files.component'; -import {ReactiveFormsModule} from "@angular/forms"; - - -describe('AppFilesComponent', () => { - let component: FilesComponent; - let fixture: ComponentFixture; - let httpTestingController: HttpTestingController; - - beforeEach(async () => { - await TestBed.configureTestingModule({ - imports: [ - FilesComponent, - HttpClientTestingModule, - ReactiveFormsModule, - MatButtonModule, - MatInputModule, - MatFormFieldModule, - NoopAnimationsModule, - ], - providers: [ - provideRouter([]), - { - provide: COBBLER_URL, - useValue: new URL('https://localhost/cobbler_api'), - }, - ] - }).compileComponents(); - httpTestingController = TestBed.inject(HttpTestingController); - }); - - beforeEach(() => { - fixture = TestBed.createComponent(FilesComponent); - component = fixture.componentInstance; - fixture.detectChanges(); - }); - - it('should create', () => { - expect(component).toBeTruthy(); - }); -}); diff --git a/projects/cobbler-frontend/src/app/items/files/files.component.ts b/projects/cobbler-frontend/src/app/items/files/files.component.ts deleted file mode 100644 index 00575704..00000000 --- a/projects/cobbler-frontend/src/app/items/files/files.component.ts +++ /dev/null @@ -1,108 +0,0 @@ -import { Component, inject, OnDestroy, signal } from '@angular/core'; -import { FilesService } from '../../services/files.service'; -import { RouterOutlet } from '@angular/router'; -import { MatFormFieldModule, MatLabel } from '@angular/material/form-field'; -import { MatButtonModule } from '@angular/material/button'; -import { - FormBuilder, - FormControl, - FormGroup, - ReactiveFormsModule, - Validators, -} from '@angular/forms'; -import { MatInputModule } from '@angular/material/input'; -import { Subscription } from 'rxjs'; -import { CobblerApiService } from 'cobbler-api'; - -@Component({ - selector: 'cobbler-files', - templateUrl: './files.component.html', - styleUrls: ['./files.component.css'], - standalone: true, - imports: [ - RouterOutlet, - MatFormFieldModule, - MatLabel, - MatButtonModule, - ReactiveFormsModule, - MatInputModule, - ], -}) -export class FilesComponent implements OnDestroy { - cobblerApiSvc = inject(CobblerApiService) - data = []; - - subs = new Subscription(); - filesForm: FormGroup; - - errorMsg = signal({ - action: '', - group: '', - mode: '', - path: '', - comment: '', - is_dir: '', - name: '', - owners: '', - template: '', - }); - - constructor(service: FilesService, private fb: FormBuilder) { - this.data = service.getAll(); - // this.subs.add( - // this.cobblerApiSvc.get_file('bert').subscribe(data=>{ - // console.log('svc', data) - // }) - // ) - // FIXME: This needs to be replaced by an overview view. This component is the detail view atm. - this.setForm(0) - this.subs.add( - this.filesForm.valueChanges.subscribe(() => { - this.updateErrMessage(); - }) - ); - } - - ngOnDestroy(): void { - this.subs.unsubscribe(); - } - - setForm(idx: number) { - this.filesForm = this.fb.group({ - action: new FormControl(this.data[idx].action), - group: new FormControl(this.data[idx].group, [Validators.required]), - mode: new FormControl(this.data[idx].mode, [Validators.required]), - path: new FormControl(this.data[idx].path, [Validators.required]), - comment: new FormControl(this.data[idx].comment), - is_dir: new FormControl(this.data[idx].is_dir), - name: new FormControl(this.data[idx].name, Validators.required), - owners: new FormControl(this.data[idx].owners, [Validators.required]), - template: new FormControl( - this.data[idx].template, - this.data[idx].is_dir ? [] : [Validators.required] - ), - }); - } - - updateErrMessage() { - if (this.filesForm.controls['name'].hasError('required')) { - this.errorMsg.update((err) => ({ ...err, name: 'Name is required' })); - } else { - this.errorMsg.update(() => ({ - action: '', - group: '', - mode: '', - path: '', - comment: '', - is_dir: '', - name: '', - owners: '', - template: '', - })); - } - } - - onSubmit() {} - - onCancle() {} -} diff --git a/projects/cobbler-frontend/src/app/items/image/edit/image-edit.component.html b/projects/cobbler-frontend/src/app/items/image/edit/image-edit.component.html new file mode 100644 index 00000000..098e9c53 --- /dev/null +++ b/projects/cobbler-frontend/src/app/items/image/edit/image-edit.component.html @@ -0,0 +1,104 @@ +
+
+

Name: {{ name }}

+ + + + + + + + + + + + +
+
+ +
+ + Name + + + + UID + + + + Last modified time + + + + Creation time + + + + Depth + + + Is Subobject? + + + Inherited + + + Comment + + + + Network Count + + + + Parent + + + + Arch + + + + Autoinstall + + + + Operating System Breed + + + + Image File + + + + Image Type + + + + Operating System Version + + + + + Inherited + + @if (isEditMode) { + + } +
diff --git a/projects/cobbler-frontend/src/app/items/image/edit/image-edit.component.scss b/projects/cobbler-frontend/src/app/items/image/edit/image-edit.component.scss new file mode 100644 index 00000000..2a9efa5d --- /dev/null +++ b/projects/cobbler-frontend/src/app/items/image/edit/image-edit.component.scss @@ -0,0 +1,30 @@ +.title-table { + display: table; + width: 100%; +} + +.title-row { + display: table-cell; + width: 100%; +} + +.title-cell-text { + display: table-cell; + width: 100%; + vertical-align: middle; +} + +.title-cell-button { + display: table-cell; +} + +.form-replicate { + min-width: 150px; + max-width: 600px; + width: 100%; +} + +.form-field-full-width { + width: 100%; +} + diff --git a/projects/cobbler-frontend/src/app/items/image/edit/image-edit.component.spec.ts b/projects/cobbler-frontend/src/app/items/image/edit/image-edit.component.spec.ts new file mode 100644 index 00000000..494a0b39 --- /dev/null +++ b/projects/cobbler-frontend/src/app/items/image/edit/image-edit.component.spec.ts @@ -0,0 +1,50 @@ +import {provideHttpClient} from '@angular/common/http'; +import {provideHttpClientTesting} from '@angular/common/http/testing'; +import { ComponentFixture, TestBed } from '@angular/core/testing'; +import {NoopAnimationsModule} from '@angular/platform-browser/animations'; +import {ActivatedRoute, provideRouter} from '@angular/router'; +import {COBBLER_URL} from 'cobbler-api'; + +import { ImageEditComponent } from './image-edit.component'; + +describe('ImageEditComponent', () => { + let component: ImageEditComponent; + let fixture: ComponentFixture; + + beforeEach(async () => { + await TestBed.configureTestingModule({ + imports: [ + ImageEditComponent, + NoopAnimationsModule, + ], + providers: [ + provideRouter([]), + provideHttpClient(), + provideHttpClientTesting(), + { + provide: COBBLER_URL, + useValue: new URL('http://localhost/cobbler_api') + }, + { + provide: ActivatedRoute, + useValue: { + snapshot: { + paramMap: { + get: () => "testimage" + }, + }, + }, + }, + ] + }) + .compileComponents(); + + fixture = TestBed.createComponent(ImageEditComponent); + component = fixture.componentInstance; + fixture.detectChanges(); + }); + + it('should create', () => { + expect(component).toBeTruthy(); + }); +}); diff --git a/projects/cobbler-frontend/src/app/items/image/edit/image-edit.component.ts b/projects/cobbler-frontend/src/app/items/image/edit/image-edit.component.ts new file mode 100644 index 00000000..15ef8ad8 --- /dev/null +++ b/projects/cobbler-frontend/src/app/items/image/edit/image-edit.component.ts @@ -0,0 +1,162 @@ +import {Component, inject, OnInit} from '@angular/core'; +import {FormBuilder, FormControl, FormsModule, ReactiveFormsModule} from '@angular/forms'; +import {MatOption} from '@angular/material/autocomplete'; +import {MatButton, MatIconButton} from '@angular/material/button'; +import {MatCheckbox} from '@angular/material/checkbox'; +import {MatFormField, MatLabel} from '@angular/material/form-field'; +import {MatIcon} from '@angular/material/icon'; +import {MatInput} from '@angular/material/input'; +import {MatSelect} from '@angular/material/select'; +import {MatSnackBar} from '@angular/material/snack-bar'; +import {MatTooltip} from '@angular/material/tooltip'; +import {ActivatedRoute, Router} from '@angular/router'; +import {CobblerApiService, Image} from 'cobbler-api'; +import {MultiSelectComponent} from '../../../common/multi-select/multi-select.component'; +import {UserService} from '../../../services/user.service'; + +@Component({ + selector: 'cobbler-image-edit', + standalone: true, + imports: [ + FormsModule, + MatButton, + MatCheckbox, + MatFormField, + MatIcon, + MatIconButton, + MatInput, + MatLabel, + MatOption, + MatSelect, + MatTooltip, + ReactiveFormsModule, + MultiSelectComponent + ], + templateUrl: './image-edit.component.html', + styleUrl: './image-edit.component.scss' +}) +export class ImageEditComponent implements OnInit{ + name: string; + image: Image; + private readonly _formBuilder = inject(FormBuilder); + imageFormGroup = this._formBuilder.group({ + name: new FormControl({value: "", disabled: true}), + uid: new FormControl({value: "", disabled: true}), + mtime: new FormControl({value: "", disabled: true}), + ctime: new FormControl({value: "", disabled: true}), + depth: new FormControl({value: 0, disabled: true}), + network_count: new FormControl({value: 0, disabled: true}), + is_subobject: new FormControl({value: false, disabled: true}), + comment: new FormControl({value: "", disabled: true}), + redhat_management_key: new FormControl({value: "", disabled: true}), + parent: new FormControl({value: "", disabled: true}), + arch: new FormControl({value: "", disabled: true}), + autoinstall: new FormControl({value: "", disabled: true}), + breed: new FormControl({value: "", disabled: true}), + file: new FormControl({value: "", disabled: true}), + image_type: new FormControl({value: "", disabled: true}), + os_version: new FormControl({value: "", disabled: true}), + boot_loaders: new FormControl({value: [], disabled: true}), + bootloader_inherited: new FormControl({value: false, disabled: true}), + owners: new FormControl({value: [], disabled: true}), + owners_inherited: new FormControl({value: false, disabled: true}), + }); + isEditMode: boolean = false; + + constructor( + private route: ActivatedRoute, + private userService: UserService, + private cobblerApiService: CobblerApiService, + private _snackBar: MatSnackBar, + private router: Router, + ) { + this.name = this.route.snapshot.paramMap.get("name"); + } + + ngOnInit(): void { + this.refreshData() + } + + refreshData(): void { + this.cobblerApiService.get_image(this.name, false, false, this.userService.token).subscribe(value => { + this.image = value + this.imageFormGroup.controls.name.setValue(this.image.name) + this.imageFormGroup.controls.uid.setValue(this.image.uid) + this.imageFormGroup.controls.mtime.setValue(new Date(this.image.mtime * 1000).toString()) + this.imageFormGroup.controls.ctime.setValue(new Date(this.image.ctime * 1000).toString()) + this.imageFormGroup.controls.depth.setValue(this.image.depth) + this.imageFormGroup.controls.network_count.setValue(this.image.network_count) + this.imageFormGroup.controls.is_subobject.setValue(this.image.is_subobject) + this.imageFormGroup.controls.comment.setValue(this.image.comment) + this.imageFormGroup.controls.parent.setValue(this.image.parent) + this.imageFormGroup.controls.arch.setValue(this.image.arch) + this.imageFormGroup.controls.autoinstall.setValue(this.image.autoinstall) + this.imageFormGroup.controls.breed.setValue(this.image.breed) + this.imageFormGroup.controls.file.setValue(this.image.file) + this.imageFormGroup.controls.image_type.setValue(this.image.image_type) + this.imageFormGroup.controls.os_version.setValue(this.image.os_version) + if (typeof this.image.boot_loaders === "string") { + this.imageFormGroup.controls.bootloader_inherited.setValue(true) + } else { + this.imageFormGroup.controls.bootloader_inherited.setValue(false) + this.imageFormGroup.controls.boot_loaders.setValue(this.image.boot_loaders) + } + if (typeof this.image.owners === "string") { + this.imageFormGroup.controls.owners_inherited.setValue(true) + } else { + this.imageFormGroup.controls.owners_inherited.setValue(false) + this.imageFormGroup.controls.owners.setValue(this.image.owners) + } + }, error => { + // HTML encode the error message since it originates from XML + this._snackBar.open(this.toHTML(error.message), 'Close'); + }); + } + + removeImage(): void { + this.cobblerApiService.remove_image(this.name, this.userService.token, false).subscribe(value => { + if (value) { + this.router.navigate(["/items", "image"]) + } + // HTML encode the error message since it originates from XML + this._snackBar.open("Delete failed! Check server logs for more information.", 'Close'); + }, error => { + // HTML encode the error message since it originates from XML + this._snackBar.open(this.toHTML(error.message), 'Close'); + }) + } + + editImage(): void { + // TODO + this._snackBar.open("Not implemented at the moment!", "Close") + } + + copyImage(): void { + this.cobblerApiService.copy_image("", "", this.userService.token) + .subscribe(value => { + // TODO + }, error => { + // HTML encode the error message since it originates from XML + this._snackBar.open(this.toHTML(error.message), 'Close'); + }) + } + + saveImage(): void { + // TODO + } + + get imageOwners(): string[] { + if (this.image && this.image.owners) { + const ownersResult = this.image.owners + if (typeof ownersResult !== 'string') { + return ownersResult; + } + } + return [] + } + + toHTML(input: string): any { + // FIXME: Deduplicate method + return new DOMParser().parseFromString(input, 'text/html').documentElement.textContent; + } +} diff --git a/projects/cobbler-frontend/src/app/items/image/overview/image-overview.component.html b/projects/cobbler-frontend/src/app/items/image/overview/image-overview.component.html new file mode 100644 index 00000000..2def2eec --- /dev/null +++ b/projects/cobbler-frontend/src/app/items/image/overview/image-overview.component.html @@ -0,0 +1,52 @@ +

IMAGES

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Name{{element.name}}Architecture{{element.arch}}Breed{{element.breed}}Operating System Version{{element.os_version}} + + + + + + +
+ diff --git a/projects/cobbler-frontend/src/app/items/profiles/profiles.component.css b/projects/cobbler-frontend/src/app/items/image/overview/image-overview.component.scss similarity index 100% rename from projects/cobbler-frontend/src/app/items/profiles/profiles.component.css rename to projects/cobbler-frontend/src/app/items/image/overview/image-overview.component.scss diff --git a/projects/cobbler-frontend/src/app/items/image/overview/image-overview.component.spec.ts b/projects/cobbler-frontend/src/app/items/image/overview/image-overview.component.spec.ts new file mode 100644 index 00000000..ef023a0c --- /dev/null +++ b/projects/cobbler-frontend/src/app/items/image/overview/image-overview.component.spec.ts @@ -0,0 +1,35 @@ +import {provideHttpClient} from '@angular/common/http'; +import {provideHttpClientTesting} from '@angular/common/http/testing'; +import { ComponentFixture, TestBed } from '@angular/core/testing'; +import {provideRouter} from '@angular/router'; +import {COBBLER_URL} from 'cobbler-api'; + +import { ImageOverviewComponent } from './image-overview.component'; + +describe('ImageOverviewComponent', () => { + let component: ImageOverviewComponent; + let fixture: ComponentFixture; + + beforeEach(async () => { + await TestBed.configureTestingModule({ + imports: [ImageOverviewComponent], + providers: [ + provideHttpClient(), + provideHttpClientTesting(), + { + provide: COBBLER_URL, + useValue: new URL('http://localhost/cobbler_api') + }, + ] + }) + .compileComponents(); + + fixture = TestBed.createComponent(ImageOverviewComponent); + component = fixture.componentInstance; + fixture.detectChanges(); + }); + + it('should create', () => { + expect(component).toBeTruthy(); + }); +}); diff --git a/projects/cobbler-frontend/src/app/items/image/overview/image-overview.component.ts b/projects/cobbler-frontend/src/app/items/image/overview/image-overview.component.ts new file mode 100644 index 00000000..57af48df --- /dev/null +++ b/projects/cobbler-frontend/src/app/items/image/overview/image-overview.component.ts @@ -0,0 +1,92 @@ +import {Component, OnInit, ViewChild} from '@angular/core'; +import {MatIconButton} from '@angular/material/button'; +import {MatIcon} from '@angular/material/icon'; +import {MatMenu, MatMenuItem, MatMenuTrigger} from '@angular/material/menu'; +import {MatSnackBar} from '@angular/material/snack-bar'; +import { + MatCell, + MatCellDef, + MatColumnDef, + MatHeaderCell, MatHeaderCellDef, + MatHeaderRow, + MatHeaderRowDef, + MatRow, MatRowDef, MatTable +} from '@angular/material/table'; +import {Router} from '@angular/router'; +import {CobblerApiService, Image} from 'cobbler-api'; +import {UserService} from '../../../services/user.service'; + +@Component({ + selector: 'cobbler-overview', + standalone: true, + imports: [ + MatCell, + MatCellDef, + MatColumnDef, + MatHeaderCell, + MatHeaderRow, + MatHeaderRowDef, + MatIcon, + MatIconButton, + MatMenu, + MatMenuItem, + MatRow, + MatRowDef, + MatTable, + MatMenuTrigger, + MatHeaderCellDef + ], + templateUrl: './image-overview.component.html', + styleUrl: './image-overview.component.scss' +}) +export class ImageOverviewComponent implements OnInit { + + displayedColumns: string[] = ['name', "arch", "breed", "os_version", "actions"]; + dataSource: Array = []; + + @ViewChild(MatTable) table: MatTable; + + constructor( + public userService: UserService, + private cobblerApiService: CobblerApiService, + private _snackBar: MatSnackBar, + private router: Router, + ) { + } + + ngOnInit(): void { + this.retrieveImages() + } + + private retrieveImages(): void { + this.cobblerApiService.get_images().subscribe(value => { + this.dataSource = value + }, error => { + // HTML encode the error message since it originates from XML + this._snackBar.open(this.toHTML(error.message), 'Close'); + }) + } + + showImage(uid: string, name: string): void { + this.router.navigate(["/items", "image", name]) + } + + editImage(uid: string, name: string): void { + // TODO + } + + deleteImage(uid: string, name: string): void { + this.cobblerApiService.remove_distro(name, this.userService.token, false).subscribe(value => { + this.retrieveImages() + }, error => { + // HTML encode the error message since it originates from XML + this._snackBar.open(this.toHTML(error.message), 'Close'); + }) + } + + toHTML(input: string): any { + // FIXME: Deduplicate method + return new DOMParser().parseFromString(input, 'text/html').documentElement.textContent; + } + +} diff --git a/projects/cobbler-frontend/src/app/items/images/images.component.html b/projects/cobbler-frontend/src/app/items/images/images.component.html deleted file mode 100644 index 96fc01e4..00000000 --- a/projects/cobbler-frontend/src/app/items/images/images.component.html +++ /dev/null @@ -1,26 +0,0 @@ -
-
- -

IMAGES

-
- - -
-
- @for(item of data;track item){ -
- - {{ item[3] }} - - -
- } -
-
-
diff --git a/projects/cobbler-frontend/src/app/items/images/images.component.spec.js b/projects/cobbler-frontend/src/app/items/images/images.component.spec.js deleted file mode 100644 index d1a1d9e9..00000000 --- a/projects/cobbler-frontend/src/app/items/images/images.component.spec.js +++ /dev/null @@ -1,66 +0,0 @@ -"use strict"; -var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { - function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } - return new (P || (P = Promise))(function (resolve, reject) { - function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } - function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } - function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } - step((generator = generator.apply(thisArg, _arguments || [])).next()); - }); -}; -var __generator = (this && this.__generator) || function (thisArg, body) { - var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g; - return g = { next: verb(0), "throw": verb(1), "return": verb(2) }, typeof Symbol === "function" && (g[Symbol.iterator] = function() { return this; }), g; - function verb(n) { return function (v) { return step([n, v]); }; } - function step(op) { - if (f) throw new TypeError("Generator is already executing."); - while (_) try { - if (f = 1, y && (t = op[0] & 2 ? y["return"] : op[0] ? y["throw"] || ((t = y["return"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t; - if (y = 0, t) op = [op[0] & 2, t.value]; - switch (op[0]) { - case 0: case 1: t = op; break; - case 4: _.label++; return { value: op[1], done: false }; - case 5: _.label++; y = op[1]; op = [0]; continue; - case 7: op = _.ops.pop(); _.trys.pop(); continue; - default: - if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; } - if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; } - if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; } - if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; } - if (t[2]) _.ops.pop(); - _.trys.pop(); continue; - } - op = body.call(thisArg, _); - } catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; } - if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true }; - } -}; -Object.defineProperty(exports, "__esModule", { value: true }); -var testing_1 = require("@angular/core/testing"); -var images_component_1 = require("./images.component"); -describe('ImagesComponent', function () { - var component; - var fixture; - beforeEach(function () { return __awaiter(void 0, void 0, void 0, function () { - return __generator(this, function (_a) { - switch (_a.label) { - case 0: return [4 /*yield*/, testing_1.TestBed.configureTestingModule({ - declarations: [images_component_1.ImagesComponent] - }) - .compileComponents()]; - case 1: - _a.sent(); - return [2 /*return*/]; - } - }); - }); }); - beforeEach(function () { - fixture = testing_1.TestBed.createComponent(images_component_1.ImagesComponent); - component = fixture.componentInstance; - fixture.detectChanges(); - }); - it('should create', function () { - expect(component).toBeTruthy(); - }); -}); -//# sourceMappingURL=images.component.spec.js.map \ No newline at end of file diff --git a/projects/cobbler-frontend/src/app/items/images/images.component.spec.js.map b/projects/cobbler-frontend/src/app/items/images/images.component.spec.js.map deleted file mode 100644 index 9024c3e4..00000000 --- a/projects/cobbler-frontend/src/app/items/images/images.component.spec.js.map +++ /dev/null @@ -1 +0,0 @@ -{"version":3,"file":"images.component.spec.js","sourceRoot":"","sources":["images.component.spec.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA,iDAAkE;AAElE,uDAAqD;AAErD,QAAQ,CAAC,iBAAiB,EAAE;IAC1B,IAAI,SAA0B,CAAC;IAC/B,IAAI,OAA0C,CAAC;IAE/C,UAAU,CAAC;;;wBACT,qBAAM,iBAAO,CAAC,sBAAsB,CAAC;wBACnC,YAAY,EAAE,CAAE,kCAAe,CAAE;qBAClC,CAAC;yBACD,iBAAiB,EAAE,EAAA;;oBAHpB,SAGoB,CAAC;;;;SACtB,CAAC,CAAC;IAEH,UAAU,CAAC;QACT,OAAO,GAAG,iBAAO,CAAC,eAAe,CAAC,kCAAe,CAAC,CAAC;QACnD,SAAS,GAAG,OAAO,CAAC,iBAAiB,CAAC;QACtC,OAAO,CAAC,aAAa,EAAE,CAAC;IAC1B,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,eAAe,EAAE;QAClB,MAAM,CAAC,SAAS,CAAC,CAAC,UAAU,EAAE,CAAC;IACjC,CAAC,CAAC,CAAC;AACL,CAAC,CAAC,CAAC"} \ No newline at end of file diff --git a/projects/cobbler-frontend/src/app/items/images/images.component.spec.ts b/projects/cobbler-frontend/src/app/items/images/images.component.spec.ts deleted file mode 100644 index 1ef42438..00000000 --- a/projects/cobbler-frontend/src/app/items/images/images.component.spec.ts +++ /dev/null @@ -1,39 +0,0 @@ -import { ComponentFixture, TestBed } from '@angular/core/testing'; -import { MatButtonModule } from '@angular/material/button'; -import { MatFormFieldModule } from '@angular/material/form-field'; -import { MatInputModule } from '@angular/material/input'; -import { NoopAnimationsModule } from '@angular/platform-browser/animations'; -import {provideRouter} from '@angular/router'; - -import { ImagesComponent } from './images.component'; - - -describe('ImagesComponent', () => { - let component: ImagesComponent; - let fixture: ComponentFixture; - - beforeEach(async () => { - await TestBed.configureTestingModule({ - imports: [ - ImagesComponent, - MatButtonModule, - MatFormFieldModule, - MatInputModule, - NoopAnimationsModule, - ], - providers: [ - provideRouter([]), - ] - }).compileComponents(); - }); - - beforeEach(() => { - fixture = TestBed.createComponent(ImagesComponent); - component = fixture.componentInstance; - fixture.detectChanges(); - }); - - it('should create', () => { - expect(component).toBeTruthy(); - }); -}); diff --git a/projects/cobbler-frontend/src/app/items/images/images.component.ts b/projects/cobbler-frontend/src/app/items/images/images.component.ts deleted file mode 100644 index 37666c28..00000000 --- a/projects/cobbler-frontend/src/app/items/images/images.component.ts +++ /dev/null @@ -1,21 +0,0 @@ -import {Component} from '@angular/core'; -import {ImagesService} from '../../services/images.service'; -import { RouterOutlet } from '@angular/router'; -import { MatInputModule } from "@angular/material/input"; -import {MatButtonModule} from "@angular/material/button"; - -@Component({ - selector: 'cobbler-images', - templateUrl: './images.component.html', - styleUrls: ['./images.component.css'], - standalone: true, - imports: [RouterOutlet, MatInputModule, MatButtonModule], -}) -export class ImagesComponent { - data = []; - - constructor(service: ImagesService) { - this.data = service.getAll(); - } - -} diff --git a/projects/cobbler-frontend/src/app/items/management-class/edit/management-class-edit.component.html b/projects/cobbler-frontend/src/app/items/management-class/edit/management-class-edit.component.html new file mode 100644 index 00000000..eb54ff4f --- /dev/null +++ b/projects/cobbler-frontend/src/app/items/management-class/edit/management-class-edit.component.html @@ -0,0 +1,82 @@ +
+
+

Name: {{ name }}

+ + + + + + + + + + + + +
+
+ +
+ + Name + + + + UID + + + + Last modified time + + + + Creation time + + + + Depth + + + Is Subobject? + + Comment + + + Is Definition? + + Class Name + + + + + + + + Inherited + + + + + + + + @if (isEditMode) { + + } +
diff --git a/projects/cobbler-frontend/src/app/items/management-class/edit/management-class-edit.component.scss b/projects/cobbler-frontend/src/app/items/management-class/edit/management-class-edit.component.scss new file mode 100644 index 00000000..2a9efa5d --- /dev/null +++ b/projects/cobbler-frontend/src/app/items/management-class/edit/management-class-edit.component.scss @@ -0,0 +1,30 @@ +.title-table { + display: table; + width: 100%; +} + +.title-row { + display: table-cell; + width: 100%; +} + +.title-cell-text { + display: table-cell; + width: 100%; + vertical-align: middle; +} + +.title-cell-button { + display: table-cell; +} + +.form-replicate { + min-width: 150px; + max-width: 600px; + width: 100%; +} + +.form-field-full-width { + width: 100%; +} + diff --git a/projects/cobbler-frontend/src/app/items/management-class/edit/management-class-edit.component.spec.ts b/projects/cobbler-frontend/src/app/items/management-class/edit/management-class-edit.component.spec.ts new file mode 100644 index 00000000..dfc975d3 --- /dev/null +++ b/projects/cobbler-frontend/src/app/items/management-class/edit/management-class-edit.component.spec.ts @@ -0,0 +1,50 @@ +import {provideHttpClient} from '@angular/common/http'; +import {provideHttpClientTesting} from '@angular/common/http/testing'; +import { ComponentFixture, TestBed } from '@angular/core/testing'; +import {NoopAnimationsModule} from '@angular/platform-browser/animations'; +import {ActivatedRoute, provideRouter} from '@angular/router'; +import {COBBLER_URL} from 'cobbler-api'; + +import { ManagementClassEditComponent } from './management-class-edit.component'; + +describe('ManagementClassEditComponent', () => { + let component: ManagementClassEditComponent; + let fixture: ComponentFixture; + + beforeEach(async () => { + await TestBed.configureTestingModule({ + imports: [ + ManagementClassEditComponent, + NoopAnimationsModule, + ], + providers: [ + provideRouter([]), + provideHttpClient(), + provideHttpClientTesting(), + { + provide: COBBLER_URL, + useValue: new URL('http://localhost/cobbler_api') + }, + { + provide: ActivatedRoute, + useValue: { + snapshot: { + paramMap: { + get: () => "testmgmtclass" + }, + }, + }, + }, + ] + }) + .compileComponents(); + + fixture = TestBed.createComponent(ManagementClassEditComponent); + component = fixture.componentInstance; + fixture.detectChanges(); + }); + + it('should create', () => { + expect(component).toBeTruthy(); + }); +}); diff --git a/projects/cobbler-frontend/src/app/items/management-class/edit/management-class-edit.component.ts b/projects/cobbler-frontend/src/app/items/management-class/edit/management-class-edit.component.ts new file mode 100644 index 00000000..f2d47ddf --- /dev/null +++ b/projects/cobbler-frontend/src/app/items/management-class/edit/management-class-edit.component.ts @@ -0,0 +1,150 @@ +import {Component, inject, OnInit} from '@angular/core'; +import {FormBuilder, FormControl, FormsModule, ReactiveFormsModule} from '@angular/forms'; +import {MatOption} from '@angular/material/autocomplete'; +import {MatButton, MatIconButton} from '@angular/material/button'; +import {MatCheckbox} from '@angular/material/checkbox'; +import {MatFormField, MatLabel} from '@angular/material/form-field'; +import {MatIcon} from '@angular/material/icon'; +import {MatInput} from '@angular/material/input'; +import {MatSelect} from '@angular/material/select'; +import {MatSnackBar} from '@angular/material/snack-bar'; +import {MatTooltip} from '@angular/material/tooltip'; +import {ActivatedRoute, Router} from '@angular/router'; +import {CobblerApiService, Mgmgtclass} from 'cobbler-api'; +import {KeyValueEditorComponent} from '../../../common/key-value-editor/key-value-editor.component'; +import {MultiSelectComponent} from '../../../common/multi-select/multi-select.component'; +import {UserService} from '../../../services/user.service'; + +@Component({ + selector: 'cobbler-edit', + standalone: true, + imports: [ + FormsModule, + MatButton, + MatCheckbox, + MatFormField, + MatIcon, + MatIconButton, + MatInput, + MatLabel, + MatOption, + MatSelect, + MatTooltip, + ReactiveFormsModule, + MultiSelectComponent, + KeyValueEditorComponent + ], + templateUrl: './management-class-edit.component.html', + styleUrl: './management-class-edit.component.scss' +}) +export class ManagementClassEditComponent implements OnInit { + name: string; + managementClass: Mgmgtclass; + private readonly _formBuilder = inject(FormBuilder); + managementClassFormGroup = this._formBuilder.group({ + name: new FormControl({value: "", disabled: true}), + uid: new FormControl({value: "", disabled: true}), + mtime: new FormControl({value: "", disabled: true}), + ctime: new FormControl({value: "", disabled: true}), + depth: new FormControl({value: 0, disabled: true}), + is_subobject: new FormControl({value: false, disabled: true}), + is_definition: new FormControl({value: false, disabled: true}), + comment: new FormControl({value: "", disabled: true}), + redhat_management_key: new FormControl({value: "", disabled: true}), + class_name: new FormControl({value: "", disabled: true}), + owners: new FormControl({value: [], disabled: true}), + owners_inherited: new FormControl({value: false, disabled: true}), + params: new FormControl({value: {}, disabled: true}), + files: new FormControl({value: [], disabled: true}), + packages: new FormControl({value: [], disabled: true}), + }); + isEditMode: boolean = false; + + constructor( + private route: ActivatedRoute, + private userService: UserService, + private cobblerApiService: CobblerApiService, + private _snackBar: MatSnackBar, + private router: Router, + ) { + this.name = this.route.snapshot.paramMap.get("name"); + } + + ngOnInit(): void { + this.refreshData() + } + + refreshData(): void { + this.cobblerApiService.get_mgmtclass(this.name, false, false, this.userService.token).subscribe(value => { + this.managementClass = value + this.managementClassFormGroup.controls.name.setValue(this.managementClass.name) + this.managementClassFormGroup.controls.uid.setValue(this.managementClass.uid) + this.managementClassFormGroup.controls.mtime.setValue(new Date(this.managementClass.mtime * 1000).toString()) + this.managementClassFormGroup.controls.ctime.setValue(new Date(this.managementClass.ctime * 1000).toString()) + this.managementClassFormGroup.controls.depth.setValue(this.managementClass.depth) + this.managementClassFormGroup.controls.is_subobject.setValue(this.managementClass.is_subobject) + this.managementClassFormGroup.controls.is_definition.setValue(this.managementClass.is_definition) + this.managementClassFormGroup.controls.comment.setValue(this.managementClass.comment) + this.managementClassFormGroup.controls.class_name.setValue(this.managementClass.class_name) + if (typeof this.managementClass.owners === "string") { + this.managementClassFormGroup.controls.owners_inherited.setValue(true) + } else { + this.managementClassFormGroup.controls.owners_inherited.setValue(false) + this.managementClassFormGroup.controls.owners.setValue(this.managementClass.owners) + } + this.managementClassFormGroup.controls.params.setValue(this.managementClass.params) + this.managementClassFormGroup.controls.files.setValue(this.managementClass.files) + this.managementClassFormGroup.controls.packages.setValue(this.managementClass.packages) + }, error => { + // HTML encode the error message since it originates from XML + this._snackBar.open(this.toHTML(error.message), 'Close'); + }); + } + + removeManagementClass(): void { + this.cobblerApiService.remove_mgmtclass(this.name, this.userService.token, false).subscribe(value => { + if (value) { + this.router.navigate(["/items", "profile"]) + } + // HTML encode the error message since it originates from XML + this._snackBar.open("Delete failed! Check server logs for more information.", 'Close'); + }, error => { + // HTML encode the error message since it originates from XML + this._snackBar.open(this.toHTML(error.message), 'Close'); + }) + } + + editProfile(): void { + // TODO + this._snackBar.open("Not implemented at the moment!", "Close") + } + + copyProfile(): void { + this.cobblerApiService.copy_mgmtclass("", "", this.userService.token) + .subscribe(value => { + // TODO + }, error => { + // HTML encode the error message since it originates from XML + this._snackBar.open(this.toHTML(error.message), 'Close'); + }) + } + + saveProfile(): void { + // TODO + } + + get mgmtClassOwners(): string[] { + if (this.managementClass && this.managementClass.owners) { + const ownersResult = this.managementClass.owners + if (typeof ownersResult !== 'string') { + return ownersResult; + } + } + return [] + } + + toHTML(input: string): any { + // FIXME: Deduplicate method + return new DOMParser().parseFromString(input, 'text/html').documentElement.textContent; + } +} diff --git a/projects/cobbler-frontend/src/app/items/management-class/overview/management-class-overview.component.html b/projects/cobbler-frontend/src/app/items/management-class/overview/management-class-overview.component.html new file mode 100644 index 00000000..961469ba --- /dev/null +++ b/projects/cobbler-frontend/src/app/items/management-class/overview/management-class-overview.component.html @@ -0,0 +1,46 @@ +

MANAGEMENT CLASSES

+ + + + + + + + + + + + + + + + + + + + + + + + + + + +
Name{{element.name}}Class Name{{element.class_name}}Is Definition?{{element.is_definition}} + + + + + + +
+ diff --git a/projects/cobbler-frontend/src/app/items/repos/repos.component.css b/projects/cobbler-frontend/src/app/items/management-class/overview/management-class-overview.component.scss similarity index 100% rename from projects/cobbler-frontend/src/app/items/repos/repos.component.css rename to projects/cobbler-frontend/src/app/items/management-class/overview/management-class-overview.component.scss diff --git a/projects/cobbler-frontend/src/app/items/management-class/overview/management-class-overview.component.spec.ts b/projects/cobbler-frontend/src/app/items/management-class/overview/management-class-overview.component.spec.ts new file mode 100644 index 00000000..3e27e522 --- /dev/null +++ b/projects/cobbler-frontend/src/app/items/management-class/overview/management-class-overview.component.spec.ts @@ -0,0 +1,36 @@ +import {provideHttpClient} from '@angular/common/http'; +import {provideHttpClientTesting} from '@angular/common/http/testing'; +import { ComponentFixture, TestBed } from '@angular/core/testing'; +import {provideRouter} from '@angular/router'; +import {COBBLER_URL} from 'cobbler-api'; + +import { ManagementClassOverviewComponent } from './management-class-overview.component'; + +describe('ManagementClassOverviewComponent', () => { + let component: ManagementClassOverviewComponent; + let fixture: ComponentFixture; + + beforeEach(async () => { + await TestBed.configureTestingModule({ + imports: [ManagementClassOverviewComponent], + providers: [ + provideRouter([]), + provideHttpClient(), + provideHttpClientTesting(), + { + provide: COBBLER_URL, + useValue: new URL('http://localhost/cobbler_api') + }, + ] + }) + .compileComponents(); + + fixture = TestBed.createComponent(ManagementClassOverviewComponent); + component = fixture.componentInstance; + fixture.detectChanges(); + }); + + it('should create', () => { + expect(component).toBeTruthy(); + }); +}); diff --git a/projects/cobbler-frontend/src/app/items/management-class/overview/management-class-overview.component.ts b/projects/cobbler-frontend/src/app/items/management-class/overview/management-class-overview.component.ts new file mode 100644 index 00000000..aa43423b --- /dev/null +++ b/projects/cobbler-frontend/src/app/items/management-class/overview/management-class-overview.component.ts @@ -0,0 +1,91 @@ +import {Component, OnInit, ViewChild} from '@angular/core'; +import {MatIconButton} from '@angular/material/button'; +import {MatIcon} from '@angular/material/icon'; +import {MatMenu, MatMenuItem, MatMenuTrigger} from '@angular/material/menu'; +import {MatSnackBar} from '@angular/material/snack-bar'; +import { + MatCell, + MatCellDef, + MatColumnDef, + MatHeaderCell, MatHeaderCellDef, + MatHeaderRow, + MatHeaderRowDef, + MatRow, MatRowDef, MatTable +} from '@angular/material/table'; +import {Router} from '@angular/router'; +import {CobblerApiService, Mgmgtclass} from 'cobbler-api'; +import {UserService} from '../../../services/user.service'; + +@Component({ + selector: 'cobbler-overview', + standalone: true, + imports: [ + MatCell, + MatCellDef, + MatColumnDef, + MatHeaderCell, + MatHeaderRow, + MatHeaderRowDef, + MatIcon, + MatIconButton, + MatMenu, + MatMenuItem, + MatRow, + MatRowDef, + MatTable, + MatHeaderCellDef, + MatMenuTrigger + ], + templateUrl: './management-class-overview.component.html', + styleUrl: './management-class-overview.component.scss' +}) +export class ManagementClassOverviewComponent implements OnInit { + displayedColumns: string[] = ['name', "class_name", "is_definition", "actions"]; + dataSource: Array = []; + + @ViewChild(MatTable) table: MatTable; + + constructor( + public userService: UserService, + private cobblerApiService: CobblerApiService, + private _snackBar: MatSnackBar, + private router: Router, + ) { + } + + ngOnInit(): void { + this.retrieveManagementClasses() + } + + private retrieveManagementClasses(): void { + this.cobblerApiService.get_mgmtclasses().subscribe(value => { + this.dataSource = value + }, error => { + // HTML encode the error message since it originates from XML + this._snackBar.open(this.toHTML(error.message), 'Close'); + }) + } + + showManagementClass(uid: string, name: string): void { + this.router.navigate(["/items", "management-class", name]) + } + + editManagementClass(uid: string, name: string): void { + // TODO + } + + deleteManagementClass(uid: string, name: string): void { + this.cobblerApiService.remove_mgmtclass(name, this.userService.token, false).subscribe(value => { + this.retrieveManagementClasses() + }, error => { + // HTML encode the error message since it originates from XML + this._snackBar.open(this.toHTML(error.message), 'Close'); + }) + } + + toHTML(input: string): any { + // FIXME: Deduplicate method + return new DOMParser().parseFromString(input, 'text/html').documentElement.textContent; + } + +} diff --git a/projects/cobbler-frontend/src/app/items/management-classes/management-classes.component.html b/projects/cobbler-frontend/src/app/items/management-classes/management-classes.component.html deleted file mode 100644 index 0c23793c..00000000 --- a/projects/cobbler-frontend/src/app/items/management-classes/management-classes.component.html +++ /dev/null @@ -1,26 +0,0 @@ -
-
- -

MANAGEMENT CLASSES

-
- - -
-
- @for(item of data;track item){ -
- - {{ item[3] }} - - -
- } -
-
-
diff --git a/projects/cobbler-frontend/src/app/items/management-classes/management-classes.component.spec.js b/projects/cobbler-frontend/src/app/items/management-classes/management-classes.component.spec.js deleted file mode 100644 index e1dbef87..00000000 --- a/projects/cobbler-frontend/src/app/items/management-classes/management-classes.component.spec.js +++ /dev/null @@ -1,66 +0,0 @@ -"use strict"; -var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { - function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } - return new (P || (P = Promise))(function (resolve, reject) { - function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } - function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } - function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } - step((generator = generator.apply(thisArg, _arguments || [])).next()); - }); -}; -var __generator = (this && this.__generator) || function (thisArg, body) { - var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g; - return g = { next: verb(0), "throw": verb(1), "return": verb(2) }, typeof Symbol === "function" && (g[Symbol.iterator] = function() { return this; }), g; - function verb(n) { return function (v) { return step([n, v]); }; } - function step(op) { - if (f) throw new TypeError("Generator is already executing."); - while (_) try { - if (f = 1, y && (t = op[0] & 2 ? y["return"] : op[0] ? y["throw"] || ((t = y["return"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t; - if (y = 0, t) op = [op[0] & 2, t.value]; - switch (op[0]) { - case 0: case 1: t = op; break; - case 4: _.label++; return { value: op[1], done: false }; - case 5: _.label++; y = op[1]; op = [0]; continue; - case 7: op = _.ops.pop(); _.trys.pop(); continue; - default: - if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; } - if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; } - if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; } - if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; } - if (t[2]) _.ops.pop(); - _.trys.pop(); continue; - } - op = body.call(thisArg, _); - } catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; } - if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true }; - } -}; -Object.defineProperty(exports, "__esModule", { value: true }); -var testing_1 = require("@angular/core/testing"); -var management_classes_component_1 = require("./management-classes.component"); -describe('ManagementClassesComponent', function () { - var component; - var fixture; - beforeEach(function () { return __awaiter(void 0, void 0, void 0, function () { - return __generator(this, function (_a) { - switch (_a.label) { - case 0: return [4 /*yield*/, testing_1.TestBed.configureTestingModule({ - declarations: [management_classes_component_1.ManagementClassesComponent] - }) - .compileComponents()]; - case 1: - _a.sent(); - return [2 /*return*/]; - } - }); - }); }); - beforeEach(function () { - fixture = testing_1.TestBed.createComponent(management_classes_component_1.ManagementClassesComponent); - component = fixture.componentInstance; - fixture.detectChanges(); - }); - it('should create', function () { - expect(component).toBeTruthy(); - }); -}); -//# sourceMappingURL=management-classes.component.spec.js.map \ No newline at end of file diff --git a/projects/cobbler-frontend/src/app/items/management-classes/management-classes.component.spec.js.map b/projects/cobbler-frontend/src/app/items/management-classes/management-classes.component.spec.js.map deleted file mode 100644 index 2597f168..00000000 --- a/projects/cobbler-frontend/src/app/items/management-classes/management-classes.component.spec.js.map +++ /dev/null @@ -1 +0,0 @@ -{"version":3,"file":"management-classes.component.spec.js","sourceRoot":"","sources":["management-classes.component.spec.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA,iDAAkE;AAElE,+EAA4E;AAE5E,QAAQ,CAAC,4BAA4B,EAAE;IACrC,IAAI,SAAqC,CAAC;IAC1C,IAAI,OAAqD,CAAC;IAE1D,UAAU,CAAC;;;wBACT,qBAAM,iBAAO,CAAC,sBAAsB,CAAC;wBACnC,YAAY,EAAE,CAAE,yDAA0B,CAAE;qBAC7C,CAAC;yBACD,iBAAiB,EAAE,EAAA;;oBAHpB,SAGoB,CAAC;;;;SACtB,CAAC,CAAC;IAEH,UAAU,CAAC;QACT,OAAO,GAAG,iBAAO,CAAC,eAAe,CAAC,yDAA0B,CAAC,CAAC;QAC9D,SAAS,GAAG,OAAO,CAAC,iBAAiB,CAAC;QACtC,OAAO,CAAC,aAAa,EAAE,CAAC;IAC1B,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,eAAe,EAAE;QAClB,MAAM,CAAC,SAAS,CAAC,CAAC,UAAU,EAAE,CAAC;IACjC,CAAC,CAAC,CAAC;AACL,CAAC,CAAC,CAAC"} \ No newline at end of file diff --git a/projects/cobbler-frontend/src/app/items/management-classes/management-classes.component.spec.ts b/projects/cobbler-frontend/src/app/items/management-classes/management-classes.component.spec.ts deleted file mode 100644 index cc34ee58..00000000 --- a/projects/cobbler-frontend/src/app/items/management-classes/management-classes.component.spec.ts +++ /dev/null @@ -1,39 +0,0 @@ -import { ComponentFixture, TestBed } from '@angular/core/testing'; -import { MatButtonModule } from '@angular/material/button'; -import { MatFormFieldModule } from '@angular/material/form-field'; -import { MatInputModule } from '@angular/material/input'; -import { NoopAnimationsModule } from '@angular/platform-browser/animations'; -import {provideRouter} from '@angular/router'; - -import { ManagementClassesComponent } from './management-classes.component'; - - -describe('ManagementClassesComponent', () => { - let component: ManagementClassesComponent; - let fixture: ComponentFixture; - - beforeEach(async () => { - await TestBed.configureTestingModule({ - imports: [ - MatButtonModule, - MatFormFieldModule, - MatInputModule, - NoopAnimationsModule, - ManagementClassesComponent, - ], - providers: [ - provideRouter([]), - ] - }).compileComponents(); - }); - - beforeEach(() => { - fixture = TestBed.createComponent(ManagementClassesComponent); - component = fixture.componentInstance; - fixture.detectChanges(); - }); - - it('should create', () => { - expect(component).toBeTruthy(); - }); -}); diff --git a/projects/cobbler-frontend/src/app/items/management-classes/management-classes.component.ts b/projects/cobbler-frontend/src/app/items/management-classes/management-classes.component.ts deleted file mode 100644 index c01216b2..00000000 --- a/projects/cobbler-frontend/src/app/items/management-classes/management-classes.component.ts +++ /dev/null @@ -1,22 +0,0 @@ -import {Component} from '@angular/core'; -import {MngclassesService} from '../../services/mngclasses.service'; -import { RouterOutlet } from '@angular/router'; -import {MatButtonModule} from "@angular/material/button"; -import {MatFormFieldModule} from "@angular/material/form-field"; -import {MatInputModule} from "@angular/material/input"; - -@Component({ - selector: 'cobbler-management-classes', - templateUrl: './management-classes.component.html', - styleUrls: ['./management-classes.component.css'], - standalone: true, - imports: [RouterOutlet, MatButtonModule, MatFormFieldModule, MatInputModule], -}) -export class ManagementClassesComponent { - data = []; - - constructor(service: MngclassesService) { - this.data = service.getAll(); - } - -} diff --git a/projects/cobbler-frontend/src/app/items/package/edit/package-edit.component.html b/projects/cobbler-frontend/src/app/items/package/edit/package-edit.component.html new file mode 100644 index 00000000..95e086d9 --- /dev/null +++ b/projects/cobbler-frontend/src/app/items/package/edit/package-edit.component.html @@ -0,0 +1,101 @@ +
+
+

Name: {{ name }}

+ + + + + + + + + + + + +
+
+ +
+ + Name + + + + UID + + + + Last modified time + + + + Creation time + + + + Depth + + + Is Subobject? + + Comment + + + + Mode + + + + Owner + + + + Group + + + + Path + + + + Template + + + + Action + + + + Installer + + + + Version + + + + + Inherited + + @if (isEditMode) { + + } +
+ diff --git a/projects/cobbler-frontend/src/app/items/package/edit/package-edit.component.scss b/projects/cobbler-frontend/src/app/items/package/edit/package-edit.component.scss new file mode 100644 index 00000000..2a9efa5d --- /dev/null +++ b/projects/cobbler-frontend/src/app/items/package/edit/package-edit.component.scss @@ -0,0 +1,30 @@ +.title-table { + display: table; + width: 100%; +} + +.title-row { + display: table-cell; + width: 100%; +} + +.title-cell-text { + display: table-cell; + width: 100%; + vertical-align: middle; +} + +.title-cell-button { + display: table-cell; +} + +.form-replicate { + min-width: 150px; + max-width: 600px; + width: 100%; +} + +.form-field-full-width { + width: 100%; +} + diff --git a/projects/cobbler-frontend/src/app/items/package/edit/package-edit.component.spec.ts b/projects/cobbler-frontend/src/app/items/package/edit/package-edit.component.spec.ts new file mode 100644 index 00000000..d78114d4 --- /dev/null +++ b/projects/cobbler-frontend/src/app/items/package/edit/package-edit.component.spec.ts @@ -0,0 +1,50 @@ +import {provideHttpClient} from '@angular/common/http'; +import {provideHttpClientTesting} from '@angular/common/http/testing'; +import { ComponentFixture, TestBed } from '@angular/core/testing'; +import {NoopAnimationsModule} from '@angular/platform-browser/animations'; +import {ActivatedRoute, provideRouter} from '@angular/router'; +import {COBBLER_URL} from 'cobbler-api'; + +import { PackageEditComponent } from './package-edit.component'; + +describe('PackageEditComponent', () => { + let component: PackageEditComponent; + let fixture: ComponentFixture; + + beforeEach(async () => { + await TestBed.configureTestingModule({ + imports: [ + PackageEditComponent, + NoopAnimationsModule, + ], + providers: [ + provideRouter([]), + provideHttpClient(), + provideHttpClientTesting(), + { + provide: COBBLER_URL, + useValue: new URL('http://localhost/cobbler_api') + }, + { + provide: ActivatedRoute, + useValue: { + snapshot: { + paramMap: { + get: () => "testpackage" + }, + }, + }, + }, + ] + }) + .compileComponents(); + + fixture = TestBed.createComponent(PackageEditComponent); + component = fixture.componentInstance; + fixture.detectChanges(); + }); + + it('should create', () => { + expect(component).toBeTruthy(); + }); +}); diff --git a/projects/cobbler-frontend/src/app/items/package/edit/package-edit.component.ts b/projects/cobbler-frontend/src/app/items/package/edit/package-edit.component.ts new file mode 100644 index 00000000..a65ab926 --- /dev/null +++ b/projects/cobbler-frontend/src/app/items/package/edit/package-edit.component.ts @@ -0,0 +1,154 @@ +import {Component, inject, OnInit} from '@angular/core'; +import {FormBuilder, FormControl, FormsModule, ReactiveFormsModule} from '@angular/forms'; +import {MatOption} from '@angular/material/autocomplete'; +import {MatButton, MatIconButton} from '@angular/material/button'; +import {MatCheckbox} from '@angular/material/checkbox'; +import {MatFormField, MatLabel} from '@angular/material/form-field'; +import {MatIcon} from '@angular/material/icon'; +import {MatInput} from '@angular/material/input'; +import {MatSelect} from '@angular/material/select'; +import {MatSnackBar} from '@angular/material/snack-bar'; +import {MatTooltip} from '@angular/material/tooltip'; +import {ActivatedRoute, Router} from '@angular/router'; +import {CobblerApiService, Package} from 'cobbler-api'; +import {MultiSelectComponent} from '../../../common/multi-select/multi-select.component'; +import {UserService} from '../../../services/user.service'; + +@Component({ + selector: 'cobbler-edit', + standalone: true, + imports: [ + FormsModule, + MatButton, + MatCheckbox, + MatFormField, + MatIcon, + MatIconButton, + MatInput, + MatLabel, + MatOption, + MatSelect, + MatTooltip, + ReactiveFormsModule, + MultiSelectComponent + ], + templateUrl: './package-edit.component.html', + styleUrl: './package-edit.component.scss' +}) +export class PackageEditComponent implements OnInit { + name: string; + package: Package; + private readonly _formBuilder = inject(FormBuilder); + packageFormGroup = this._formBuilder.group({ + name: new FormControl({value: "", disabled: true}), + uid: new FormControl({value: "", disabled: true}), + mtime: new FormControl({value: "", disabled: true}), + ctime: new FormControl({value: "", disabled: true}), + depth: new FormControl({value: 0, disabled: true}), + is_subobject: new FormControl({value: false, disabled: true}), + comment: new FormControl({value: "", disabled: true}), + redhat_management_key: new FormControl({value: "", disabled: true}), + mode: new FormControl({value: "", disabled: true}), + owner: new FormControl({value: "", disabled: true}), + group: new FormControl({value: "", disabled: true}), + path: new FormControl({value: "", disabled: true}), + template: new FormControl({value: "", disabled: true}), + action: new FormControl({value: "", disabled: true}), + installer: new FormControl({value: "", disabled: true}), + version: new FormControl({value: "", disabled: true}), + owners: new FormControl({value: [], disabled: true}), + owners_inherited: new FormControl({value: false, disabled: true}), + }); + isEditMode: boolean = false; + + constructor( + private route: ActivatedRoute, + private userService: UserService, + private cobblerApiService: CobblerApiService, + private _snackBar: MatSnackBar, + private router: Router, + ) { + this.name = this.route.snapshot.paramMap.get("name"); + } + + ngOnInit(): void { + this.refreshData() + } + + refreshData(): void { + this.cobblerApiService.get_package(this.name, false, false, this.userService.token).subscribe(value => { + this.package = value + this.packageFormGroup.controls.name.setValue(this.package.name) + this.packageFormGroup.controls.uid.setValue(this.package.uid) + this.packageFormGroup.controls.mtime.setValue(new Date(this.package.mtime * 1000).toString()) + this.packageFormGroup.controls.ctime.setValue(new Date(this.package.ctime * 1000).toString()) + this.packageFormGroup.controls.depth.setValue(this.package.depth) + this.packageFormGroup.controls.is_subobject.setValue(this.package.is_subobject) + this.packageFormGroup.controls.comment.setValue(this.package.comment) + this.packageFormGroup.controls.mode.setValue(this.package.mode) + this.packageFormGroup.controls.owner.setValue(this.package.owner) + this.packageFormGroup.controls.group.setValue(this.package.group) + this.packageFormGroup.controls.path.setValue(this.package.path) + this.packageFormGroup.controls.template.setValue(this.package.template) + this.packageFormGroup.controls.action.setValue(this.package.action) + this.packageFormGroup.controls.installer.setValue(this.package.installer) + this.packageFormGroup.controls.version.setValue(this.package.version) + if (typeof this.package.owners === "string") { + this.packageFormGroup.controls.owners_inherited.setValue(true) + } else { + this.packageFormGroup.controls.owners_inherited.setValue(false) + this.packageFormGroup.controls.owners.setValue(this.package.owners) + } + }, error => { + // HTML encode the error message since it originates from XML + this._snackBar.open(this.toHTML(error.message), 'Close'); + }); + } + + removePackage(): void { + this.cobblerApiService.remove_package(this.name, this.userService.token, false).subscribe(value => { + if (value) { + this.router.navigate(["/items", "package"]) + } + // HTML encode the error message since it originates from XML + this._snackBar.open("Delete failed! Check server logs for more information.", 'Close'); + }, error => { + // HTML encode the error message since it originates from XML + this._snackBar.open(this.toHTML(error.message), 'Close'); + }) + } + + editPackage(): void { + // TODO + this._snackBar.open("Not implemented at the moment!", "Close") + } + + copyPackage(): void { + this.cobblerApiService.copy_package("", "", this.userService.token) + .subscribe(value => { + // TODO + }, error => { + // HTML encode the error message since it originates from XML + this._snackBar.open(this.toHTML(error.message), 'Close'); + }) + } + + savePackage(): void { + // TODO + } + + get packageOwners(): string[] { + if (this.package && this.package.owners) { + const ownersResult = this.package.owners + if (typeof ownersResult !== 'string') { + return ownersResult; + } + } + return [] + } + + toHTML(input: string): any { + // FIXME: Deduplicate method + return new DOMParser().parseFromString(input, 'text/html').documentElement.textContent; + } +} diff --git a/projects/cobbler-frontend/src/app/items/package/overview/package-overview.component.html b/projects/cobbler-frontend/src/app/items/package/overview/package-overview.component.html new file mode 100644 index 00000000..e84d1b7a --- /dev/null +++ b/projects/cobbler-frontend/src/app/items/package/overview/package-overview.component.html @@ -0,0 +1,46 @@ +

PACKAGES

+ + + + + + + + + + + + + + + + + + + + + + + + + + + +
Name{{element.name}}Installer{{element.installer}}Version{{element.version}} + + + + + + +
+ diff --git a/projects/cobbler-frontend/src/app/items/snippets/snippets.component.css b/projects/cobbler-frontend/src/app/items/package/overview/package-overview.component.scss similarity index 100% rename from projects/cobbler-frontend/src/app/items/snippets/snippets.component.css rename to projects/cobbler-frontend/src/app/items/package/overview/package-overview.component.scss diff --git a/projects/cobbler-frontend/src/app/items/package/overview/package-overview.component.spec.ts b/projects/cobbler-frontend/src/app/items/package/overview/package-overview.component.spec.ts new file mode 100644 index 00000000..8453d71f --- /dev/null +++ b/projects/cobbler-frontend/src/app/items/package/overview/package-overview.component.spec.ts @@ -0,0 +1,35 @@ +import {provideHttpClient} from '@angular/common/http'; +import {provideHttpClientTesting} from '@angular/common/http/testing'; +import { ComponentFixture, TestBed } from '@angular/core/testing'; +import {provideRouter} from '@angular/router'; +import {COBBLER_URL} from 'cobbler-api'; + +import { PackageOverviewComponent } from './package-overview.component'; + +describe('PackageOverviewComponent', () => { + let component: PackageOverviewComponent; + let fixture: ComponentFixture; + + beforeEach(async () => { + await TestBed.configureTestingModule({ + imports: [PackageOverviewComponent], + providers: [ + provideHttpClient(), + provideHttpClientTesting(), + { + provide: COBBLER_URL, + useValue: new URL('http://localhost/cobbler_api') + }, + ] + }) + .compileComponents(); + + fixture = TestBed.createComponent(PackageOverviewComponent); + component = fixture.componentInstance; + fixture.detectChanges(); + }); + + it('should create', () => { + expect(component).toBeTruthy(); + }); +}); diff --git a/projects/cobbler-frontend/src/app/items/package/overview/package-overview.component.ts b/projects/cobbler-frontend/src/app/items/package/overview/package-overview.component.ts new file mode 100644 index 00000000..6e733691 --- /dev/null +++ b/projects/cobbler-frontend/src/app/items/package/overview/package-overview.component.ts @@ -0,0 +1,90 @@ +import {Component, OnInit, ViewChild} from '@angular/core'; +import {MatIconButton} from '@angular/material/button'; +import {MatIcon} from '@angular/material/icon'; +import {MatMenu, MatMenuItem, MatMenuTrigger} from '@angular/material/menu'; +import {MatSnackBar} from '@angular/material/snack-bar'; +import { + MatCell, + MatCellDef, + MatColumnDef, + MatHeaderCell, MatHeaderCellDef, + MatHeaderRow, + MatHeaderRowDef, + MatRow, MatRowDef, MatTable +} from '@angular/material/table'; +import {Router} from '@angular/router'; +import {CobblerApiService, Package} from 'cobbler-api'; +import {UserService} from '../../../services/user.service'; + +@Component({ + selector: 'cobbler-overview', + standalone: true, + imports: [ + MatCell, + MatCellDef, + MatColumnDef, + MatHeaderCell, + MatHeaderRow, + MatHeaderRowDef, + MatIcon, + MatIconButton, + MatMenu, + MatMenuItem, + MatRow, + MatRowDef, + MatTable, + MatMenuTrigger, + MatHeaderCellDef + ], + templateUrl: './package-overview.component.html', + styleUrl: './package-overview.component.scss' +}) +export class PackageOverviewComponent implements OnInit { + displayedColumns: string[] = ['name', "installer", "version", "actions"]; + dataSource: Array = []; + + @ViewChild(MatTable) table: MatTable; + + constructor( + public userService: UserService, + private cobblerApiService: CobblerApiService, + private _snackBar: MatSnackBar, + private router: Router, + ) { + } + + ngOnInit(): void { + this.retrievePackages() + } + + private retrievePackages(): void { + this.cobblerApiService.get_packages().subscribe(value => { + this.dataSource = value + }, error => { + // HTML encode the error message since it originates from XML + this._snackBar.open(this.toHTML(error.message), 'Close'); + }) + } + + showPackage(uid: string, name: string): void { + this.router.navigate(["/items", "package", name]) + } + + editPackage(uid: string, name: string): void { + // TODO + } + + deletePackage(uid: string, name: string): void { + this.cobblerApiService.remove_package(name, this.userService.token, false).subscribe(value => { + this.retrievePackages() + }, error => { + // HTML encode the error message since it originates from XML + this._snackBar.open(this.toHTML(error.message), 'Close'); + }) + } + + toHTML(input: string): any { + // FIXME: Deduplicate method + return new DOMParser().parseFromString(input, 'text/html').documentElement.textContent; + } +} diff --git a/projects/cobbler-frontend/src/app/items/packages/packages.component.html b/projects/cobbler-frontend/src/app/items/packages/packages.component.html deleted file mode 100644 index a6cea1d2..00000000 --- a/projects/cobbler-frontend/src/app/items/packages/packages.component.html +++ /dev/null @@ -1,26 +0,0 @@ -
- -

PACKAGES

-
-
- - -
-
- @for(item of data;track item){ -
- - {{ item[3] }} - - -
- } -
-
-
diff --git a/projects/cobbler-frontend/src/app/items/packages/packages.component.spec.js b/projects/cobbler-frontend/src/app/items/packages/packages.component.spec.js deleted file mode 100644 index 36512660..00000000 --- a/projects/cobbler-frontend/src/app/items/packages/packages.component.spec.js +++ /dev/null @@ -1,66 +0,0 @@ -"use strict"; -var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { - function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } - return new (P || (P = Promise))(function (resolve, reject) { - function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } - function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } - function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } - step((generator = generator.apply(thisArg, _arguments || [])).next()); - }); -}; -var __generator = (this && this.__generator) || function (thisArg, body) { - var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g; - return g = { next: verb(0), "throw": verb(1), "return": verb(2) }, typeof Symbol === "function" && (g[Symbol.iterator] = function() { return this; }), g; - function verb(n) { return function (v) { return step([n, v]); }; } - function step(op) { - if (f) throw new TypeError("Generator is already executing."); - while (_) try { - if (f = 1, y && (t = op[0] & 2 ? y["return"] : op[0] ? y["throw"] || ((t = y["return"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t; - if (y = 0, t) op = [op[0] & 2, t.value]; - switch (op[0]) { - case 0: case 1: t = op; break; - case 4: _.label++; return { value: op[1], done: false }; - case 5: _.label++; y = op[1]; op = [0]; continue; - case 7: op = _.ops.pop(); _.trys.pop(); continue; - default: - if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; } - if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; } - if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; } - if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; } - if (t[2]) _.ops.pop(); - _.trys.pop(); continue; - } - op = body.call(thisArg, _); - } catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; } - if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true }; - } -}; -Object.defineProperty(exports, "__esModule", { value: true }); -var testing_1 = require("@angular/core/testing"); -var packages_component_1 = require("./packages.component"); -describe('PackagesComponent', function () { - var component; - var fixture; - beforeEach(function () { return __awaiter(void 0, void 0, void 0, function () { - return __generator(this, function (_a) { - switch (_a.label) { - case 0: return [4 /*yield*/, testing_1.TestBed.configureTestingModule({ - declarations: [packages_component_1.PackagesComponent] - }) - .compileComponents()]; - case 1: - _a.sent(); - return [2 /*return*/]; - } - }); - }); }); - beforeEach(function () { - fixture = testing_1.TestBed.createComponent(packages_component_1.PackagesComponent); - component = fixture.componentInstance; - fixture.detectChanges(); - }); - it('should create', function () { - expect(component).toBeTruthy(); - }); -}); -//# sourceMappingURL=packages.component.spec.js.map \ No newline at end of file diff --git a/projects/cobbler-frontend/src/app/items/packages/packages.component.spec.js.map b/projects/cobbler-frontend/src/app/items/packages/packages.component.spec.js.map deleted file mode 100644 index 81ac4df1..00000000 --- a/projects/cobbler-frontend/src/app/items/packages/packages.component.spec.js.map +++ /dev/null @@ -1 +0,0 @@ -{"version":3,"file":"packages.component.spec.js","sourceRoot":"","sources":["packages.component.spec.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA,iDAAkE;AAElE,2DAAyD;AAEzD,QAAQ,CAAC,mBAAmB,EAAE;IAC5B,IAAI,SAA4B,CAAC;IACjC,IAAI,OAA4C,CAAC;IAEjD,UAAU,CAAC;;;wBACT,qBAAM,iBAAO,CAAC,sBAAsB,CAAC;wBACnC,YAAY,EAAE,CAAE,sCAAiB,CAAE;qBACpC,CAAC;yBACD,iBAAiB,EAAE,EAAA;;oBAHpB,SAGoB,CAAC;;;;SACtB,CAAC,CAAC;IAEH,UAAU,CAAC;QACT,OAAO,GAAG,iBAAO,CAAC,eAAe,CAAC,sCAAiB,CAAC,CAAC;QACrD,SAAS,GAAG,OAAO,CAAC,iBAAiB,CAAC;QACtC,OAAO,CAAC,aAAa,EAAE,CAAC;IAC1B,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,eAAe,EAAE;QAClB,MAAM,CAAC,SAAS,CAAC,CAAC,UAAU,EAAE,CAAC;IACjC,CAAC,CAAC,CAAC;AACL,CAAC,CAAC,CAAC"} \ No newline at end of file diff --git a/projects/cobbler-frontend/src/app/items/packages/packages.component.spec.ts b/projects/cobbler-frontend/src/app/items/packages/packages.component.spec.ts deleted file mode 100644 index bff01db7..00000000 --- a/projects/cobbler-frontend/src/app/items/packages/packages.component.spec.ts +++ /dev/null @@ -1,38 +0,0 @@ -import { ComponentFixture, TestBed } from '@angular/core/testing'; -import { MatButtonModule } from '@angular/material/button'; -import { MatFormFieldModule } from '@angular/material/form-field'; -import { MatInputModule } from '@angular/material/input'; -import { NoopAnimationsModule } from '@angular/platform-browser/animations'; -import {provideRouter} from '@angular/router'; - -import { PackagesComponent } from './packages.component'; - -describe('PackagesComponent', () => { - let component: PackagesComponent; - let fixture: ComponentFixture; - - beforeEach(async () => { - await TestBed.configureTestingModule({ - imports: [ - PackagesComponent, - MatInputModule, - MatFormFieldModule, - MatButtonModule, - NoopAnimationsModule, - ], - providers: [ - provideRouter([]), - ] - }).compileComponents(); - }); - - beforeEach(() => { - fixture = TestBed.createComponent(PackagesComponent); - component = fixture.componentInstance; - fixture.detectChanges(); - }); - - it('should create', () => { - expect(component).toBeTruthy(); - }); -}); diff --git a/projects/cobbler-frontend/src/app/items/packages/packages.component.ts b/projects/cobbler-frontend/src/app/items/packages/packages.component.ts deleted file mode 100644 index 63c9e0be..00000000 --- a/projects/cobbler-frontend/src/app/items/packages/packages.component.ts +++ /dev/null @@ -1,21 +0,0 @@ -import {Component} from '@angular/core'; -import {PackagesService} from '../../services/packages.service'; -import { RouterOutlet } from '@angular/router'; -import {MatFormFieldModule} from "@angular/material/form-field"; -import {MatInputModule} from "@angular/material/input"; -import {MatButtonModule} from "@angular/material/button"; - -@Component({ - selector: 'cobbler-packages', - templateUrl: './packages.component.html', - styleUrls: ['./packages.component.css'], - standalone: true, - imports: [RouterOutlet, MatFormFieldModule, MatInputModule, MatButtonModule], -}) -export class PackagesComponent { - data = []; - - constructor(service: PackagesService) { - this.data = service.getAll(); - } -} diff --git a/projects/cobbler-frontend/src/app/items/profile/edit/profile-edit.component.html b/projects/cobbler-frontend/src/app/items/profile/edit/profile-edit.component.html new file mode 100644 index 00000000..fd3ca8ed --- /dev/null +++ b/projects/cobbler-frontend/src/app/items/profile/edit/profile-edit.component.html @@ -0,0 +1,158 @@ +
+
+

Name: {{ name }}

+ + + + + + + + + + + + +
+
+ +
+ + Name + + + + UID + + + + Last modified time + + + + Creation time + + + + Depth + + + Is Subobject? + + + Inherited + + + Comment + + + + Autoinstall + + + + DHCP Tag + + + + Distribution + + + + Menu + + + + Next-Server IPv4 + + + + Next-Server IPv6 + + + + Filename + + + + Parent + + + + Proxy + + + + RedHat Management Key + + + + Server + + + + + Inherited + + + + Inherited + + + + Inherited + + + + Inherited + + + + Inherited + + + + Inherited + + + + Inherited + + + + + + + + + + Inherited + + + + + + + Inherited + + + @if (isEditMode) { + + } +
diff --git a/projects/cobbler-frontend/src/app/items/profile/edit/profile-edit.component.scss b/projects/cobbler-frontend/src/app/items/profile/edit/profile-edit.component.scss new file mode 100644 index 00000000..2a9efa5d --- /dev/null +++ b/projects/cobbler-frontend/src/app/items/profile/edit/profile-edit.component.scss @@ -0,0 +1,30 @@ +.title-table { + display: table; + width: 100%; +} + +.title-row { + display: table-cell; + width: 100%; +} + +.title-cell-text { + display: table-cell; + width: 100%; + vertical-align: middle; +} + +.title-cell-button { + display: table-cell; +} + +.form-replicate { + min-width: 150px; + max-width: 600px; + width: 100%; +} + +.form-field-full-width { + width: 100%; +} + diff --git a/projects/cobbler-frontend/src/app/items/profile/edit/profile-edit.component.spec.ts b/projects/cobbler-frontend/src/app/items/profile/edit/profile-edit.component.spec.ts new file mode 100644 index 00000000..c7443298 --- /dev/null +++ b/projects/cobbler-frontend/src/app/items/profile/edit/profile-edit.component.spec.ts @@ -0,0 +1,50 @@ +import {provideHttpClient} from '@angular/common/http'; +import {provideHttpClientTesting} from '@angular/common/http/testing'; +import { ComponentFixture, TestBed } from '@angular/core/testing'; +import {NoopAnimationsModule} from '@angular/platform-browser/animations'; +import {ActivatedRoute, provideRouter} from '@angular/router'; +import {COBBLER_URL} from 'cobbler-api'; + +import { ProfileEditComponent } from './profile-edit.component'; + +describe('ProfileEditComponent', () => { + let component: ProfileEditComponent; + let fixture: ComponentFixture; + + beforeEach(async () => { + await TestBed.configureTestingModule({ + imports: [ + ProfileEditComponent, + NoopAnimationsModule, + ], + providers: [ + provideRouter([]), + provideHttpClient(), + provideHttpClientTesting(), + { + provide: COBBLER_URL, + useValue: new URL('http://localhost/cobbler_api') + }, + { + provide: ActivatedRoute, + useValue: { + snapshot: { + paramMap: { + get: () => "testprof" + }, + }, + }, + }, + ] + }) + .compileComponents(); + + fixture = TestBed.createComponent(ProfileEditComponent); + component = fixture.componentInstance; + fixture.detectChanges(); + }); + + it('should create', () => { + expect(component).toBeTruthy(); + }); +}); diff --git a/projects/cobbler-frontend/src/app/items/profile/edit/profile-edit.component.ts b/projects/cobbler-frontend/src/app/items/profile/edit/profile-edit.component.ts new file mode 100644 index 00000000..0741cd22 --- /dev/null +++ b/projects/cobbler-frontend/src/app/items/profile/edit/profile-edit.component.ts @@ -0,0 +1,311 @@ +import {Component, inject, OnInit} from '@angular/core'; +import {FormBuilder, FormControl, FormsModule, ReactiveFormsModule} from '@angular/forms'; +import {MatOption} from '@angular/material/autocomplete'; +import {MatButton, MatIconButton} from '@angular/material/button'; +import {MatCheckbox} from '@angular/material/checkbox'; +import {MatFormField, MatLabel} from '@angular/material/form-field'; +import {MatIcon} from '@angular/material/icon'; +import {MatInput} from '@angular/material/input'; +import {MatSelect} from '@angular/material/select'; +import {MatSnackBar} from '@angular/material/snack-bar'; +import {MatTooltip} from '@angular/material/tooltip'; +import {ActivatedRoute, Router} from '@angular/router'; +import {CobblerApiService, Profile} from 'cobbler-api'; +import {KeyValueEditorComponent} from '../../../common/key-value-editor/key-value-editor.component'; +import {MultiSelectComponent} from '../../../common/multi-select/multi-select.component'; +import {UserService} from '../../../services/user.service'; + +@Component({ + selector: 'cobbler-edit', + standalone: true, + imports: [ + MatIcon, + MatIconButton, + MatTooltip, + FormsModule, + MatButton, + MatCheckbox, + MatFormField, + MatInput, + MatLabel, + MatOption, + MatSelect, + ReactiveFormsModule, + MultiSelectComponent, + KeyValueEditorComponent + ], + templateUrl: './profile-edit.component.html', + styleUrl: './profile-edit.component.scss' +}) +export class ProfileEditComponent implements OnInit{ + name: string; + profile: Profile; + private readonly _formBuilder = inject(FormBuilder); + profileFormGroup = this._formBuilder.group({ + name: new FormControl({value: "", disabled: true}), + uid: new FormControl({value: "", disabled: true}), + mtime: new FormControl({value: "", disabled: true}), + ctime: new FormControl({value: "", disabled: true}), + depth: new FormControl({value: 0, disabled: true}), + is_subobject: new FormControl({value: false, disabled: true}), + comment: new FormControl({value: "", disabled: true}), + redhat_management_key: new FormControl({value: "", disabled: true}), + autoinstall: new FormControl({value: "", disabled: true}), + dhcp_tag: new FormControl({value: "", disabled: true}), + distro: new FormControl({value: "", disabled: true}), + menu: new FormControl({value: "", disabled: true}), + next_server_v4: new FormControl({value: "", disabled: true}), + next_server_v6: new FormControl({value: "", disabled: true}), + filename: new FormControl({value: "", disabled: true}), + parent: new FormControl({value: "", disabled: true}), + proxy: new FormControl({value: "", disabled: true}), + server: new FormControl({value: "", disabled: true}), + boot_loaders: new FormControl({value: [], disabled: true}), + bootloader_inherited: new FormControl({value: false, disabled: true}), + owners: new FormControl({value: [], disabled: true}), + owners_inherited: new FormControl({value: false, disabled: true}), + autoinstall_meta: new FormControl({value: {}, disabled: true}), + autoinstall_meta_inherited: new FormControl({value: false, disabled: true}), + boot_files: new FormControl({value: {}, disabled: true}), + boot_files_inherited: new FormControl({value: false, disabled: true}), + fetchable_files: new FormControl({value: {}, disabled: true}), + fetchable_files_inherited: new FormControl({value: false, disabled: true}), + kernel_options: new FormControl({value: {}, disabled: true}), + kernel_options_inherited: new FormControl({value: false, disabled: true}), + kernel_options_post: new FormControl({value: {}, disabled: true}), + kernel_options_post_inherited: new FormControl({value: false, disabled: true}), + mgmt_classes: new FormControl({value: [], disabled: true}), + mgmt_classes_inherited: new FormControl({value: false, disabled: true}), + mgmt_parameters: new FormControl({value: {}, disabled: true}), + mgmt_parameters_inherited: new FormControl({value: false, disabled: true}), + name_servers: new FormControl({value: [], disabled: true}), + name_servers_search: new FormControl({value: [], disabled: true}), + repos: new FormControl({value: [], disabled: true}), + template_files: new FormControl({value: {}, disabled: true}), + template_files_inherited: new FormControl({value: false, disabled: true}), + + }); + isEditMode: boolean = false; + + constructor( + private route: ActivatedRoute, + private userService: UserService, + private cobblerApiService: CobblerApiService, + private _snackBar: MatSnackBar, + private router: Router, + ) { + this.name = this.route.snapshot.paramMap.get("name"); + } + + ngOnInit(): void { + this.refreshData() + } + + refreshData(): void { + this.cobblerApiService.get_profile(this.name, false, false, this.userService.token).subscribe(value => { + this.profile = value + this.profileFormGroup.controls.name.setValue(this.profile.name) + this.profileFormGroup.controls.uid.setValue(this.profile.uid) + this.profileFormGroup.controls.mtime.setValue(new Date(this.profile.mtime * 1000).toString()) + this.profileFormGroup.controls.ctime.setValue(new Date(this.profile.ctime * 1000).toString()) + this.profileFormGroup.controls.depth.setValue(this.profile.depth) + this.profileFormGroup.controls.is_subobject.setValue(this.profile.is_subobject) + this.profileFormGroup.controls.comment.setValue(this.profile.comment) + this.profileFormGroup.controls.redhat_management_key.setValue(this.profile.redhat_management_key) + this.profileFormGroup.controls.autoinstall.setValue(this.profile.autoinstall) + this.profileFormGroup.controls.dhcp_tag.setValue(this.profile.dhcp_tag) + this.profileFormGroup.controls.distro.setValue(this.profile.distro) + this.profileFormGroup.controls.menu.setValue(this.profile.menu) + this.profileFormGroup.controls.next_server_v4.setValue(this.profile.next_server_v4) + this.profileFormGroup.controls.next_server_v6.setValue(this.profile.next_server_v6) + this.profileFormGroup.controls.filename.setValue(this.profile.filename) + this.profileFormGroup.controls.parent.setValue(this.profile.parent) + this.profileFormGroup.controls.proxy.setValue(this.profile.proxy) + this.profileFormGroup.controls.server.setValue(this.profile.server) + this.profileFormGroup.controls.name_servers.setValue(this.profile.name_servers) + this.profileFormGroup.controls.name_servers_search.setValue(this.profile.name_servers_search) + this.profileFormGroup.controls.repos.setValue(this.profile.repos) + if (typeof this.profile.boot_loaders === "string") { + this.profileFormGroup.controls.bootloader_inherited.setValue(true) + } else { + this.profileFormGroup.controls.bootloader_inherited.setValue(false) + this.profileFormGroup.controls.boot_loaders.setValue(this.profile.boot_loaders) + } + if (typeof this.profile.owners === "string") { + this.profileFormGroup.controls.owners_inherited.setValue(true) + } else { + this.profileFormGroup.controls.owners_inherited.setValue(false) + this.profileFormGroup.controls.owners.setValue(this.profile.owners) + } + if (typeof this.profile.autoinstall_meta === "string") { + this.profileFormGroup.controls.autoinstall_meta_inherited.setValue(true) + } else { + this.profileFormGroup.controls.autoinstall_meta_inherited.setValue(false) + this.profileFormGroup.controls.autoinstall_meta.setValue(this.profile.autoinstall_meta) + } + if (typeof this.profile.boot_files === "string") { + this.profileFormGroup.controls.boot_files_inherited.setValue(true) + } else { + this.profileFormGroup.controls.boot_files_inherited.setValue(false) + this.profileFormGroup.controls.boot_files.setValue(this.profile.boot_files) + } + if (typeof this.profile.fetchable_files === "string") { + this.profileFormGroup.controls.fetchable_files_inherited.setValue(true) + } else { + this.profileFormGroup.controls.fetchable_files_inherited.setValue(false) + this.profileFormGroup.controls.fetchable_files.setValue(this.profile.fetchable_files) + } + if (typeof this.profile.kernel_options === "string") { + this.profileFormGroup.controls.kernel_options_inherited.setValue(true) + } else { + this.profileFormGroup.controls.kernel_options_inherited.setValue(false) + this.profileFormGroup.controls.kernel_options.setValue(this.profile.kernel_options) + } + if (typeof this.profile.kernel_options_post === "string") { + this.profileFormGroup.controls.kernel_options_post_inherited.setValue(true) + } else { + this.profileFormGroup.controls.kernel_options_post_inherited.setValue(false) + this.profileFormGroup.controls.kernel_options_post.setValue(this.profile.kernel_options_post) + } + if (typeof this.profile.mgmt_classes === "string") { + this.profileFormGroup.controls.mgmt_classes_inherited.setValue(true) + } else { + this.profileFormGroup.controls.mgmt_classes_inherited.setValue(false) + this.profileFormGroup.controls.mgmt_classes.setValue(this.profile.mgmt_classes) + } + if (typeof this.profile.mgmt_parameters === "string") { + this.profileFormGroup.controls.mgmt_parameters_inherited.setValue(true) + } else { + this.profileFormGroup.controls.mgmt_parameters_inherited.setValue(false) + this.profileFormGroup.controls.mgmt_parameters.setValue(this.profile.mgmt_parameters) + } + if (typeof this.profile.template_files === "string") { + this.profileFormGroup.controls.template_files_inherited.setValue(true) + } else { + this.profileFormGroup.controls.template_files_inherited.setValue(false) + this.profileFormGroup.controls.template_files.setValue(this.profile.template_files) + } + }, error => { + // HTML encode the error message since it originates from XML + this._snackBar.open(this.toHTML(error.message), 'Close'); + }); + } + + removeProfile(): void { + this.cobblerApiService.remove_profile(this.name, this.userService.token, false).subscribe(value => { + if (value) { + this.router.navigate(["/items", "profile"]) + } + // HTML encode the error message since it originates from XML + this._snackBar.open("Delete failed! Check server logs for more information.", 'Close'); + }, error => { + // HTML encode the error message since it originates from XML + this._snackBar.open(this.toHTML(error.message), 'Close'); + }) + } + + editProfile(): void { + // TODO + this._snackBar.open("Not implemented at the moment!", "Close") + } + + copyProfile(): void { + this.cobblerApiService.copy_profile("", "", this.userService.token) + .subscribe(value => { + // TODO + }, error => { + // HTML encode the error message since it originates from XML + this._snackBar.open(this.toHTML(error.message), 'Close'); + }) + } + + saveProfile(): void { + // TODO + } + + get profileOwners(): string[] { + if (this.profile && this.profile.owners) { + const ownersResult = this.profile.owners + if (typeof ownersResult !== 'string') { + return ownersResult; + } + } + return [] + } + + get profileAutoinstallMeta(): object { + if (this.profile && this.profile.autoinstall_meta) { + const autoinstallMetaResult = this.profile.autoinstall_meta + if (typeof autoinstallMetaResult !== 'string') { + return autoinstallMetaResult + } + } + return {} + } + + get profileKernelOptions(): object { + if (this.profile && this.profile.kernel_options) { + const kernelOptionsResult = this.profile.kernel_options + if (typeof kernelOptionsResult !== 'string') { + return kernelOptionsResult + } + } + return {} + } + + get profileKernelOptionsPost(): object { + if (this.profile && this.profile.kernel_options_post) { + const kernelOptionsPost = this.profile.kernel_options_post + if (typeof kernelOptionsPost !== 'string') { + return kernelOptionsPost + } + } + return {} + } + + + get profileBootFiles(): object { + if (this.profile && this.profile.boot_files) { + const bootFilesResult = this.profile.boot_files + if (typeof bootFilesResult !== 'string') { + return bootFilesResult + } + } + return {} + } + + get profileFetchableFiles(): object { + if (this.profile && this.profile.fetchable_files) { + const fetchableFilesResult = this.profile.fetchable_files + if (typeof fetchableFilesResult !== 'string') { + return fetchableFilesResult + } + } + return {} + } + + get profileMgmtParameters(): object { + if (this.profile && this.profile.mgmt_parameters) { + const mgmtParametersResult = this.profile.mgmt_parameters + if (typeof mgmtParametersResult !== 'string') { + return mgmtParametersResult + } + } + return {} + } + + get profileTemplateFiles(): object { + if (this.profile && this.profile.template_files) { + const templateFilesResult = this.profile.template_files + if (typeof templateFilesResult !== 'string') { + return templateFilesResult + } + } + return {} + } + + toHTML(input: string): any { + // FIXME: Deduplicate method + return new DOMParser().parseFromString(input, 'text/html').documentElement.textContent; + } +} diff --git a/projects/cobbler-frontend/src/app/items/profile/overview/profile-overview.component.html b/projects/cobbler-frontend/src/app/items/profile/overview/profile-overview.component.html new file mode 100644 index 00000000..13eda434 --- /dev/null +++ b/projects/cobbler-frontend/src/app/items/profile/overview/profile-overview.component.html @@ -0,0 +1,46 @@ +

PROFILES

+ + + + + + + + + + + + + + + + + + + + + + + + + + + +
Name{{element.name}}Distro{{element.distro}}Server{{element.server}} + + + + + + +
+ diff --git a/projects/cobbler-frontend/src/app/items/systems/systems.component.css b/projects/cobbler-frontend/src/app/items/profile/overview/profile-overview.component.scss similarity index 100% rename from projects/cobbler-frontend/src/app/items/systems/systems.component.css rename to projects/cobbler-frontend/src/app/items/profile/overview/profile-overview.component.scss diff --git a/projects/cobbler-frontend/src/app/items/profile/overview/profile-overview.component.spec.ts b/projects/cobbler-frontend/src/app/items/profile/overview/profile-overview.component.spec.ts new file mode 100644 index 00000000..8570ab9a --- /dev/null +++ b/projects/cobbler-frontend/src/app/items/profile/overview/profile-overview.component.spec.ts @@ -0,0 +1,36 @@ +import {provideHttpClient} from '@angular/common/http'; +import {provideHttpClientTesting} from '@angular/common/http/testing'; +import { ComponentFixture, TestBed } from '@angular/core/testing'; +import {provideRouter} from '@angular/router'; +import {COBBLER_URL} from 'cobbler-api'; + +import { ProfileOverviewComponent } from './profile-overview.component'; + +describe('ProfileOverviewComponent', () => { + let component: ProfileOverviewComponent; + let fixture: ComponentFixture; + + beforeEach(async () => { + await TestBed.configureTestingModule({ + imports: [ProfileOverviewComponent], + providers: [ + provideRouter([]), + provideHttpClient(), + provideHttpClientTesting(), + { + provide: COBBLER_URL, + useValue: new URL('http://localhost/cobbler_api') + }, + ] + }) + .compileComponents(); + + fixture = TestBed.createComponent(ProfileOverviewComponent); + component = fixture.componentInstance; + fixture.detectChanges(); + }); + + it('should create', () => { + expect(component).toBeTruthy(); + }); +}); diff --git a/projects/cobbler-frontend/src/app/items/profile/overview/profile-overview.component.ts b/projects/cobbler-frontend/src/app/items/profile/overview/profile-overview.component.ts new file mode 100644 index 00000000..9e9f6dde --- /dev/null +++ b/projects/cobbler-frontend/src/app/items/profile/overview/profile-overview.component.ts @@ -0,0 +1,90 @@ +import {Component, OnInit, ViewChild} from '@angular/core'; +import {MatIconButton} from '@angular/material/button'; +import {MatIcon} from '@angular/material/icon'; +import {MatMenu, MatMenuItem, MatMenuTrigger} from '@angular/material/menu'; +import {MatSnackBar} from '@angular/material/snack-bar'; +import { + MatCell, + MatCellDef, + MatColumnDef, + MatHeaderCell, MatHeaderCellDef, + MatHeaderRow, + MatHeaderRowDef, + MatRow, MatRowDef, MatTable +} from '@angular/material/table'; +import {Router} from '@angular/router'; +import {CobblerApiService, Profile} from 'cobbler-api'; +import {UserService} from '../../../services/user.service'; + +@Component({ + selector: 'cobbler-overview', + standalone: true, + imports: [ + MatCell, + MatCellDef, + MatColumnDef, + MatHeaderCell, + MatHeaderRow, + MatHeaderRowDef, + MatIcon, + MatIconButton, + MatMenu, + MatMenuItem, + MatRow, + MatRowDef, + MatTable, + MatMenuTrigger, + MatHeaderCellDef + ], + templateUrl: './profile-overview.component.html', + styleUrl: './profile-overview.component.scss' +}) +export class ProfileOverviewComponent implements OnInit { + displayedColumns: string[] = ['name', "distro", "server", "actions"]; + dataSource: Array = []; + + @ViewChild(MatTable) table: MatTable; + + constructor( + public userService: UserService, + private cobblerApiService: CobblerApiService, + private _snackBar: MatSnackBar, + private router: Router, + ) { + } + + ngOnInit(): void { + this.retrieveProfiles() + } + + private retrieveProfiles(): void { + this.cobblerApiService.get_profiles().subscribe(value => { + this.dataSource = value + }, error => { + // HTML encode the error message since it originates from XML + this._snackBar.open(this.toHTML(error.message), 'Close'); + }) + } + + showProfile(uid: string, name: string): void { + this.router.navigate(["/items", "profile", name]) + } + + editProfile(uid: string, name: string): void { + // TODO + } + + deleteProfile(uid: string, name: string): void { + this.cobblerApiService.remove_profile(name, this.userService.token, false).subscribe(value => { + this.retrieveProfiles() + }, error => { + // HTML encode the error message since it originates from XML + this._snackBar.open(this.toHTML(error.message), 'Close'); + }) + } + + toHTML(input: string): any { + // FIXME: Deduplicate method + return new DOMParser().parseFromString(input, 'text/html').documentElement.textContent; + } +} diff --git a/projects/cobbler-frontend/src/app/items/profiles/profiles.component.html b/projects/cobbler-frontend/src/app/items/profiles/profiles.component.html deleted file mode 100644 index ddfc6696..00000000 --- a/projects/cobbler-frontend/src/app/items/profiles/profiles.component.html +++ /dev/null @@ -1,26 +0,0 @@ -
-
- -

PROFILES

-
- - -
-
- @for(item of data;track item){ -
- - {{ item[3] }} - - -
- } -
-
-
diff --git a/projects/cobbler-frontend/src/app/items/profiles/profiles.component.spec.js b/projects/cobbler-frontend/src/app/items/profiles/profiles.component.spec.js deleted file mode 100644 index bf1a9ce4..00000000 --- a/projects/cobbler-frontend/src/app/items/profiles/profiles.component.spec.js +++ /dev/null @@ -1,66 +0,0 @@ -"use strict"; -var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { - function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } - return new (P || (P = Promise))(function (resolve, reject) { - function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } - function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } - function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } - step((generator = generator.apply(thisArg, _arguments || [])).next()); - }); -}; -var __generator = (this && this.__generator) || function (thisArg, body) { - var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g; - return g = { next: verb(0), "throw": verb(1), "return": verb(2) }, typeof Symbol === "function" && (g[Symbol.iterator] = function() { return this; }), g; - function verb(n) { return function (v) { return step([n, v]); }; } - function step(op) { - if (f) throw new TypeError("Generator is already executing."); - while (_) try { - if (f = 1, y && (t = op[0] & 2 ? y["return"] : op[0] ? y["throw"] || ((t = y["return"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t; - if (y = 0, t) op = [op[0] & 2, t.value]; - switch (op[0]) { - case 0: case 1: t = op; break; - case 4: _.label++; return { value: op[1], done: false }; - case 5: _.label++; y = op[1]; op = [0]; continue; - case 7: op = _.ops.pop(); _.trys.pop(); continue; - default: - if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; } - if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; } - if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; } - if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; } - if (t[2]) _.ops.pop(); - _.trys.pop(); continue; - } - op = body.call(thisArg, _); - } catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; } - if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true }; - } -}; -Object.defineProperty(exports, "__esModule", { value: true }); -var testing_1 = require("@angular/core/testing"); -var profiles_component_1 = require("./profiles.component"); -describe('ProfilesComponent', function () { - var component; - var fixture; - beforeEach(function () { return __awaiter(void 0, void 0, void 0, function () { - return __generator(this, function (_a) { - switch (_a.label) { - case 0: return [4 /*yield*/, testing_1.TestBed.configureTestingModule({ - declarations: [profiles_component_1.ProfilesComponent] - }) - .compileComponents()]; - case 1: - _a.sent(); - return [2 /*return*/]; - } - }); - }); }); - beforeEach(function () { - fixture = testing_1.TestBed.createComponent(profiles_component_1.ProfilesComponent); - component = fixture.componentInstance; - fixture.detectChanges(); - }); - it('should create', function () { - expect(component).toBeTruthy(); - }); -}); -//# sourceMappingURL=profiles.component.spec.js.map \ No newline at end of file diff --git a/projects/cobbler-frontend/src/app/items/profiles/profiles.component.spec.js.map b/projects/cobbler-frontend/src/app/items/profiles/profiles.component.spec.js.map deleted file mode 100644 index 9fb80686..00000000 --- a/projects/cobbler-frontend/src/app/items/profiles/profiles.component.spec.js.map +++ /dev/null @@ -1 +0,0 @@ -{"version":3,"file":"profiles.component.spec.js","sourceRoot":"","sources":["profiles.component.spec.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA,iDAAkE;AAElE,2DAAyD;AAEzD,QAAQ,CAAC,mBAAmB,EAAE;IAC5B,IAAI,SAA4B,CAAC;IACjC,IAAI,OAA4C,CAAC;IAEjD,UAAU,CAAC;;;wBACT,qBAAM,iBAAO,CAAC,sBAAsB,CAAC;wBACnC,YAAY,EAAE,CAAE,sCAAiB,CAAE;qBACpC,CAAC;yBACD,iBAAiB,EAAE,EAAA;;oBAHpB,SAGoB,CAAC;;;;SACtB,CAAC,CAAC;IAEH,UAAU,CAAC;QACT,OAAO,GAAG,iBAAO,CAAC,eAAe,CAAC,sCAAiB,CAAC,CAAC;QACrD,SAAS,GAAG,OAAO,CAAC,iBAAiB,CAAC;QACtC,OAAO,CAAC,aAAa,EAAE,CAAC;IAC1B,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,eAAe,EAAE;QAClB,MAAM,CAAC,SAAS,CAAC,CAAC,UAAU,EAAE,CAAC;IACjC,CAAC,CAAC,CAAC;AACL,CAAC,CAAC,CAAC"} \ No newline at end of file diff --git a/projects/cobbler-frontend/src/app/items/profiles/profiles.component.spec.ts b/projects/cobbler-frontend/src/app/items/profiles/profiles.component.spec.ts deleted file mode 100644 index 447287a6..00000000 --- a/projects/cobbler-frontend/src/app/items/profiles/profiles.component.spec.ts +++ /dev/null @@ -1,39 +0,0 @@ -import { ComponentFixture, TestBed } from '@angular/core/testing'; -import { MatButtonModule } from '@angular/material/button'; -import { MatFormFieldModule } from '@angular/material/form-field'; -import { MatInputModule } from '@angular/material/input'; -import { NoopAnimationsModule } from '@angular/platform-browser/animations'; -import {provideRouter} from '@angular/router'; - -import { ProfilesComponent } from './profiles.component'; - - -describe('ProfilesComponent', () => { - let component: ProfilesComponent; - let fixture: ComponentFixture; - - beforeEach(async () => { - await TestBed.configureTestingModule({ - imports: [ - ProfilesComponent, - MatInputModule, - MatFormFieldModule, - MatButtonModule, - NoopAnimationsModule, - ], - providers: [ - provideRouter([]), - ] - }).compileComponents(); - }); - - beforeEach(() => { - fixture = TestBed.createComponent(ProfilesComponent); - component = fixture.componentInstance; - fixture.detectChanges(); - }); - - it('should create', () => { - expect(component).toBeTruthy(); - }); -}); diff --git a/projects/cobbler-frontend/src/app/items/profiles/profiles.component.ts b/projects/cobbler-frontend/src/app/items/profiles/profiles.component.ts deleted file mode 100644 index 8956b188..00000000 --- a/projects/cobbler-frontend/src/app/items/profiles/profiles.component.ts +++ /dev/null @@ -1,22 +0,0 @@ -import {Component} from '@angular/core'; -import {ProfileService} from '../../services/profile.service'; -import { RouterOutlet } from '@angular/router'; -import {MatFormFieldModule} from "@angular/material/form-field"; -import {MatButtonModule} from "@angular/material/button"; -import {MatInputModule} from "@angular/material/input"; - -@Component({ - selector: 'cobbler-profiles', - templateUrl: './profiles.component.html', - styleUrls: ['./profiles.component.css'], - standalone: true, - imports: [RouterOutlet, MatFormFieldModule, MatButtonModule, MatInputModule], -}) -export class ProfilesComponent { - data = []; - - constructor(service: ProfileService) { - this.data = service.getAll(); - } - -} diff --git a/projects/cobbler-frontend/src/app/items/repos/repos.component.html b/projects/cobbler-frontend/src/app/items/repos/repos.component.html deleted file mode 100644 index 666d05e4..00000000 --- a/projects/cobbler-frontend/src/app/items/repos/repos.component.html +++ /dev/null @@ -1,26 +0,0 @@ -
-
- -

REPOS

-
- - -
-
- @for(item of data;track item){ -
- - {{ item[3] }} - - -
- } -
-
-
diff --git a/projects/cobbler-frontend/src/app/items/repos/repos.component.spec.js b/projects/cobbler-frontend/src/app/items/repos/repos.component.spec.js deleted file mode 100644 index 06a6074f..00000000 --- a/projects/cobbler-frontend/src/app/items/repos/repos.component.spec.js +++ /dev/null @@ -1,66 +0,0 @@ -"use strict"; -var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { - function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } - return new (P || (P = Promise))(function (resolve, reject) { - function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } - function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } - function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } - step((generator = generator.apply(thisArg, _arguments || [])).next()); - }); -}; -var __generator = (this && this.__generator) || function (thisArg, body) { - var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g; - return g = { next: verb(0), "throw": verb(1), "return": verb(2) }, typeof Symbol === "function" && (g[Symbol.iterator] = function() { return this; }), g; - function verb(n) { return function (v) { return step([n, v]); }; } - function step(op) { - if (f) throw new TypeError("Generator is already executing."); - while (_) try { - if (f = 1, y && (t = op[0] & 2 ? y["return"] : op[0] ? y["throw"] || ((t = y["return"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t; - if (y = 0, t) op = [op[0] & 2, t.value]; - switch (op[0]) { - case 0: case 1: t = op; break; - case 4: _.label++; return { value: op[1], done: false }; - case 5: _.label++; y = op[1]; op = [0]; continue; - case 7: op = _.ops.pop(); _.trys.pop(); continue; - default: - if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; } - if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; } - if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; } - if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; } - if (t[2]) _.ops.pop(); - _.trys.pop(); continue; - } - op = body.call(thisArg, _); - } catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; } - if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true }; - } -}; -Object.defineProperty(exports, "__esModule", { value: true }); -var testing_1 = require("@angular/core/testing"); -var repos_component_1 = require("./repos.component"); -describe('ReposComponent', function () { - var component; - var fixture; - beforeEach(function () { return __awaiter(void 0, void 0, void 0, function () { - return __generator(this, function (_a) { - switch (_a.label) { - case 0: return [4 /*yield*/, testing_1.TestBed.configureTestingModule({ - declarations: [repos_component_1.ReposComponent] - }) - .compileComponents()]; - case 1: - _a.sent(); - return [2 /*return*/]; - } - }); - }); }); - beforeEach(function () { - fixture = testing_1.TestBed.createComponent(repos_component_1.ReposComponent); - component = fixture.componentInstance; - fixture.detectChanges(); - }); - it('should create', function () { - expect(component).toBeTruthy(); - }); -}); -//# sourceMappingURL=repos.component.spec.js.map \ No newline at end of file diff --git a/projects/cobbler-frontend/src/app/items/repos/repos.component.spec.js.map b/projects/cobbler-frontend/src/app/items/repos/repos.component.spec.js.map deleted file mode 100644 index 47c8d997..00000000 --- a/projects/cobbler-frontend/src/app/items/repos/repos.component.spec.js.map +++ /dev/null @@ -1 +0,0 @@ -{"version":3,"file":"repos.component.spec.js","sourceRoot":"","sources":["repos.component.spec.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA,iDAAkE;AAElE,qDAAmD;AAEnD,QAAQ,CAAC,gBAAgB,EAAE;IACzB,IAAI,SAAyB,CAAC;IAC9B,IAAI,OAAyC,CAAC;IAE9C,UAAU,CAAC;;;wBACT,qBAAM,iBAAO,CAAC,sBAAsB,CAAC;wBACnC,YAAY,EAAE,CAAE,gCAAc,CAAE;qBACjC,CAAC;yBACD,iBAAiB,EAAE,EAAA;;oBAHpB,SAGoB,CAAC;;;;SACtB,CAAC,CAAC;IAEH,UAAU,CAAC;QACT,OAAO,GAAG,iBAAO,CAAC,eAAe,CAAC,gCAAc,CAAC,CAAC;QAClD,SAAS,GAAG,OAAO,CAAC,iBAAiB,CAAC;QACtC,OAAO,CAAC,aAAa,EAAE,CAAC;IAC1B,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,eAAe,EAAE;QAClB,MAAM,CAAC,SAAS,CAAC,CAAC,UAAU,EAAE,CAAC;IACjC,CAAC,CAAC,CAAC;AACL,CAAC,CAAC,CAAC"} \ No newline at end of file diff --git a/projects/cobbler-frontend/src/app/items/repos/repos.component.spec.ts b/projects/cobbler-frontend/src/app/items/repos/repos.component.spec.ts deleted file mode 100644 index 84be7c5f..00000000 --- a/projects/cobbler-frontend/src/app/items/repos/repos.component.spec.ts +++ /dev/null @@ -1,39 +0,0 @@ -import { ComponentFixture, TestBed } from '@angular/core/testing'; -import { MatButtonModule } from '@angular/material/button'; -import { MatFormFieldModule } from '@angular/material/form-field'; -import { MatInputModule } from '@angular/material/input'; -import { NoopAnimationsModule } from '@angular/platform-browser/animations'; -import {provideRouter} from '@angular/router'; - -import { ReposComponent } from './repos.component'; - - -describe('ReposComponent', () => { - let component: ReposComponent; - let fixture: ComponentFixture; - - beforeEach(async () => { - await TestBed.configureTestingModule({ - imports: [ - ReposComponent, - MatInputModule, - MatFormFieldModule, - MatButtonModule, - NoopAnimationsModule, - ], - providers: [ - provideRouter([]), - ] - }).compileComponents(); - }); - - beforeEach(() => { - fixture = TestBed.createComponent(ReposComponent); - component = fixture.componentInstance; - fixture.detectChanges(); - }); - - it('should create', () => { - expect(component).toBeTruthy(); - }); -}); diff --git a/projects/cobbler-frontend/src/app/items/repos/repos.component.ts b/projects/cobbler-frontend/src/app/items/repos/repos.component.ts deleted file mode 100644 index 33523a7a..00000000 --- a/projects/cobbler-frontend/src/app/items/repos/repos.component.ts +++ /dev/null @@ -1,21 +0,0 @@ -import {Component} from '@angular/core'; -import {ReposService} from '../../services/repos.service'; -import { RouterOutlet } from '@angular/router'; -import {MatFormFieldModule} from "@angular/material/form-field"; -import {MatButtonModule} from "@angular/material/button"; -import {MatInputModule} from "@angular/material/input"; - -@Component({ - selector: 'cobbler-repos', - templateUrl: './repos.component.html', - styleUrls: ['./repos.component.css'], - standalone: true, - imports: [RouterOutlet, MatFormFieldModule, MatButtonModule, MatInputModule], -}) -export class ReposComponent { - data = []; - - constructor(service: ReposService) { - this.data = service.getAll(); - } -} diff --git a/projects/cobbler-frontend/src/app/items/repository/edit/repository-edit.component.html b/projects/cobbler-frontend/src/app/items/repository/edit/repository-edit.component.html new file mode 100644 index 00000000..957ae8cb --- /dev/null +++ b/projects/cobbler-frontend/src/app/items/repository/edit/repository-edit.component.html @@ -0,0 +1,113 @@ +
+
+

Name: {{ name }}

+ + + + + + + + + + + + +
+
+ +
+ + Name + + + + UID + + + + Last modified time + + + + Creation time + + + + Depth + + + Is Subobject? + + Comment + + + + Operating System Version + + + + Operating System Breed + + + + Mirror + + + + Mirror Type + + + + Proxy + + + + Priority + + + Keep updated? + Mirror Locally? + + + + + + + + + + + Createrepo Flags + + + + + + + + + + + + @if (isEditMode) { + + } +
+ diff --git a/projects/cobbler-frontend/src/app/items/repository/edit/repository-edit.component.scss b/projects/cobbler-frontend/src/app/items/repository/edit/repository-edit.component.scss new file mode 100644 index 00000000..2a9efa5d --- /dev/null +++ b/projects/cobbler-frontend/src/app/items/repository/edit/repository-edit.component.scss @@ -0,0 +1,30 @@ +.title-table { + display: table; + width: 100%; +} + +.title-row { + display: table-cell; + width: 100%; +} + +.title-cell-text { + display: table-cell; + width: 100%; + vertical-align: middle; +} + +.title-cell-button { + display: table-cell; +} + +.form-replicate { + min-width: 150px; + max-width: 600px; + width: 100%; +} + +.form-field-full-width { + width: 100%; +} + diff --git a/projects/cobbler-frontend/src/app/items/repository/edit/repository-edit.component.spec.ts b/projects/cobbler-frontend/src/app/items/repository/edit/repository-edit.component.spec.ts new file mode 100644 index 00000000..546d224a --- /dev/null +++ b/projects/cobbler-frontend/src/app/items/repository/edit/repository-edit.component.spec.ts @@ -0,0 +1,50 @@ +import {provideHttpClient} from '@angular/common/http'; +import {provideHttpClientTesting} from '@angular/common/http/testing'; +import { ComponentFixture, TestBed } from '@angular/core/testing'; +import {NoopAnimationsModule} from '@angular/platform-browser/animations'; +import {ActivatedRoute, provideRouter} from '@angular/router'; +import {COBBLER_URL} from 'cobbler-api'; + +import { RepositoryEditComponent } from './repository-edit.component'; + +describe('RepositoryEditComponent', () => { + let component: RepositoryEditComponent; + let fixture: ComponentFixture; + + beforeEach(async () => { + await TestBed.configureTestingModule({ + imports: [ + RepositoryEditComponent, + NoopAnimationsModule, + ], + providers: [ + provideRouter([]), + provideHttpClient(), + provideHttpClientTesting(), + { + provide: COBBLER_URL, + useValue: new URL('http://localhost/cobbler_api') + }, + { + provide: ActivatedRoute, + useValue: { + snapshot: { + paramMap: { + get: () => "testrepository" + }, + }, + }, + }, + ] + }) + .compileComponents(); + + fixture = TestBed.createComponent(RepositoryEditComponent); + component = fixture.componentInstance; + fixture.detectChanges(); + }); + + it('should create', () => { + expect(component).toBeTruthy(); + }); +}); diff --git a/projects/cobbler-frontend/src/app/items/repository/edit/repository-edit.component.ts b/projects/cobbler-frontend/src/app/items/repository/edit/repository-edit.component.ts new file mode 100644 index 00000000..b50facea --- /dev/null +++ b/projects/cobbler-frontend/src/app/items/repository/edit/repository-edit.component.ts @@ -0,0 +1,190 @@ +import {Component, inject, OnInit} from '@angular/core'; +import {FormBuilder, FormControl, FormsModule, ReactiveFormsModule} from '@angular/forms'; +import {MatOption} from '@angular/material/autocomplete'; +import {MatButton, MatIconButton} from '@angular/material/button'; +import {MatCheckbox} from '@angular/material/checkbox'; +import {MatFormField, MatLabel} from '@angular/material/form-field'; +import {MatIcon} from '@angular/material/icon'; +import {MatInput} from '@angular/material/input'; +import {MatSelect} from '@angular/material/select'; +import {MatSnackBar} from '@angular/material/snack-bar'; +import {MatTooltip} from '@angular/material/tooltip'; +import {ActivatedRoute, Router} from '@angular/router'; +import {CobblerApiService, Repo} from 'cobbler-api'; +import {KeyValueEditorComponent} from '../../../common/key-value-editor/key-value-editor.component'; +import {MultiSelectComponent} from '../../../common/multi-select/multi-select.component'; +import {UserService} from '../../../services/user.service'; + +@Component({ + selector: 'cobbler-edit', + standalone: true, + imports: [ + FormsModule, + MatButton, + MatCheckbox, + MatFormField, + MatIcon, + MatIconButton, + MatInput, + MatLabel, + MatOption, + MatSelect, + MatTooltip, + ReactiveFormsModule, + MultiSelectComponent, + KeyValueEditorComponent + ], + templateUrl: './repository-edit.component.html', + styleUrl: './repository-edit.component.scss' +}) +export class RepositoryEditComponent implements OnInit { + name: string; + repository: Repo; + private readonly _formBuilder = inject(FormBuilder); + repositoryFormGroup = this._formBuilder.group({ + name: new FormControl({value: "", disabled: true}), + uid: new FormControl({value: "", disabled: true}), + mtime: new FormControl({value: "", disabled: true}), + ctime: new FormControl({value: "", disabled: true}), + depth: new FormControl({value: 0, disabled: true}), + priority: new FormControl({value: 0, disabled: true}), + is_subobject: new FormControl({value: false, disabled: true}), + keep_updated: new FormControl({value: false, disabled: true}), + mirror_locally: new FormControl({value: false, disabled: true}), + comment: new FormControl({value: "", disabled: true}), + redhat_management_key: new FormControl({value: "", disabled: true}), + mirror_type: new FormControl({value: "", disabled: true}), + mirror: new FormControl({value: "", disabled: true}), + breed: new FormControl({value: "", disabled: true}), + os_version: new FormControl({value: "", disabled: true}), + proxy: new FormControl({value: "", disabled: true}), + createrepo_flags: new FormControl({value: "", disabled: true}), + owners: new FormControl({value: [], disabled: true}), + owners_inherited: new FormControl({value: false, disabled: true}), + apt_components: new FormControl({value: [], disabled: true}), + apt_dists: new FormControl({value: [], disabled: true}), + rpm_list: new FormControl({value: [], disabled: true}), + environment: new FormControl({value: {}, disabled: true}), + yumopts: new FormControl({value: {}, disabled: true}), + rsyncopts: new FormControl({value: {}, disabled: true}), + }); + isEditMode: boolean = false; + + constructor( + private route: ActivatedRoute, + private userService: UserService, + private cobblerApiService: CobblerApiService, + private _snackBar: MatSnackBar, + private router: Router, + ) { + this.name = this.route.snapshot.paramMap.get("name"); + } + + ngOnInit(): void { + this.refreshData() + } + + refreshData(): void { + this.cobblerApiService.get_repo(this.name, false, false, this.userService.token).subscribe(value => { + this.repository = value + this.repositoryFormGroup.controls.name.setValue(this.repository.name) + this.repositoryFormGroup.controls.uid.setValue(this.repository.uid) + this.repositoryFormGroup.controls.mtime.setValue(new Date(this.repository.mtime * 1000).toString()) + this.repositoryFormGroup.controls.ctime.setValue(new Date(this.repository.ctime * 1000).toString()) + this.repositoryFormGroup.controls.depth.setValue(this.repository.depth) + this.repositoryFormGroup.controls.priority.setValue(this.repository.priority) + this.repositoryFormGroup.controls.is_subobject.setValue(this.repository.is_subobject) + this.repositoryFormGroup.controls.keep_updated.setValue(this.repository.keep_updated) + this.repositoryFormGroup.controls.mirror_locally.setValue(this.repository.mirror_locally) + this.repositoryFormGroup.controls.comment.setValue(this.repository.comment) + this.repositoryFormGroup.controls.proxy.setValue(this.repository.proxy) + this.repositoryFormGroup.controls.mirror_type.setValue(this.repository.mirror_type) + this.repositoryFormGroup.controls.mirror.setValue(this.repository.mirror) + this.repositoryFormGroup.controls.breed.setValue(this.repository.breed) + this.repositoryFormGroup.controls.os_version.setValue(this.repository.os_version) + this.repositoryFormGroup.controls.createrepo_flags.setValue(this.repository.createrepo_flags) + this.repositoryFormGroup.controls.rpm_list.setValue(this.repository.rpm_list) + this.repositoryFormGroup.controls.apt_dists.setValue(this.repository.apt_dists) + this.repositoryFormGroup.controls.apt_components.setValue(this.repository.apt_components) + if (typeof this.repository.owners === "string") { + this.repositoryFormGroup.controls.owners_inherited.setValue(true) + } else { + this.repositoryFormGroup.controls.owners_inherited.setValue(false) + this.repositoryFormGroup.controls.owners.setValue(this.repository.owners) + } + this.repositoryFormGroup.controls.environment.setValue(this.repository.environment) + this.repositoryFormGroup.controls.yumopts.setValue(this.repository.yumopts) + this.repositoryFormGroup.controls.rsyncopts.setValue(this.repository.rsyncopts) + }, error => { + // HTML encode the error message since it originates from XML + this._snackBar.open(this.toHTML(error.message), 'Close'); + }); + } + + removeRepository(): void { + this.cobblerApiService.remove_repo(this.name, this.userService.token, false).subscribe(value => { + if (value) { + this.router.navigate(["/items", "repository"]) + } + // HTML encode the error message since it originates from XML + this._snackBar.open("Delete failed! Check server logs for more information.", 'Close'); + }, error => { + // HTML encode the error message since it originates from XML + this._snackBar.open(this.toHTML(error.message), 'Close'); + }) + } + + editRepository(): void { + // TODO + this._snackBar.open("Not implemented at the moment!", "Close") + } + + copyRepository(): void { + this.cobblerApiService.copy_repo("", "", this.userService.token) + .subscribe(value => { + // TODO + }, error => { + // HTML encode the error message since it originates from XML + this._snackBar.open(this.toHTML(error.message), 'Close'); + }) + } + + saveRepository(): void { + // TODO + } + + get repositoryOwners(): string[] { + if (this.repository && this.repository.owners) { + const ownersResult = this.repository.owners + if (typeof ownersResult !== 'string') { + return ownersResult; + } + } + return [] + } + + get repositoryYumopts(): object { + if (this.repository && this.repository.yumopts) { + const yumoptsResult = this.repository.yumopts + if (typeof yumoptsResult !== 'string') { + return yumoptsResult + } + } + return {} + } + + get repositoryRsyncopts(): object { + if (this.repository && this.repository.rsyncopts) { + const rsyncoptsResult = this.repository.rsyncopts + if (typeof rsyncoptsResult !== 'string') { + return rsyncoptsResult + } + } + return {} + } + + toHTML(input: string): any { + // FIXME: Deduplicate method + return new DOMParser().parseFromString(input, 'text/html').documentElement.textContent; + } +} diff --git a/projects/cobbler-frontend/src/app/items/repository/overview/repository-overview.component.html b/projects/cobbler-frontend/src/app/items/repository/overview/repository-overview.component.html new file mode 100644 index 00000000..f616ff95 --- /dev/null +++ b/projects/cobbler-frontend/src/app/items/repository/overview/repository-overview.component.html @@ -0,0 +1,46 @@ +

REPOSITORIES

+ + + + + + + + + + + + + + + + + + + + + + + + + + + +
Name{{element.name}}Breed{{element.breed}}Mirror Type{{element.mirror_type}} + + + + + + +
+ diff --git a/projects/cobbler-frontend/src/app/items/templates/templates.component.css b/projects/cobbler-frontend/src/app/items/repository/overview/repository-overview.component.scss similarity index 100% rename from projects/cobbler-frontend/src/app/items/templates/templates.component.css rename to projects/cobbler-frontend/src/app/items/repository/overview/repository-overview.component.scss diff --git a/projects/cobbler-frontend/src/app/items/repository/overview/repository-overview.component.spec.ts b/projects/cobbler-frontend/src/app/items/repository/overview/repository-overview.component.spec.ts new file mode 100644 index 00000000..13c93d1c --- /dev/null +++ b/projects/cobbler-frontend/src/app/items/repository/overview/repository-overview.component.spec.ts @@ -0,0 +1,36 @@ +import {provideHttpClient} from '@angular/common/http'; +import {provideHttpClientTesting} from '@angular/common/http/testing'; +import { ComponentFixture, TestBed } from '@angular/core/testing'; +import {provideRouter} from '@angular/router'; +import {COBBLER_URL} from 'cobbler-api'; + +import { RepositoryOverviewComponent } from './repository-overview.component'; + +describe('RepositoryOverviewComponent', () => { + let component: RepositoryOverviewComponent; + let fixture: ComponentFixture; + + beforeEach(async () => { + await TestBed.configureTestingModule({ + imports: [RepositoryOverviewComponent], + providers: [ + provideRouter([]), + provideHttpClient(), + provideHttpClientTesting(), + { + provide: COBBLER_URL, + useValue: new URL('http://localhost/cobbler_api') + }, + ] + }) + .compileComponents(); + + fixture = TestBed.createComponent(RepositoryOverviewComponent); + component = fixture.componentInstance; + fixture.detectChanges(); + }); + + it('should create', () => { + expect(component).toBeTruthy(); + }); +}); diff --git a/projects/cobbler-frontend/src/app/items/repository/overview/repository-overview.component.ts b/projects/cobbler-frontend/src/app/items/repository/overview/repository-overview.component.ts new file mode 100644 index 00000000..136fae32 --- /dev/null +++ b/projects/cobbler-frontend/src/app/items/repository/overview/repository-overview.component.ts @@ -0,0 +1,90 @@ +import {Component, OnInit, ViewChild} from '@angular/core'; +import {MatIconButton} from '@angular/material/button'; +import {MatIcon} from '@angular/material/icon'; +import {MatMenu, MatMenuItem, MatMenuTrigger} from '@angular/material/menu'; +import {MatSnackBar} from '@angular/material/snack-bar'; +import { + MatCell, + MatCellDef, + MatColumnDef, + MatHeaderCell, MatHeaderCellDef, + MatHeaderRow, + MatHeaderRowDef, + MatRow, MatRowDef, MatTable +} from '@angular/material/table'; +import {Router} from '@angular/router'; +import {CobblerApiService, Repo} from 'cobbler-api'; +import {UserService} from '../../../services/user.service'; + +@Component({ + selector: 'cobbler-overview', + standalone: true, + imports: [ + MatCell, + MatCellDef, + MatColumnDef, + MatHeaderCell, + MatHeaderRow, + MatHeaderRowDef, + MatIcon, + MatIconButton, + MatMenu, + MatMenuItem, + MatRow, + MatRowDef, + MatTable, + MatHeaderCellDef, + MatMenuTrigger + ], + templateUrl: './repository-overview.component.html', + styleUrl: './repository-overview.component.scss' +}) +export class RepositoryOverviewComponent implements OnInit { + displayedColumns: string[] = ['name', "breed", "mirror_type", "actions"]; + dataSource: Array = []; + + @ViewChild(MatTable) table: MatTable; + + constructor( + public userService: UserService, + private cobblerApiService: CobblerApiService, + private _snackBar: MatSnackBar, + private router: Router, + ) { + } + + ngOnInit(): void { + this.retrieveRepositories() + } + + private retrieveRepositories(): void { + this.cobblerApiService.get_repos().subscribe(value => { + this.dataSource = value + }, error => { + // HTML encode the error message since it originates from XML + this._snackBar.open(this.toHTML(error.message), 'Close'); + }) + } + + showRepository(uid: string, name: string): void { + this.router.navigate(["/items", "repository", name]) + } + + editRepository(uid: string, name: string): void { + // TODO + } + + deleteRepository(uid: string, name: string): void { + this.cobblerApiService.remove_repo(name, this.userService.token, false).subscribe(value => { + this.retrieveRepositories() + }, error => { + // HTML encode the error message since it originates from XML + this._snackBar.open(this.toHTML(error.message), 'Close'); + }) + } + + toHTML(input: string): any { + // FIXME: Deduplicate method + return new DOMParser().parseFromString(input, 'text/html').documentElement.textContent; + } +} diff --git a/projects/cobbler-frontend/src/app/items/snippet/edit/snippet-edit.component.html b/projects/cobbler-frontend/src/app/items/snippet/edit/snippet-edit.component.html new file mode 100644 index 00000000..ff11f0f7 --- /dev/null +++ b/projects/cobbler-frontend/src/app/items/snippet/edit/snippet-edit.component.html @@ -0,0 +1,44 @@ +
+
+

Name: {{ name }}

+ + + + + + + + + + + + +
+
+ +
+ + Template Content + + + @if (isEditMode) { + + } +
+ diff --git a/projects/cobbler-frontend/src/app/items/snippet/edit/snippet-edit.component.scss b/projects/cobbler-frontend/src/app/items/snippet/edit/snippet-edit.component.scss new file mode 100644 index 00000000..2a9efa5d --- /dev/null +++ b/projects/cobbler-frontend/src/app/items/snippet/edit/snippet-edit.component.scss @@ -0,0 +1,30 @@ +.title-table { + display: table; + width: 100%; +} + +.title-row { + display: table-cell; + width: 100%; +} + +.title-cell-text { + display: table-cell; + width: 100%; + vertical-align: middle; +} + +.title-cell-button { + display: table-cell; +} + +.form-replicate { + min-width: 150px; + max-width: 600px; + width: 100%; +} + +.form-field-full-width { + width: 100%; +} + diff --git a/projects/cobbler-frontend/src/app/items/snippet/edit/snippet-edit.component.spec.ts b/projects/cobbler-frontend/src/app/items/snippet/edit/snippet-edit.component.spec.ts new file mode 100644 index 00000000..46395828 --- /dev/null +++ b/projects/cobbler-frontend/src/app/items/snippet/edit/snippet-edit.component.spec.ts @@ -0,0 +1,50 @@ +import {provideHttpClient} from '@angular/common/http'; +import {provideHttpClientTesting} from '@angular/common/http/testing'; +import { ComponentFixture, TestBed } from '@angular/core/testing'; +import {NoopAnimationsModule} from '@angular/platform-browser/animations'; +import {ActivatedRoute, provideRouter} from '@angular/router'; +import {COBBLER_URL} from 'cobbler-api'; + +import { SnippetEditComponent } from './snippet-edit.component'; + +describe('SnippetEditComponent', () => { + let component: SnippetEditComponent; + let fixture: ComponentFixture; + + beforeEach(async () => { + await TestBed.configureTestingModule({ + imports: [ + SnippetEditComponent, + NoopAnimationsModule, + ], + providers: [ + provideRouter([]), + provideHttpClient(), + provideHttpClientTesting(), + { + provide: COBBLER_URL, + useValue: new URL('http://localhost/cobbler_api') + }, + { + provide: ActivatedRoute, + useValue: { + snapshot: { + paramMap: { + get: () => "testsnippet" + }, + }, + }, + }, + ] + }) + .compileComponents(); + + fixture = TestBed.createComponent(SnippetEditComponent); + component = fixture.componentInstance; + fixture.detectChanges(); + }); + + it('should create', () => { + expect(component).toBeTruthy(); + }); +}); diff --git a/projects/cobbler-frontend/src/app/items/snippet/edit/snippet-edit.component.ts b/projects/cobbler-frontend/src/app/items/snippet/edit/snippet-edit.component.ts new file mode 100644 index 00000000..140928cb --- /dev/null +++ b/projects/cobbler-frontend/src/app/items/snippet/edit/snippet-edit.component.ts @@ -0,0 +1,106 @@ +import {Component, inject, OnInit} from '@angular/core'; +import {FormBuilder, FormControl, FormsModule, ReactiveFormsModule} from '@angular/forms'; +import {MatOption} from '@angular/material/autocomplete'; +import {MatButton, MatIconButton} from '@angular/material/button'; +import {MatCheckbox} from '@angular/material/checkbox'; +import {MatFormField, MatLabel} from '@angular/material/form-field'; +import {MatIcon} from '@angular/material/icon'; +import {MatInput} from '@angular/material/input'; +import {MatSelect} from '@angular/material/select'; +import {MatSnackBar} from '@angular/material/snack-bar'; +import {MatTooltip} from '@angular/material/tooltip'; +import {ActivatedRoute, Router} from '@angular/router'; +import {CobblerApiService, Profile} from 'cobbler-api'; +import {UserService} from '../../../services/user.service'; + +@Component({ + selector: 'cobbler-edit', + standalone: true, + imports: [ + FormsModule, + MatButton, + MatCheckbox, + MatFormField, + MatIcon, + MatIconButton, + MatInput, + MatLabel, + MatOption, + MatSelect, + MatTooltip, + ReactiveFormsModule + ], + templateUrl: './snippet-edit.component.html', + styleUrl: './snippet-edit.component.scss' +}) +export class SnippetEditComponent implements OnInit { + name: string; + content: string; + private readonly _formBuilder = inject(FormBuilder); + snippetFormGroup = this._formBuilder.group({ + content: new FormControl({value: "", disabled: true}), + }); + isEditMode: boolean = false; + + constructor( + private route: ActivatedRoute, + private userService: UserService, + private cobblerApiService: CobblerApiService, + private _snackBar: MatSnackBar, + private router: Router, + ) { + this.name = this.route.snapshot.paramMap.get("name"); + } + + ngOnInit(): void { + this.refreshData() + } + + refreshData(): void { + this.cobblerApiService.read_autoinstall_snippet(this.name, this.userService.token).subscribe(value => { + this.content = value; + this.snippetFormGroup.controls.content.setValue(this.toHTML(this.content)); + }, error => { + // HTML encode the error message since it originates from XML + this._snackBar.open(this.toHTML(error.message), 'Close'); + }); + } + + removeSnippet(): void { + this.cobblerApiService.remove_autoinstall_snippet(this.name, this.userService.token).subscribe(value => { + if (value) { + this.router.navigate(["/items", "profile"]) + } + // HTML encode the error message since it originates from XML + this._snackBar.open("Delete failed! Check server logs for more information.", 'Close'); + }, error => { + // HTML encode the error message since it originates from XML + this._snackBar.open(this.toHTML(error.message), 'Close'); + }) + } + + editSnippet(): void { + // TODO + this._snackBar.open("Not implemented at the moment!", "Close") + } + + copySnippet(): void { + // TODO + this._snackBar.open("Not implemented at the moment!", "Close") + } + + saveSnippet(): void { + // TODO + this.cobblerApiService.write_autoinstall_snippet(this.name, "", this.userService.token).subscribe(value => { + // TODO + }, error => { + // HTML encode the error message since it originates from XML + this._snackBar.open(this.toHTML(error.message), 'Close'); + }) + } + + toHTML(input: string): any { + // FIXME: Deduplicate method + return new DOMParser().parseFromString(input, 'text/html').documentElement.textContent; + } +} diff --git a/projects/cobbler-frontend/src/app/items/snippet/overview/snippet-overview.component.html b/projects/cobbler-frontend/src/app/items/snippet/overview/snippet-overview.component.html new file mode 100644 index 00000000..038301c1 --- /dev/null +++ b/projects/cobbler-frontend/src/app/items/snippet/overview/snippet-overview.component.html @@ -0,0 +1,34 @@ +

SNIPPETS

+ + + + + + + + + + + + + + + +
Name{{element}} + + + + + + +
+ diff --git a/projects/cobbler-frontend/src/app/items/snippet/overview/snippet-overview.component.scss b/projects/cobbler-frontend/src/app/items/snippet/overview/snippet-overview.component.scss new file mode 100644 index 00000000..e69de29b diff --git a/projects/cobbler-frontend/src/app/items/snippet/overview/snippet-overview.component.spec.ts b/projects/cobbler-frontend/src/app/items/snippet/overview/snippet-overview.component.spec.ts new file mode 100644 index 00000000..e11ed445 --- /dev/null +++ b/projects/cobbler-frontend/src/app/items/snippet/overview/snippet-overview.component.spec.ts @@ -0,0 +1,36 @@ +import {provideHttpClient} from '@angular/common/http'; +import {provideHttpClientTesting} from '@angular/common/http/testing'; +import { ComponentFixture, TestBed } from '@angular/core/testing'; +import {provideRouter} from '@angular/router'; +import {COBBLER_URL} from 'cobbler-api'; + +import { SnippetOverviewComponent } from './snippet-overview.component'; + +describe('SnippetOverviewComponent', () => { + let component: SnippetOverviewComponent; + let fixture: ComponentFixture; + + beforeEach(async () => { + await TestBed.configureTestingModule({ + imports: [SnippetOverviewComponent], + providers: [ + provideRouter([]), + provideHttpClient(), + provideHttpClientTesting(), + { + provide: COBBLER_URL, + useValue: new URL('http://localhost/cobbler_api') + }, + ] + }) + .compileComponents(); + + fixture = TestBed.createComponent(SnippetOverviewComponent); + component = fixture.componentInstance; + fixture.detectChanges(); + }); + + it('should create', () => { + expect(component).toBeTruthy(); + }); +}); diff --git a/projects/cobbler-frontend/src/app/items/snippet/overview/snippet-overview.component.ts b/projects/cobbler-frontend/src/app/items/snippet/overview/snippet-overview.component.ts new file mode 100644 index 00000000..2a6f746b --- /dev/null +++ b/projects/cobbler-frontend/src/app/items/snippet/overview/snippet-overview.component.ts @@ -0,0 +1,90 @@ +import {Component, OnInit, ViewChild} from '@angular/core'; +import {MatIconButton} from '@angular/material/button'; +import {MatIcon} from '@angular/material/icon'; +import {MatMenu, MatMenuItem, MatMenuTrigger} from '@angular/material/menu'; +import {MatSnackBar} from '@angular/material/snack-bar'; +import { + MatCell, + MatCellDef, + MatColumnDef, + MatHeaderCell, MatHeaderCellDef, + MatHeaderRow, + MatHeaderRowDef, + MatRow, MatRowDef, MatTable +} from '@angular/material/table'; +import {Router} from '@angular/router'; +import {CobblerApiService} from 'cobbler-api'; +import {UserService} from '../../../services/user.service'; + +@Component({ + selector: 'cobbler-overview', + standalone: true, + imports: [ + MatCell, + MatCellDef, + MatColumnDef, + MatHeaderCell, + MatHeaderRow, + MatHeaderRowDef, + MatIcon, + MatIconButton, + MatMenu, + MatMenuItem, + MatRow, + MatRowDef, + MatTable, + MatMenuTrigger, + MatHeaderCellDef + ], + templateUrl: './snippet-overview.component.html', + styleUrl: './snippet-overview.component.scss' +}) +export class SnippetOverviewComponent implements OnInit{ + displayedColumns: string[] = ['name', "actions"]; + dataSource: Array = []; + + @ViewChild(MatTable) table: MatTable; + + constructor( + public userService: UserService, + private cobblerApiService: CobblerApiService, + private _snackBar: MatSnackBar, + private router: Router, + ) { + } + + ngOnInit(): void { + this.retrieveSnippets() + } + + private retrieveSnippets(): void { + this.cobblerApiService.get_autoinstall_snippets(this.userService.token).subscribe(value => { + this.dataSource = value + }, error => { + // HTML encode the error message since it originates from XML + this._snackBar.open(this.toHTML(error.message), 'Close'); + }) + } + + showSnippet(name: string): void { + this.router.navigate(["/items", "snippet", name]) + } + + editSnippet(name: string): void { + // TODO + } + + deleteSnippet(name: string): void { + this.cobblerApiService.remove_autoinstall_snippet(name, this.userService.token).subscribe(value => { + this.retrieveSnippets() + }, error => { + // HTML encode the error message since it originates from XML + this._snackBar.open(this.toHTML(error.message), 'Close'); + }) + } + + toHTML(input: string): any { + // FIXME: Deduplicate method + return new DOMParser().parseFromString(input, 'text/html').documentElement.textContent; + } +} diff --git a/projects/cobbler-frontend/src/app/items/snippets/snippets.component.html b/projects/cobbler-frontend/src/app/items/snippets/snippets.component.html deleted file mode 100644 index ff6e6433..00000000 --- a/projects/cobbler-frontend/src/app/items/snippets/snippets.component.html +++ /dev/null @@ -1,13 +0,0 @@ -
-
- -

SNIPPETS

-
- - data 01 - data 02 - data 03 - -
-
-
diff --git a/projects/cobbler-frontend/src/app/items/snippets/snippets.component.spec.ts b/projects/cobbler-frontend/src/app/items/snippets/snippets.component.spec.ts deleted file mode 100644 index c1cf5c48..00000000 --- a/projects/cobbler-frontend/src/app/items/snippets/snippets.component.spec.ts +++ /dev/null @@ -1,30 +0,0 @@ -import { ComponentFixture, TestBed } from '@angular/core/testing'; -import { MatListModule } from '@angular/material/list'; -import {provideRouter} from '@angular/router'; - -import { SnippetsComponent } from './snippets.component'; - - -describe('SnippetsComponent', () => { - let component: SnippetsComponent; - let fixture: ComponentFixture; - - beforeEach(async () => { - await TestBed.configureTestingModule({ - imports: [SnippetsComponent, MatListModule], - providers: [ - provideRouter([]), - ] - }).compileComponents(); - }); - - beforeEach(() => { - fixture = TestBed.createComponent(SnippetsComponent); - component = fixture.componentInstance; - fixture.detectChanges(); - }); - - it('should create', () => { - expect(component).toBeTruthy(); - }); -}); diff --git a/projects/cobbler-frontend/src/app/items/snippets/snippets.component.ts b/projects/cobbler-frontend/src/app/items/snippets/snippets.component.ts deleted file mode 100644 index 8d144cb8..00000000 --- a/projects/cobbler-frontend/src/app/items/snippets/snippets.component.ts +++ /dev/null @@ -1,16 +0,0 @@ -import {Component} from '@angular/core'; -import { MatListModule } from '@angular/material/list'; -import { RouterOutlet } from '@angular/router'; - -@Component({ - selector: 'cobbler-snippets', - templateUrl: './snippets.component.html', - styleUrls: ['./snippets.component.css'], - standalone: true, - imports: [RouterOutlet, MatListModule], -}) -export class SnippetsComponent { - - constructor() { - } -} diff --git a/projects/cobbler-frontend/src/app/items/system/edit/system-edit.component.html b/projects/cobbler-frontend/src/app/items/system/edit/system-edit.component.html new file mode 100644 index 00000000..e7ba4164 --- /dev/null +++ b/projects/cobbler-frontend/src/app/items/system/edit/system-edit.component.html @@ -0,0 +1,234 @@ +
+
+

Name: {{ name }}

+ + + + + + + + + + + + +
+
+ + + + +
+ + Name + + + + UID + + + + Last modified time + + + + Creation time + + + + Depth + + + Is Subobject? + + + Inherited + + + Comment + + + IPv6 Auto Configuration? + Repositories enabled? + Network boot enabled? + VM auto boot? + VM PXE boot? + + Autoinstall + + + + Parent + + + + Gateway + + + + Hostname + + + + Image + + + + IPv6 Default Device + + + + Next Server IPv4 + + + + Next Server IPv6 + + + + DHCP Filename + + + + Power Address + + + + Power ID + + + + Power Password + + + + Power Type + + + + Power Username + + + + Power Options + + + + Power Identity File + + + + Profile + + + + Proxy + + + + RedHat Management Key + + + + Server + + + + Status + + + + VM Disk Driver + + + + VM Path + + + + VM Type + + + + VM CPUs + + + + VM File Size + + + + VM RAM + + + + Serial Device + + + + Serial Baud Rate + + + + + Inherited + + + + Inherited + + + + Inherited + + + + Inherited + + + + Inherited + + + + Inherited + + + + Inherited + + + + + + + + + + Inherited + + + + Inherited + + @if (isEditMode) { + + } +
diff --git a/projects/cobbler-frontend/src/app/items/system/edit/system-edit.component.scss b/projects/cobbler-frontend/src/app/items/system/edit/system-edit.component.scss new file mode 100644 index 00000000..2a9efa5d --- /dev/null +++ b/projects/cobbler-frontend/src/app/items/system/edit/system-edit.component.scss @@ -0,0 +1,30 @@ +.title-table { + display: table; + width: 100%; +} + +.title-row { + display: table-cell; + width: 100%; +} + +.title-cell-text { + display: table-cell; + width: 100%; + vertical-align: middle; +} + +.title-cell-button { + display: table-cell; +} + +.form-replicate { + min-width: 150px; + max-width: 600px; + width: 100%; +} + +.form-field-full-width { + width: 100%; +} + diff --git a/projects/cobbler-frontend/src/app/items/system/edit/system-edit.component.spec.ts b/projects/cobbler-frontend/src/app/items/system/edit/system-edit.component.spec.ts new file mode 100644 index 00000000..848c1bf8 --- /dev/null +++ b/projects/cobbler-frontend/src/app/items/system/edit/system-edit.component.spec.ts @@ -0,0 +1,50 @@ +import {provideHttpClient} from '@angular/common/http'; +import {provideHttpClientTesting} from '@angular/common/http/testing'; +import { ComponentFixture, TestBed } from '@angular/core/testing'; +import {NoopAnimationsModule} from '@angular/platform-browser/animations'; +import {ActivatedRoute, provideRouter} from '@angular/router'; +import {COBBLER_URL} from 'cobbler-api'; + +import { SystemEditComponent } from './system-edit.component'; + +describe('SystemEditComponent', () => { + let component: SystemEditComponent; + let fixture: ComponentFixture; + + beforeEach(async () => { + await TestBed.configureTestingModule({ + imports: [ + SystemEditComponent, + NoopAnimationsModule, + ], + providers: [ + provideRouter([]), + provideHttpClient(), + provideHttpClientTesting(), + { + provide: COBBLER_URL, + useValue: new URL('http://localhost/cobbler_api') + }, + { + provide: ActivatedRoute, + useValue: { + snapshot: { + paramMap: { + get: () => "testsystem" + }, + }, + }, + }, + ] + }) + .compileComponents(); + + fixture = TestBed.createComponent(SystemEditComponent); + component = fixture.componentInstance; + fixture.detectChanges(); + }); + + it('should create', () => { + expect(component).toBeTruthy(); + }); +}); diff --git a/projects/cobbler-frontend/src/app/items/system/edit/system-edit.component.ts b/projects/cobbler-frontend/src/app/items/system/edit/system-edit.component.ts new file mode 100644 index 00000000..6d29cf31 --- /dev/null +++ b/projects/cobbler-frontend/src/app/items/system/edit/system-edit.component.ts @@ -0,0 +1,362 @@ +import {Component, inject, OnInit} from '@angular/core'; +import {FormBuilder, FormControl, FormsModule, ReactiveFormsModule} from '@angular/forms'; +import {MatOption} from '@angular/material/autocomplete'; +import {MatButton, MatIconButton} from '@angular/material/button'; +import {MatCheckbox} from '@angular/material/checkbox'; +import {MatFormField, MatLabel} from '@angular/material/form-field'; +import {MatIcon} from '@angular/material/icon'; +import {MatInput} from '@angular/material/input'; +import {MatSelect} from '@angular/material/select'; +import {MatSnackBar} from '@angular/material/snack-bar'; +import {MatTooltip} from '@angular/material/tooltip'; +import {ActivatedRoute, Router} from '@angular/router'; +import {CobblerApiService, System} from 'cobbler-api'; +import {KeyValueEditorComponent} from '../../../common/key-value-editor/key-value-editor.component'; +import {MultiSelectComponent} from '../../../common/multi-select/multi-select.component'; +import {UserService} from '../../../services/user.service'; + +@Component({ + selector: 'cobbler-edit', + standalone: true, + imports: [ + FormsModule, + MatButton, + MatCheckbox, + MatFormField, + MatIcon, + MatIconButton, + MatInput, + MatLabel, + MatOption, + MatSelect, + MatTooltip, + ReactiveFormsModule, + MultiSelectComponent, + KeyValueEditorComponent + ], + templateUrl: './system-edit.component.html', + styleUrl: './system-edit.component.scss' +}) +export class SystemEditComponent implements OnInit { + name: string; + system: System; + private readonly _formBuilder = inject(FormBuilder); + systemFormGroup = this._formBuilder.group({ + name: new FormControl({value: "", disabled: true}), + uid: new FormControl({value: "", disabled: true}), + mtime: new FormControl({value: "", disabled: true}), + ctime: new FormControl({value: "", disabled: true}), + depth: new FormControl({value: 0, disabled: true}), + virt_cpus: new FormControl({value: 0, disabled: true}), + virt_file_size: new FormControl({value: 0, disabled: true}), + virt_ram: new FormControl({value: 0, disabled: true}), + serial_device: new FormControl({value: 0, disabled: true}), + serial_baud_rate: new FormControl({value: 0, disabled: true}), + is_subobject: new FormControl({value: false, disabled: true}), + comment: new FormControl({value: "", disabled: true}), + redhat_management_key: new FormControl({value: "", disabled: true}), + autoinstall: new FormControl({value: "", disabled: true}), + parent: new FormControl({value: "", disabled: true}), + gateway: new FormControl({value: "", disabled: true}), + hostname: new FormControl({value: "", disabled: true}), + image: new FormControl({value: "", disabled: true}), + ipv6_default_device: new FormControl({value: "", disabled: true}), + next_server_v4: new FormControl({value: "", disabled: true}), + next_server_v6: new FormControl({value: "", disabled: true}), + filename: new FormControl({value: "", disabled: true}), + power_address: new FormControl({value: "", disabled: true}), + power_id: new FormControl({value: "", disabled: true}), + power_pass: new FormControl({value: "", disabled: true}), + power_type: new FormControl({value: "", disabled: true}), + power_user: new FormControl({value: "", disabled: true}), + power_options: new FormControl({value: "", disabled: true}), + power_identity_file: new FormControl({value: "", disabled: true}), + profile: new FormControl({value: "", disabled: true}), + proxy: new FormControl({value: "", disabled: true}), + server: new FormControl({value: "", disabled: true}), + status: new FormControl({value: "", disabled: true}), + virt_disk_driver: new FormControl({value: "", disabled: true}), + virt_path: new FormControl({value: "", disabled: true}), + virt_type: new FormControl({value: "", disabled: true}), + boot_loaders: new FormControl({value: [], disabled: true}), + bootloader_inherited: new FormControl({value: false, disabled: true}), + ipv6_autoconfiguration: new FormControl({value: false, disabled: true}), + repos_enabled: new FormControl({value: false, disabled: true}), + netboot_enabled: new FormControl({value: false, disabled: true}), + virt_auto_boot: new FormControl({value: false, disabled: true}), + virt_pxe_boot: new FormControl({value: false, disabled: true}), + owners: new FormControl({value: [], disabled: true}), + owners_inherited: new FormControl({value: false, disabled: true}), + boot_files: new FormControl({value: {}, disabled: true}), + boot_files_inherited: new FormControl({value: false, disabled: true}), + fetchable_files: new FormControl({value: {}, disabled: true}), + fetchable_files_inherited: new FormControl({value: false, disabled: true}), + kernel_options: new FormControl({value: {}, disabled: true}), + kernel_options_inherited: new FormControl({value: false, disabled: true}), + kernel_options_post: new FormControl({value: {}, disabled: true}), + kernel_options_post_inherited: new FormControl({value: false, disabled: true}), + mgmt_classes: new FormControl({value: [], disabled: true}), + mgmt_classes_inherited: new FormControl({value: false, disabled: true}), + mgmt_parameters: new FormControl({value: {}, disabled: true}), + mgmt_parameters_inherited: new FormControl({value: false, disabled: true}), + template_files: new FormControl({value: {}, disabled: true}), + template_files_inherited: new FormControl({value: false, disabled: true}), + autoinstall_meta: new FormControl({value: {}, disabled: true}), + autoinstall_meta_inherited: new FormControl({value: false, disabled: true}), + name_servers: new FormControl({value: [], disabled: true}), + name_servers_search: new FormControl({value: [], disabled: true}), + }); + isEditMode: boolean = false; + + constructor( + private route: ActivatedRoute, + private userService: UserService, + private cobblerApiService: CobblerApiService, + private _snackBar: MatSnackBar, + private router: Router, + ) { + this.name = this.route.snapshot.paramMap.get("name"); + } + + ngOnInit(): void { + this.refreshData() + } + + refreshData(): void { + this.cobblerApiService.get_system(this.name, false, false, this.userService.token).subscribe(value => { + this.system = value + this.systemFormGroup.controls.name.setValue(this.system.name) + this.systemFormGroup.controls.uid.setValue(this.system.uid) + this.systemFormGroup.controls.mtime.setValue(new Date(this.system.mtime * 1000).toString()) + this.systemFormGroup.controls.ctime.setValue(new Date(this.system.ctime * 1000).toString()) + this.systemFormGroup.controls.depth.setValue(this.system.depth) + if (typeof this.system.virt_cpus !== "string") { + this.systemFormGroup.controls.virt_cpus.setValue(this.system.virt_cpus) + } + if (typeof this.system.virt_file_size !== "string") { + this.systemFormGroup.controls.virt_file_size.setValue(this.system.virt_file_size) + } + if (typeof this.system.virt_ram !== "string") { + this.systemFormGroup.controls.virt_ram.setValue(this.system.virt_ram) + } + this.systemFormGroup.controls.serial_device.setValue(this.system.serial_device) + this.systemFormGroup.controls.serial_baud_rate.setValue(this.system.serial_baud_rate) + this.systemFormGroup.controls.is_subobject.setValue(this.system.is_subobject) + this.systemFormGroup.controls.ipv6_autoconfiguration.setValue(this.system.ipv6_autoconfiguration) + this.systemFormGroup.controls.repos_enabled.setValue(this.system.repos_enabled) + this.systemFormGroup.controls.netboot_enabled.setValue(this.system.netboot_enabled) + if (typeof this.system.virt_auto_boot !== "string") { + // TODO: Show inheritance if string + this.systemFormGroup.controls.virt_auto_boot.setValue(this.system.virt_auto_boot) + } + this.systemFormGroup.controls.virt_pxe_boot.setValue(this.system.virt_pxe_boot) + this.systemFormGroup.controls.redhat_management_key.setValue(this.system.redhat_management_key) + this.systemFormGroup.controls.autoinstall.setValue(this.system.autoinstall) + this.systemFormGroup.controls.parent.setValue(this.system.parent) + this.systemFormGroup.controls.gateway.setValue(this.system.gateway) + this.systemFormGroup.controls.hostname.setValue(this.system.hostname) + this.systemFormGroup.controls.image.setValue(this.system.image) + this.systemFormGroup.controls.ipv6_default_device.setValue(this.system.ipv6_default_device) + this.systemFormGroup.controls.next_server_v4.setValue(this.system.next_server_v4) + this.systemFormGroup.controls.next_server_v6.setValue(this.system.next_server_v6) + this.systemFormGroup.controls.filename.setValue(this.system.filename) + this.systemFormGroup.controls.power_address.setValue(this.system.power_address) + this.systemFormGroup.controls.power_id.setValue(this.system.power_id) + this.systemFormGroup.controls.power_pass.setValue(this.system.power_pass) + this.systemFormGroup.controls.power_type.setValue(this.system.power_type) + this.systemFormGroup.controls.power_user.setValue(this.system.power_user) + this.systemFormGroup.controls.power_options.setValue(this.system.power_options) + this.systemFormGroup.controls.power_identity_file.setValue(this.system.power_identity_file) + this.systemFormGroup.controls.profile.setValue(this.system.profile) + this.systemFormGroup.controls.proxy.setValue(this.system.proxy) + this.systemFormGroup.controls.server.setValue(this.system.server) + this.systemFormGroup.controls.status.setValue(this.system.status) + this.systemFormGroup.controls.virt_disk_driver.setValue(this.system.virt_disk_driver) + this.systemFormGroup.controls.virt_path.setValue(this.system.virt_path) + this.systemFormGroup.controls.virt_type.setValue(this.system.virt_type) + this.systemFormGroup.controls.name_servers.setValue(this.system.name_servers) + this.systemFormGroup.controls.name_servers_search.setValue(this.system.name_servers_search) + if (typeof this.system.boot_loaders === "string") { + this.systemFormGroup.controls.bootloader_inherited.setValue(true) + } else { + this.systemFormGroup.controls.bootloader_inherited.setValue(false) + this.systemFormGroup.controls.boot_loaders.setValue(this.system.boot_loaders) + } + if (typeof this.system.owners === "string") { + this.systemFormGroup.controls.owners_inherited.setValue(true) + } else { + this.systemFormGroup.controls.owners_inherited.setValue(false) + this.systemFormGroup.controls.owners.setValue(this.system.owners) + } + if (typeof this.system.boot_files === "string") { + this.systemFormGroup.controls.boot_files_inherited.setValue(true) + } else { + this.systemFormGroup.controls.boot_files_inherited.setValue(false) + this.systemFormGroup.controls.boot_files.setValue(this.system.boot_files) + } + if (typeof this.system.fetchable_files === "string") { + this.systemFormGroup.controls.fetchable_files_inherited.setValue(true) + } else { + this.systemFormGroup.controls.fetchable_files_inherited.setValue(false) + this.systemFormGroup.controls.fetchable_files.setValue(this.system.fetchable_files) + } + if (typeof this.system.kernel_options === "string") { + this.systemFormGroup.controls.kernel_options_inherited.setValue(true) + } else { + this.systemFormGroup.controls.kernel_options_inherited.setValue(false) + this.systemFormGroup.controls.kernel_options.setValue(this.system.kernel_options) + } + if (typeof this.system.kernel_options_post === "string") { + this.systemFormGroup.controls.kernel_options_post_inherited.setValue(true) + } else { + this.systemFormGroup.controls.kernel_options_post_inherited.setValue(false) + this.systemFormGroup.controls.kernel_options_post.setValue(this.system.kernel_options_post) + } + if (typeof this.system.mgmt_classes === "string") { + this.systemFormGroup.controls.mgmt_classes_inherited.setValue(true) + } else { + this.systemFormGroup.controls.mgmt_classes_inherited.setValue(false) + this.systemFormGroup.controls.mgmt_classes.setValue(this.system.mgmt_classes) + } + if (typeof this.system.mgmt_parameters === "string") { + this.systemFormGroup.controls.mgmt_parameters_inherited.setValue(true) + } else { + this.systemFormGroup.controls.mgmt_parameters_inherited.setValue(false) + this.systemFormGroup.controls.mgmt_parameters.setValue(this.system.mgmt_parameters) + } + if (typeof this.system.template_files === "string") { + this.systemFormGroup.controls.template_files_inherited.setValue(true) + } else { + this.systemFormGroup.controls.template_files_inherited.setValue(false) + this.systemFormGroup.controls.template_files.setValue(this.system.template_files) + } + if (typeof this.system.autoinstall_meta === "string") { + this.systemFormGroup.controls.autoinstall_meta_inherited.setValue(true) + } else { + this.systemFormGroup.controls.autoinstall_meta_inherited.setValue(false) + this.systemFormGroup.controls.autoinstall_meta.setValue(this.system.autoinstall_meta) + } + }, error => { + // HTML encode the error message since it originates from XML + this._snackBar.open(this.toHTML(error.message), 'Close'); + }); + } + + removeSystem(): void { + this.cobblerApiService.remove_system(this.name, this.userService.token, false).subscribe(value => { + if (value) { + this.router.navigate(["/items", "system"]) + } + // HTML encode the error message since it originates from XML + this._snackBar.open("Delete failed! Check server logs for more information.", 'Close'); + }, error => { + // HTML encode the error message since it originates from XML + this._snackBar.open(this.toHTML(error.message), 'Close'); + }) + } + + editSystem(): void { + // TODO + this._snackBar.open("Not implemented at the moment!", "Close") + } + + copySystem(): void { + this.cobblerApiService.copy_system("", "", this.userService.token) + .subscribe(value => { + // TODO + }, error => { + // HTML encode the error message since it originates from XML + this._snackBar.open(this.toHTML(error.message), 'Close'); + }) + } + + saveSystem(): void { + // TODO + } + + get systemOwners(): string[] { + if (this.system && this.system.owners) { + const ownersResult = this.system.owners + if (typeof ownersResult !== 'string') { + return ownersResult; + } + } + return [] + } + + get systemAutoinstallMeta(): object { + if (this.system && this.system.autoinstall_meta) { + const autoinstallMetaResult = this.system.autoinstall_meta + if (typeof autoinstallMetaResult !== 'string') { + return autoinstallMetaResult + } + } + return {} + } + + get systemKernelOptions(): object { + if (this.system && this.system.boot_files) { + const kernelOptionsResult = this.system.boot_files + if (typeof kernelOptionsResult !== 'string') { + return kernelOptionsResult + } + } + return {} + } + + get systemKernelOptionsPost(): object { + if (this.system && this.system.boot_files) { + const kernelOptionsPost = this.system.boot_files + if (typeof kernelOptionsPost !== 'string') { + return kernelOptionsPost + } + } + return {} + } + + + get systemBootFiles(): object { + if (this.system && this.system.boot_files) { + const bootFilesResult = this.system.boot_files + if (typeof bootFilesResult !== 'string') { + return bootFilesResult + } + } + return {} + } + + get systemFetchableFiles(): object { + if (this.system && this.system.fetchable_files) { + const fetchableFilesResult = this.system.fetchable_files + if (typeof fetchableFilesResult !== 'string') { + return fetchableFilesResult + } + } + return {} + } + + get systemMgmtParameters(): object { + if (this.system && this.system.mgmt_parameters) { + const mgmtParametersResult = this.system.mgmt_parameters + if (typeof mgmtParametersResult !== 'string') { + return mgmtParametersResult + } + } + return {} + } + + get systemTemplateFiles(): object { + if (this.system && this.system.template_files) { + const templateFilesResult = this.system.template_files + if (typeof templateFilesResult !== 'string') { + return templateFilesResult + } + } + return {} + } + + toHTML(input: string): any { + // FIXME: Deduplicate method + return new DOMParser().parseFromString(input, 'text/html').documentElement.textContent; + } +} diff --git a/projects/cobbler-frontend/src/app/items/system/overview/system-overview.component.html b/projects/cobbler-frontend/src/app/items/system/overview/system-overview.component.html new file mode 100644 index 00000000..7975fcfd --- /dev/null +++ b/projects/cobbler-frontend/src/app/items/system/overview/system-overview.component.html @@ -0,0 +1,46 @@ +

SYSTEMS

+ + + + + + + + + + + + + + + + + + + + + + + + + + + +
Name{{element.name}}Profile{{element.profile}}Image{{element.image}} + + + + + + +
+ diff --git a/projects/cobbler-frontend/src/app/items/system/overview/system-overview.component.scss b/projects/cobbler-frontend/src/app/items/system/overview/system-overview.component.scss new file mode 100644 index 00000000..e69de29b diff --git a/projects/cobbler-frontend/src/app/items/system/overview/system-overview.component.spec.ts b/projects/cobbler-frontend/src/app/items/system/overview/system-overview.component.spec.ts new file mode 100644 index 00000000..b4196d02 --- /dev/null +++ b/projects/cobbler-frontend/src/app/items/system/overview/system-overview.component.spec.ts @@ -0,0 +1,36 @@ +import {provideHttpClient} from '@angular/common/http'; +import {provideHttpClientTesting} from '@angular/common/http/testing'; +import { ComponentFixture, TestBed } from '@angular/core/testing'; +import {provideRouter} from '@angular/router'; +import {COBBLER_URL} from 'cobbler-api'; + +import { SystemOverviewComponent } from './system-overview.component'; + +describe('SystemOverviewComponent', () => { + let component: SystemOverviewComponent; + let fixture: ComponentFixture; + + beforeEach(async () => { + await TestBed.configureTestingModule({ + imports: [SystemOverviewComponent], + providers: [ + provideRouter([]), + provideHttpClient(), + provideHttpClientTesting(), + { + provide: COBBLER_URL, + useValue: new URL('http://localhost/cobbler_api') + }, + ] + }) + .compileComponents(); + + fixture = TestBed.createComponent(SystemOverviewComponent); + component = fixture.componentInstance; + fixture.detectChanges(); + }); + + it('should create', () => { + expect(component).toBeTruthy(); + }); +}); diff --git a/projects/cobbler-frontend/src/app/items/system/overview/system-overview.component.ts b/projects/cobbler-frontend/src/app/items/system/overview/system-overview.component.ts new file mode 100644 index 00000000..6fc90b92 --- /dev/null +++ b/projects/cobbler-frontend/src/app/items/system/overview/system-overview.component.ts @@ -0,0 +1,90 @@ +import {Component, OnInit, ViewChild} from '@angular/core'; +import {MatIconButton} from '@angular/material/button'; +import {MatIcon} from '@angular/material/icon'; +import {MatMenu, MatMenuItem, MatMenuTrigger} from '@angular/material/menu'; +import {MatSnackBar} from '@angular/material/snack-bar'; +import { + MatCell, + MatCellDef, + MatColumnDef, + MatHeaderCell, MatHeaderCellDef, + MatHeaderRow, + MatHeaderRowDef, + MatRow, MatRowDef, MatTable +} from '@angular/material/table'; +import {Router} from '@angular/router'; +import {CobblerApiService, System} from 'cobbler-api'; +import {UserService} from '../../../services/user.service'; + +@Component({ + selector: 'cobbler-overview', + standalone: true, + imports: [ + MatCell, + MatCellDef, + MatColumnDef, + MatHeaderCell, + MatHeaderRow, + MatHeaderRowDef, + MatIcon, + MatIconButton, + MatMenu, + MatMenuItem, + MatRow, + MatRowDef, + MatTable, + MatHeaderCellDef, + MatMenuTrigger + ], + templateUrl: './system-overview.component.html', + styleUrl: './system-overview.component.scss' +}) +export class SystemOverviewComponent implements OnInit{ + displayedColumns: string[] = ['name', "profile", "image", "actions"]; + dataSource: Array = []; + + @ViewChild(MatTable) table: MatTable; + + constructor( + public userService: UserService, + private cobblerApiService: CobblerApiService, + private _snackBar: MatSnackBar, + private router: Router, + ) { + } + + ngOnInit(): void { + this.retrieveSystems() + } + + private retrieveSystems(): void { + this.cobblerApiService.get_systems().subscribe(value => { + this.dataSource = value + }, error => { + // HTML encode the error message since it originates from XML + this._snackBar.open(this.toHTML(error.message), 'Close'); + }) + } + + showSystem(uid: string, name: string): void { + this.router.navigate(["/items", "system", name]) + } + + editSystem(uid: string, name: string): void { + // TODO + } + + deleteSystem(uid: string, name: string): void { + this.cobblerApiService.remove_system(name, this.userService.token, false).subscribe(value => { + this.retrieveSystems() + }, error => { + // HTML encode the error message since it originates from XML + this._snackBar.open(this.toHTML(error.message), 'Close'); + }) + } + + toHTML(input: string): any { + // FIXME: Deduplicate method + return new DOMParser().parseFromString(input, 'text/html').documentElement.textContent; + } +} diff --git a/projects/cobbler-frontend/src/app/items/systems/systems.component.html b/projects/cobbler-frontend/src/app/items/systems/systems.component.html deleted file mode 100644 index 1848f64a..00000000 --- a/projects/cobbler-frontend/src/app/items/systems/systems.component.html +++ /dev/null @@ -1,26 +0,0 @@ -
-
- -

SYSTEMS DATA

-
- - -
-
- @for(item of data;track item){ -
- - {{ item[0] }} - - -
- } -
-
-
diff --git a/projects/cobbler-frontend/src/app/items/systems/systems.component.spec.js b/projects/cobbler-frontend/src/app/items/systems/systems.component.spec.js deleted file mode 100644 index 0c0e7565..00000000 --- a/projects/cobbler-frontend/src/app/items/systems/systems.component.spec.js +++ /dev/null @@ -1,66 +0,0 @@ -"use strict"; -var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { - function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } - return new (P || (P = Promise))(function (resolve, reject) { - function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } - function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } - function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } - step((generator = generator.apply(thisArg, _arguments || [])).next()); - }); -}; -var __generator = (this && this.__generator) || function (thisArg, body) { - var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g; - return g = { next: verb(0), "throw": verb(1), "return": verb(2) }, typeof Symbol === "function" && (g[Symbol.iterator] = function() { return this; }), g; - function verb(n) { return function (v) { return step([n, v]); }; } - function step(op) { - if (f) throw new TypeError("Generator is already executing."); - while (_) try { - if (f = 1, y && (t = op[0] & 2 ? y["return"] : op[0] ? y["throw"] || ((t = y["return"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t; - if (y = 0, t) op = [op[0] & 2, t.value]; - switch (op[0]) { - case 0: case 1: t = op; break; - case 4: _.label++; return { value: op[1], done: false }; - case 5: _.label++; y = op[1]; op = [0]; continue; - case 7: op = _.ops.pop(); _.trys.pop(); continue; - default: - if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; } - if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; } - if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; } - if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; } - if (t[2]) _.ops.pop(); - _.trys.pop(); continue; - } - op = body.call(thisArg, _); - } catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; } - if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true }; - } -}; -Object.defineProperty(exports, "__esModule", { value: true }); -var testing_1 = require("@angular/core/testing"); -var systems_component_1 = require("./systems.component"); -describe('SystemsComponent', function () { - var component; - var fixture; - beforeEach(function () { return __awaiter(void 0, void 0, void 0, function () { - return __generator(this, function (_a) { - switch (_a.label) { - case 0: return [4 /*yield*/, testing_1.TestBed.configureTestingModule({ - declarations: [systems_component_1.SystemsComponent] - }) - .compileComponents()]; - case 1: - _a.sent(); - return [2 /*return*/]; - } - }); - }); }); - beforeEach(function () { - fixture = testing_1.TestBed.createComponent(systems_component_1.SystemsComponent); - component = fixture.componentInstance; - fixture.detectChanges(); - }); - it('should create', function () { - expect(component).toBeTruthy(); - }); -}); -//# sourceMappingURL=systems.component.spec.js.map \ No newline at end of file diff --git a/projects/cobbler-frontend/src/app/items/systems/systems.component.spec.js.map b/projects/cobbler-frontend/src/app/items/systems/systems.component.spec.js.map deleted file mode 100644 index ae6bb290..00000000 --- a/projects/cobbler-frontend/src/app/items/systems/systems.component.spec.js.map +++ /dev/null @@ -1 +0,0 @@ -{"version":3,"file":"systems.component.spec.js","sourceRoot":"","sources":["systems.component.spec.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA,iDAAkE;AAElE,yDAAuD;AAEvD,QAAQ,CAAC,kBAAkB,EAAE;IAC3B,IAAI,SAA2B,CAAC;IAChC,IAAI,OAA2C,CAAC;IAEhD,UAAU,CAAC;;;wBACT,qBAAM,iBAAO,CAAC,sBAAsB,CAAC;wBACnC,YAAY,EAAE,CAAE,oCAAgB,CAAE;qBACnC,CAAC;yBACD,iBAAiB,EAAE,EAAA;;oBAHpB,SAGoB,CAAC;;;;SACtB,CAAC,CAAC;IAEH,UAAU,CAAC;QACT,OAAO,GAAG,iBAAO,CAAC,eAAe,CAAC,oCAAgB,CAAC,CAAC;QACpD,SAAS,GAAG,OAAO,CAAC,iBAAiB,CAAC;QACtC,OAAO,CAAC,aAAa,EAAE,CAAC;IAC1B,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,eAAe,EAAE;QAClB,MAAM,CAAC,SAAS,CAAC,CAAC,UAAU,EAAE,CAAC;IACjC,CAAC,CAAC,CAAC;AACL,CAAC,CAAC,CAAC"} \ No newline at end of file diff --git a/projects/cobbler-frontend/src/app/items/systems/systems.component.spec.ts b/projects/cobbler-frontend/src/app/items/systems/systems.component.spec.ts deleted file mode 100644 index 3c2ced52..00000000 --- a/projects/cobbler-frontend/src/app/items/systems/systems.component.spec.ts +++ /dev/null @@ -1,40 +0,0 @@ -import { ComponentFixture, TestBed } from '@angular/core/testing'; -import {MatButtonModule} from '@angular/material/button'; -import {MatFormFieldModule} from '@angular/material/form-field'; -import {MatInputModule} from '@angular/material/input'; -import {NoopAnimationsModule} from '@angular/platform-browser/animations'; -import {provideRouter} from '@angular/router'; - -import { SystemsComponent } from './systems.component'; - - -describe('SystemsComponent', () => { - let component: SystemsComponent; - let fixture: ComponentFixture; - - beforeEach(async () => { - await TestBed.configureTestingModule({ - imports: [ - SystemsComponent, - MatButtonModule, - MatFormFieldModule, - MatInputModule, - NoopAnimationsModule - ], - providers: [ - provideRouter([]), - ] - }) - .compileComponents(); - }); - - beforeEach(() => { - fixture = TestBed.createComponent(SystemsComponent); - component = fixture.componentInstance; - fixture.detectChanges(); - }); - - it('should create', () => { - expect(component).toBeTruthy(); - }); -}); diff --git a/projects/cobbler-frontend/src/app/items/systems/systems.component.ts b/projects/cobbler-frontend/src/app/items/systems/systems.component.ts deleted file mode 100644 index 3f1f7d1f..00000000 --- a/projects/cobbler-frontend/src/app/items/systems/systems.component.ts +++ /dev/null @@ -1,27 +0,0 @@ -import {Component} from '@angular/core'; -import {AppSystemsService} from '../../services/app-systems.service'; -import { RouterOutlet } from '@angular/router'; -import {MatButtonModule} from "@angular/material/button"; -import {MatFormFieldModule} from "@angular/material/form-field"; -import {MatInputModule} from "@angular/material/input"; - -@Component({ - selector: 'cobbler-systems', - templateUrl: './systems.component.html', - styleUrls: ['./systems.component.css'], - standalone: true, - imports: [ - RouterOutlet, - MatFormFieldModule, - MatButtonModule, - MatInputModule, - ], -}) -export class SystemsComponent { - data = []; - - constructor(service: AppSystemsService) { - this.data = service.getAll(); - } - -} diff --git a/projects/cobbler-frontend/src/app/items/template/edit/template-edit.component.html b/projects/cobbler-frontend/src/app/items/template/edit/template-edit.component.html new file mode 100644 index 00000000..d981e4a5 --- /dev/null +++ b/projects/cobbler-frontend/src/app/items/template/edit/template-edit.component.html @@ -0,0 +1,44 @@ +
+
+

Name: {{ name }}

+ + + + + + + + + + + + +
+
+ +
+ + Template Content + + + @if (isEditMode) { + + } +
+ diff --git a/projects/cobbler-frontend/src/app/items/template/edit/template-edit.component.scss b/projects/cobbler-frontend/src/app/items/template/edit/template-edit.component.scss new file mode 100644 index 00000000..2a9efa5d --- /dev/null +++ b/projects/cobbler-frontend/src/app/items/template/edit/template-edit.component.scss @@ -0,0 +1,30 @@ +.title-table { + display: table; + width: 100%; +} + +.title-row { + display: table-cell; + width: 100%; +} + +.title-cell-text { + display: table-cell; + width: 100%; + vertical-align: middle; +} + +.title-cell-button { + display: table-cell; +} + +.form-replicate { + min-width: 150px; + max-width: 600px; + width: 100%; +} + +.form-field-full-width { + width: 100%; +} + diff --git a/projects/cobbler-frontend/src/app/items/template/edit/template-edit.component.spec.ts b/projects/cobbler-frontend/src/app/items/template/edit/template-edit.component.spec.ts new file mode 100644 index 00000000..8aa827e0 --- /dev/null +++ b/projects/cobbler-frontend/src/app/items/template/edit/template-edit.component.spec.ts @@ -0,0 +1,50 @@ +import {provideHttpClient} from '@angular/common/http'; +import {provideHttpClientTesting} from '@angular/common/http/testing'; +import { ComponentFixture, TestBed } from '@angular/core/testing'; +import {NoopAnimationsModule} from '@angular/platform-browser/animations'; +import {ActivatedRoute, provideRouter} from '@angular/router'; +import {COBBLER_URL} from 'cobbler-api'; + +import { TemplateEditComponent } from './template-edit.component'; + +describe('TemplateEditComponent', () => { + let component: TemplateEditComponent; + let fixture: ComponentFixture; + + beforeEach(async () => { + await TestBed.configureTestingModule({ + imports: [ + TemplateEditComponent, + NoopAnimationsModule, + ], + providers: [ + provideRouter([]), + provideHttpClient(), + provideHttpClientTesting(), + { + provide: COBBLER_URL, + useValue: new URL('http://localhost/cobbler_api') + }, + { + provide: ActivatedRoute, + useValue: { + snapshot: { + paramMap: { + get: () => "testtemplate" + }, + }, + }, + }, + ] + }) + .compileComponents(); + + fixture = TestBed.createComponent(TemplateEditComponent); + component = fixture.componentInstance; + fixture.detectChanges(); + }); + + it('should create', () => { + expect(component).toBeTruthy(); + }); +}); diff --git a/projects/cobbler-frontend/src/app/items/template/edit/template-edit.component.ts b/projects/cobbler-frontend/src/app/items/template/edit/template-edit.component.ts new file mode 100644 index 00000000..7b612d90 --- /dev/null +++ b/projects/cobbler-frontend/src/app/items/template/edit/template-edit.component.ts @@ -0,0 +1,106 @@ +import {Component, inject, OnInit} from '@angular/core'; +import {FormBuilder, FormControl, FormsModule, ReactiveFormsModule} from '@angular/forms'; +import {MatOption} from '@angular/material/autocomplete'; +import {MatButton, MatIconButton} from '@angular/material/button'; +import {MatCheckbox} from '@angular/material/checkbox'; +import {MatFormField, MatLabel} from '@angular/material/form-field'; +import {MatIcon} from '@angular/material/icon'; +import {MatInput} from '@angular/material/input'; +import {MatSelect} from '@angular/material/select'; +import {MatSnackBar} from '@angular/material/snack-bar'; +import {MatTooltip} from '@angular/material/tooltip'; +import {ActivatedRoute, Router} from '@angular/router'; +import {CobblerApiService, Profile} from 'cobbler-api'; +import {UserService} from '../../../services/user.service'; + +@Component({ + selector: 'cobbler-edit', + standalone: true, + imports: [ + FormsModule, + MatButton, + MatCheckbox, + MatFormField, + MatIcon, + MatIconButton, + MatInput, + MatLabel, + MatOption, + MatSelect, + MatTooltip, + ReactiveFormsModule + ], + templateUrl: './template-edit.component.html', + styleUrl: './template-edit.component.scss' +}) +export class TemplateEditComponent implements OnInit { + name: string; + content: string; + private readonly _formBuilder = inject(FormBuilder); + templateFormGroup = this._formBuilder.group({ + content: new FormControl({value: "", disabled: true}), + }); + isEditMode: boolean = false; + + constructor( + private route: ActivatedRoute, + private userService: UserService, + private cobblerApiService: CobblerApiService, + private _snackBar: MatSnackBar, + private router: Router, + ) { + this.name = this.route.snapshot.paramMap.get("name"); + } + + ngOnInit(): void { + this.refreshData() + } + + refreshData(): void { + this.cobblerApiService.read_autoinstall_template(this.name, this.userService.token).subscribe(value => { + this.content = value; + this.templateFormGroup.controls.content.setValue(this.toHTML(this.content)); + }, error => { + // HTML encode the error message since it originates from XML + this._snackBar.open(this.toHTML(error.message), 'Close'); + }); + } + + removeTemplate(): void { + this.cobblerApiService.remove_autoinstall_template(this.name, this.userService.token).subscribe(value => { + if (value) { + this.router.navigate(["/items", "template"]) + } + // HTML encode the error message since it originates from XML + this._snackBar.open("Delete failed! Check server logs for more information.", 'Close'); + }, error => { + // HTML encode the error message since it originates from XML + this._snackBar.open(this.toHTML(error.message), 'Close'); + }) + } + + editTemplate(): void { + // TODO + this._snackBar.open("Not implemented at the moment!", "Close") + } + + copyTemplate(): void { + // TODO + this._snackBar.open("Not implemented at the moment!", "Close") + } + + saveTemplate(): void { + // TODO + this.cobblerApiService.write_autoinstall_template(this.name, "", this.userService.token).subscribe(value => { + // TODO + }, error => { + // HTML encode the error message since it originates from XML + this._snackBar.open(this.toHTML(error.message), 'Close'); + }) + } + + toHTML(input: string): any { + // FIXME: Deduplicate method + return new DOMParser().parseFromString(input, 'text/html').documentElement.textContent; + } +} diff --git a/projects/cobbler-frontend/src/app/items/template/overview/template-overview.component.html b/projects/cobbler-frontend/src/app/items/template/overview/template-overview.component.html new file mode 100644 index 00000000..42bd3c82 --- /dev/null +++ b/projects/cobbler-frontend/src/app/items/template/overview/template-overview.component.html @@ -0,0 +1,34 @@ +

TEMPLATES

+ + + + + + + + + + + + + + + +
Name{{element}} + + + + + + +
+ diff --git a/projects/cobbler-frontend/src/app/items/template/overview/template-overview.component.scss b/projects/cobbler-frontend/src/app/items/template/overview/template-overview.component.scss new file mode 100644 index 00000000..e69de29b diff --git a/projects/cobbler-frontend/src/app/items/template/overview/template-overview.component.spec.ts b/projects/cobbler-frontend/src/app/items/template/overview/template-overview.component.spec.ts new file mode 100644 index 00000000..452128e3 --- /dev/null +++ b/projects/cobbler-frontend/src/app/items/template/overview/template-overview.component.spec.ts @@ -0,0 +1,36 @@ +import {provideHttpClient} from '@angular/common/http'; +import {provideHttpClientTesting} from '@angular/common/http/testing'; +import { ComponentFixture, TestBed } from '@angular/core/testing'; +import {provideRouter} from '@angular/router'; +import {COBBLER_URL} from 'cobbler-api'; + +import { TemplateOverviewComponent } from './template-overview.component'; + +describe('TemplateOverviewComponent', () => { + let component: TemplateOverviewComponent; + let fixture: ComponentFixture; + + beforeEach(async () => { + await TestBed.configureTestingModule({ + imports: [TemplateOverviewComponent], + providers: [ + provideRouter([]), + provideHttpClient(), + provideHttpClientTesting(), + { + provide: COBBLER_URL, + useValue: new URL('http://localhost/cobbler_api') + }, + ] + }) + .compileComponents(); + + fixture = TestBed.createComponent(TemplateOverviewComponent); + component = fixture.componentInstance; + fixture.detectChanges(); + }); + + it('should create', () => { + expect(component).toBeTruthy(); + }); +}); diff --git a/projects/cobbler-frontend/src/app/items/template/overview/template-overview.component.ts b/projects/cobbler-frontend/src/app/items/template/overview/template-overview.component.ts new file mode 100644 index 00000000..517ab9ba --- /dev/null +++ b/projects/cobbler-frontend/src/app/items/template/overview/template-overview.component.ts @@ -0,0 +1,90 @@ +import {Component, OnInit, ViewChild} from '@angular/core'; +import {MatIconButton} from '@angular/material/button'; +import {MatIcon} from '@angular/material/icon'; +import {MatMenu, MatMenuItem, MatMenuTrigger} from '@angular/material/menu'; +import {MatSnackBar} from '@angular/material/snack-bar'; +import { + MatCell, + MatCellDef, + MatColumnDef, + MatHeaderCell, MatHeaderCellDef, + MatHeaderRow, + MatHeaderRowDef, + MatRow, MatRowDef, MatTable +} from '@angular/material/table'; +import {Router} from '@angular/router'; +import {CobblerApiService} from 'cobbler-api'; +import {UserService} from '../../../services/user.service'; + +@Component({ + selector: 'cobbler-overview', + standalone: true, + imports: [ + MatCell, + MatCellDef, + MatColumnDef, + MatHeaderCell, + MatHeaderRow, + MatHeaderRowDef, + MatIcon, + MatIconButton, + MatMenu, + MatMenuItem, + MatRow, + MatRowDef, + MatTable, + MatHeaderCellDef, + MatMenuTrigger + ], + templateUrl: './template-overview.component.html', + styleUrl: './template-overview.component.scss' +}) +export class TemplateOverviewComponent implements OnInit { + displayedColumns: string[] = ['name', "actions"]; + dataSource: Array = []; + + @ViewChild(MatTable) table: MatTable; + + constructor( + public userService: UserService, + private cobblerApiService: CobblerApiService, + private _snackBar: MatSnackBar, + private router: Router, + ) { + } + + ngOnInit(): void { + this.retrieveDistros() + } + + private retrieveDistros(): void { + this.cobblerApiService.get_autoinstall_templates(this.userService.token).subscribe(value => { + this.dataSource = value + }, error => { + // HTML encode the error message since it originates from XML + this._snackBar.open(this.toHTML(error.message), 'Close'); + }) + } + + showTemplate(name: string): void { + this.router.navigate(["/items", "template", name]) + } + + editTemplate(name: string): void { + // TODO + } + + deleteTemplate(name: string): void { + this.cobblerApiService.remove_autoinstall_template(name, this.userService.token).subscribe(value => { + this.retrieveDistros() + }, error => { + // HTML encode the error message since it originates from XML + this._snackBar.open(this.toHTML(error.message), 'Close'); + }) + } + + toHTML(input: string): any { + // FIXME: Deduplicate method + return new DOMParser().parseFromString(input, 'text/html').documentElement.textContent; + } +} diff --git a/projects/cobbler-frontend/src/app/items/templates/templates.component.html b/projects/cobbler-frontend/src/app/items/templates/templates.component.html deleted file mode 100644 index 81e6c22f..00000000 --- a/projects/cobbler-frontend/src/app/items/templates/templates.component.html +++ /dev/null @@ -1,13 +0,0 @@ -
-
- -

TEMPLATES

-
- - data 01 - data 02 - data 03 - -
-
-
diff --git a/projects/cobbler-frontend/src/app/items/templates/templates.component.spec.ts b/projects/cobbler-frontend/src/app/items/templates/templates.component.spec.ts deleted file mode 100644 index d14120e8..00000000 --- a/projects/cobbler-frontend/src/app/items/templates/templates.component.spec.ts +++ /dev/null @@ -1,30 +0,0 @@ -import { ComponentFixture, TestBed } from '@angular/core/testing'; -import { MatListModule } from '@angular/material/list'; -import {provideRouter} from '@angular/router'; - -import { TemplatesComponent } from './templates.component'; - - -describe('AppTemplatesComponent', () => { - let component: TemplatesComponent; - let fixture: ComponentFixture; - - beforeEach(async () => { - await TestBed.configureTestingModule({ - imports: [MatListModule, TemplatesComponent], - providers: [ - provideRouter([]), - ] - }).compileComponents(); - }); - - beforeEach(() => { - fixture = TestBed.createComponent(TemplatesComponent); - component = fixture.componentInstance; - fixture.detectChanges(); - }); - - it('should create', () => { - expect(component).toBeTruthy(); - }); -}); diff --git a/projects/cobbler-frontend/src/app/items/templates/templates.component.ts b/projects/cobbler-frontend/src/app/items/templates/templates.component.ts deleted file mode 100644 index 645f0c31..00000000 --- a/projects/cobbler-frontend/src/app/items/templates/templates.component.ts +++ /dev/null @@ -1,17 +0,0 @@ -import {Component} from '@angular/core'; -import { MatListModule } from '@angular/material/list'; -import { RouterOutlet } from '@angular/router'; - -@Component({ - selector: 'cobbler-templates', - templateUrl: './templates.component.html', - styleUrls: ['./templates.component.css'], - standalone: true, - imports: [RouterOutlet, MatListModule], -}) -export class TemplatesComponent { - - constructor() { - } - -} diff --git a/projects/cobbler-frontend/src/app/manage-menu/manage-menu.component.html b/projects/cobbler-frontend/src/app/manage-menu/manage-menu.component.html index 5f809ce8..94d994c7 100644 --- a/projects/cobbler-frontend/src/app/manage-menu/manage-menu.component.html +++ b/projects/cobbler-frontend/src/app/manage-menu/manage-menu.component.html @@ -12,7 +12,7 @@

Configuration

mat-list-item class="nav-link" aria-current="page" - [routerLink]="['/distros']" + [routerLink]="['/items', 'distro']" [routerLinkActive]="'is-active'" > » @@ -22,7 +22,7 @@

Configuration

mat-list-item class="nav-link" aria-current="page" - [routerLink]="['/profiles']" + [routerLink]="['/items', 'profile']" [routerLinkActive]="'is-active'" > » @@ -32,7 +32,7 @@

Configuration

mat-list-item class="nav-link" aria-current="page" - [routerLink]="['/systems']" + [routerLink]="['/items', 'system']" [routerLinkActive]="'is-active'" > » @@ -42,7 +42,7 @@

Configuration

mat-list-item class="nav-link" aria-current="page" - [routerLink]="['/repos']" + [routerLink]="['/items', 'repository']" [routerLinkActive]="'is-active'" > » @@ -52,7 +52,7 @@

Configuration

mat-list-item class="nav-link" aria-current="page" - [routerLink]="['/images']" + [routerLink]="['/items', 'image']" [routerLinkActive]="'is-active'" > » @@ -62,7 +62,7 @@

Configuration

mat-list-item class="nav-link" aria-current="page" - [routerLink]="['/templates']" + [routerLink]="['/items', 'template']" [routerLinkActive]="'is-active'" > » @@ -72,7 +72,7 @@

Configuration

mat-list-item class="nav-link" aria-current="page" - [routerLink]="['/snippets']" + [routerLink]="['/items', 'snippet']" [routerLinkActive]="'is-active'" > » @@ -82,7 +82,7 @@

Configuration

mat-list-item class="nav-link" aria-current="page" - [routerLink]="['/management-classes']" + [routerLink]="['/items', 'management-class']" [routerLinkActive]="'is-active'" > » @@ -103,7 +103,7 @@

Resources

@@ -112,7 +112,7 @@

Resources

diff --git a/projects/cobbler-frontend/src/app/services/app-systems.service.spec.js b/projects/cobbler-frontend/src/app/services/app-systems.service.spec.js deleted file mode 100644 index aef8c243..00000000 --- a/projects/cobbler-frontend/src/app/services/app-systems.service.spec.js +++ /dev/null @@ -1,15 +0,0 @@ -"use strict"; -Object.defineProperty(exports, "__esModule", { value: true }); -var testing_1 = require("@angular/core/testing"); -var app_systems_service_1 = require("./app-systems.service"); -describe('AppSystemsService', function () { - var service; - beforeEach(function () { - testing_1.TestBed.configureTestingModule({}); - service = testing_1.TestBed.inject(app_systems_service_1.AppSystemsService); - }); - it('should be created', function () { - expect(service).toBeTruthy(); - }); -}); -//# sourceMappingURL=app-systems.service.spec.js.map \ No newline at end of file diff --git a/projects/cobbler-frontend/src/app/services/app-systems.service.spec.js.map b/projects/cobbler-frontend/src/app/services/app-systems.service.spec.js.map deleted file mode 100644 index b131b5b3..00000000 --- a/projects/cobbler-frontend/src/app/services/app-systems.service.spec.js.map +++ /dev/null @@ -1 +0,0 @@ -{"version":3,"file":"app-systems.service.spec.js","sourceRoot":"","sources":["app-systems.service.spec.ts"],"names":[],"mappings":";;AAAA,iDAAgD;AAEhD,6DAA0D;AAE1D,QAAQ,CAAC,mBAAmB,EAAE;IAC5B,IAAI,OAA0B,CAAC;IAE/B,UAAU,CAAC;QACT,iBAAO,CAAC,sBAAsB,CAAC,EAAE,CAAC,CAAC;QACnC,OAAO,GAAG,iBAAO,CAAC,MAAM,CAAC,uCAAiB,CAAC,CAAC;IAC9C,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,mBAAmB,EAAE;QACtB,MAAM,CAAC,OAAO,CAAC,CAAC,UAAU,EAAE,CAAC;IAC/B,CAAC,CAAC,CAAC;AACL,CAAC,CAAC,CAAC"} \ No newline at end of file diff --git a/projects/cobbler-frontend/src/app/services/app-systems.service.spec.ts b/projects/cobbler-frontend/src/app/services/app-systems.service.spec.ts deleted file mode 100644 index 69210403..00000000 --- a/projects/cobbler-frontend/src/app/services/app-systems.service.spec.ts +++ /dev/null @@ -1,16 +0,0 @@ -import { TestBed } from '@angular/core/testing'; - -import { AppSystemsService } from './app-systems.service'; - -describe('AppSystemsService', () => { - let service: AppSystemsService; - - beforeEach(() => { - TestBed.configureTestingModule({}); - service = TestBed.inject(AppSystemsService); - }); - - it('should be created', () => { - expect(service).toBeTruthy(); - }); -}); diff --git a/projects/cobbler-frontend/src/app/services/app-systems.service.ts b/projects/cobbler-frontend/src/app/services/app-systems.service.ts deleted file mode 100644 index f721a021..00000000 --- a/projects/cobbler-frontend/src/app/services/app-systems.service.ts +++ /dev/null @@ -1,77 +0,0 @@ -import {Injectable} from '@angular/core'; - -@Injectable({ - providedIn: 'root' -}) -export class AppSystemsService { - - mockdata = [ - ['autoinstall', '<>', 0, 'Automatic Installation Template', true, - 'Path to automatic installation template', 0, 'str'], - ['autoinstall_meta', {}, 0, 'Automatic Installation Template Metadata', true, 'Ex: dog=fang agent=86', 0, 'dict'], - ['boot_files', {}, '<>', 'TFTP Boot Files', true, 'Files copied into tftpboot beyond the kernel/initrd', - 0, 'list'], - ['boot_loader', '<>', 0, 'Boot loader', true, 'Linux installation boot loader', - 'utils.get_supported_system_boot_loaders()', 'str'], - ['comment', '', 0, 'Comment', true, 'Free form text description', 0, 'str'], - ['enable_gpxe', '<>', 0, 'Enable gPXE?', true, 'Use gPXE instead of PXELINUX for advanced booting options', - 0, 'bool'], - ['fetchable_files', {}, '<>', 'Fetchable Files', true, 'Templates for tftp or wget/curl', 0, 'dict'], - ['gateway', '', 0, 'Gateway', true, '', 0, 'str'], - ['hostname', '', 0, 'Hostname', true, '', 0, 'str'], - ['image', 'None', 0, 'Image', true, 'Parent image (if not a profile)', 0, 'str'], - ['ipv6_default_device', '', 0, 'IPv6 Default Device', true, '', 0, 'str'], - ['kernel_options', {}, 0, 'Kernel Options', true, 'Ex: selinux=permissive', 0, 'dict'], - ['kernel_options_post', {}, 0, 'Kernel Options (Post Install)', true, 'Ex: clocksource=pit noapic', 0, 'dict'], - ['mgmt_classes', '<>', 0, 'Management Classes', true, 'For external config management', 0, 'list'], - ['mgmt_parameters', '<>', 0, 'Management Parameters', true, - 'Parameters which will be handed to your management application (Must be valid YAML dictionary)', 0, 'str'], - ['name', '', 0, 'Name', true, 'Ex: vanhalen.example.org', 0, 'str'], - ['name_servers', [], 0, 'Name Servers', true, 'space delimited', 0, 'list'], - ['name_servers_search', [], 0, 'Name Servers Search Path', true, 'space delimited', 0, 'list'], - ['netboot_enabled', true, 0, 'Netboot Enabled', true, 'PXE (re)install this machine at next boot?', 0, 'bool'], - ['next_server', '<>', 0, 'Next Server Override', true, 'See manpage or leave blank', 0, 'str'], - ['filename', '<>', '<>', 'DHCP Filename Override', true, 'Use to boot non-default bootloaders', - 0, 'str'], - ['owners', '<>', 0, 'Owners', true, 'Owners list for authz_ownership (space delimited)', 0, 'list'], - ['power_address', '', 0, 'Power Management Address', true, 'Ex: power-device.example.org', 0, 'str'], - ['power_id', '', 0, 'Power Management ID', true, 'Usually a plug number or blade name, if power type requires it', - 0, 'str'], - ['power_pass', '', 0, 'Power Management Password', true, '', 0, 'str'], - ['power_type', 'SETTINGS:power_management_default_type', 0, 'Power Management Type', true, - 'Power management script to use', 'power_manager.get_power_types()', 'str'], - ['power_user', '', 0, 'Power Management Username', true, '', 0, 'str'], - ['power_options', '', 0, 'Power Management Options', true, 'Additional options, to be passed to the fencing agent', - 0, 'str'], - ['power_identity_file', '', 0, 'Power Identity File', true, - 'Identity file to be passed to the fencing agent (ssh key)', 0, 'str'], - ['profile', 'None', 0, 'Profile', true, 'Parent profile', [], 'str'], - ['proxy', '<>', 0, 'Internal Proxy', true, 'Internal proxy URL', 0, 'str'], - ['redhat_management_key', '<>', 0, 'Redhat Management Key', true, - 'Registration key for RHN, Spacewalk, or Satellite', 0, 'str'], - ['server', '<>', 0, 'Server Override', true, 'See manpage or leave blank', 0, 'str'], - ['status', 'production', 0, 'Status', true, 'System status', ['', 'development', 'testing', 'acceptance', - 'production'], 'str'], - ['template_files', {}, 0, 'Template Files', true, 'File mappings for built-in configuration management', 0, 'dict'], - ['virt_auto_boot', '<>', 0, 'Virt Auto Boot', true, 'Auto boot this VM?', 0, 'bool'], - ['virt_cpus', '<>', 0, 'Virt CPUs', true, '', 0, 'int'], - ['virt_disk_driver', '<>', 0, 'Virt Disk Driver Type', true, - 'The on-disk format for the virtualization disk', 'validate.VIRT_DISK_DRIVERS', 'str'], - ['virt_file_size', '<>', 0, 'Virt File Size(GB)', true, '', 0, 'float'], - ['virt_path', '<>', 0, 'Virt Path', true, 'Ex: /directory or VolGroup00', 0, 'str'], - ['virt_pxe_boot', 0, 0, 'Virt PXE Boot', true, 'Use PXE to build this VM?', 0, 'bool'], - ['virt_ram', '<>', 0, 'Virt RAM (MB)', true, '', 0, 'int'], - ['virt_type', '<>', 0, 'Virt Type', true, 'Virtualization technology to use', 'validate.VIRT_TYPES', - 'str'], - ['serial_device', '', 0, 'Serial Device #', true, 'Serial Device Number', 0, 'int'], - ['serial_baud_rate', '', 0, 'Serial Baud Rate', true, 'Serial Baud Rate', - ['', '2400', '4800', '9600', '19200', '38400', '57600', '115200'], 'int'], - ]; - - constructor() { - } - - getAll(): Array { - return this.mockdata; - } -} diff --git a/projects/cobbler-frontend/src/app/services/data-distro.service.spec.js b/projects/cobbler-frontend/src/app/services/data-distro.service.spec.js deleted file mode 100644 index e5296cab..00000000 --- a/projects/cobbler-frontend/src/app/services/data-distro.service.spec.js +++ /dev/null @@ -1,15 +0,0 @@ -"use strict"; -Object.defineProperty(exports, "__esModule", { value: true }); -var testing_1 = require("@angular/core/testing"); -var data_distro_service_1 = require("./data-distro.service"); -describe('DataDistroService', function () { - var service; - beforeEach(function () { - testing_1.TestBed.configureTestingModule({}); - service = testing_1.TestBed.inject(data_distro_service_1.DataDistroService); - }); - it('should be created', function () { - expect(service).toBeTruthy(); - }); -}); -//# sourceMappingURL=data-distro.service.spec.js.map \ No newline at end of file diff --git a/projects/cobbler-frontend/src/app/services/data-distro.service.spec.js.map b/projects/cobbler-frontend/src/app/services/data-distro.service.spec.js.map deleted file mode 100644 index f1c3e316..00000000 --- a/projects/cobbler-frontend/src/app/services/data-distro.service.spec.js.map +++ /dev/null @@ -1 +0,0 @@ -{"version":3,"file":"data-distro.service.spec.js","sourceRoot":"","sources":["data-distro.service.spec.ts"],"names":[],"mappings":";;AAAA,iDAAgD;AAEhD,6DAA0D;AAE1D,QAAQ,CAAC,mBAAmB,EAAE;IAC5B,IAAI,OAA0B,CAAC;IAE/B,UAAU,CAAC;QACT,iBAAO,CAAC,sBAAsB,CAAC,EAAE,CAAC,CAAC;QACnC,OAAO,GAAG,iBAAO,CAAC,MAAM,CAAC,uCAAiB,CAAC,CAAC;IAC9C,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,mBAAmB,EAAE;QACtB,MAAM,CAAC,OAAO,CAAC,CAAC,UAAU,EAAE,CAAC;IAC/B,CAAC,CAAC,CAAC;AACL,CAAC,CAAC,CAAC"} \ No newline at end of file diff --git a/projects/cobbler-frontend/src/app/services/data-distro.service.spec.ts b/projects/cobbler-frontend/src/app/services/data-distro.service.spec.ts deleted file mode 100644 index 7e3a25aa..00000000 --- a/projects/cobbler-frontend/src/app/services/data-distro.service.spec.ts +++ /dev/null @@ -1,16 +0,0 @@ -import { TestBed } from '@angular/core/testing'; - -import { DataDistroService } from './data-distro.service'; - -describe('DataDistroService', () => { - let service: DataDistroService; - - beforeEach(() => { - TestBed.configureTestingModule({}); - service = TestBed.inject(DataDistroService); - }); - - it('should be created', () => { - expect(service).toBeTruthy(); - }); -}); diff --git a/projects/cobbler-frontend/src/app/services/data-distro.service.ts b/projects/cobbler-frontend/src/app/services/data-distro.service.ts deleted file mode 100644 index f8a3a23e..00000000 --- a/projects/cobbler-frontend/src/app/services/data-distro.service.ts +++ /dev/null @@ -1,63 +0,0 @@ -import { Injectable } from '@angular/core'; - -@Injectable({ - providedIn: 'root' -}) -export class DataDistroService { - // boolean True/False in python - // boolean true/false in typescript - // Changed function calls to strings for mockdata - // python 'None' => typescript 'null' - // shout names be shortened as keys, or kept descriptive? - // mockdata to be replace by the xmlrpc fetched data - canAccess: boolean; - mockdata = { - arch: ['arch', 'x86_64', 0, 'Architecture', true, 'Architecture', 'utils.get_valid_archs()', 'str'], - autoinstall: ['autoinstall_meta', {}, 0, 'Automatic Installation Template Metadata', true, 'Ex: dog=fang agent=86', - 0, 'dict'], - b_files: ['boot_files', {}, 0, 'TFTP Boot Files', true, 'Files copied into tftpboot beyond the kernel/initrd', 0, - 'list'], - b_loader: ['boot_loader', '<>', 0, 'Boot loader', true, 'Network installation boot loader', - 'utils.get_supported_system_boot_loaders()', 'str'], - breed: ['breed', 'redhat', 0, 'Breed', true, 'What is the type of distribution?', 'utils.get_valid_breeds()', 'str'], - comment: ['comment', '', 0, 'Comment', true, 'Free form text description', 0, 'str'], - f_files: ['fetchable_files', {}, 0, 'Fetchable Files', true, 'Templates for tftp or wget/curl', 0, 'list'], - initrd: ['initrd', null, 0, 'Initrd', true, 'Absolute path to kernel on filesystem', 0, 'str'], - kernel: ['kernel', null, 0, 'Kernel', true, 'Absolute path to kernel on filesystem', 0, 'str'], - rebo_initrd: ['remote_boot_initrd', null, 0, 'Remote Boot Initrd', true, - 'URL the bootloader directly retrieves and boots from', 0, 'str'], - rebo_kernel: ['remote_boot_kernel', null, 0, 'Remote Boot Kernel', true, - 'URL the bootloader directly retrieves and boots from', 0, 'str'], - kernel_options: ['kernel_options', {}, 0, 'Kernel Options', true, 'Ex: selinux=permissive', 0, 'dict'], - k_opt_post: ['kernel_options_post', {}, 0, 'Kernel Options (Post Install)', true, 'Ex: clocksource=pit noapic', 0, - 'dict'], - mng_class: ['mgmt_classes', [], 0, 'Management Classes', true, 'Management classes for external config management', - 0, 'list'], - name: ['name', '', 0, 'Name', true, 'Ex: Fedora-11-i386', 0, 'str'], - os_version: ['os_version', 'virtio26', 0, 'OS Version', true, 'Needed for some virtualization optimizations', - 'utils.get_valid_os_versions()', 'str'], - owners: ['owners', 'DEFAULT', 0, 'Owners', true, 'Owners list for authz_ownership (space delimited)', 0, 'list'], - rh_mng_key: ['redhat_management_key', '', '', 'Redhat Management Key', true, - 'Registration key for RHN, Spacewalk, or Satellite', 0, 'str'], - tmplt_files: ['template_files', {}, 0, 'Template Files', true, 'File mappings for built-in config management', 0, - 'dict'] - -}; - - constructor() { - // possibly add authentication subscription as seen in navbar.component.ts? - } - - // TODO: Specify return type properly - get_item(key: any): any { - // return list of data from mockdata - const data = this.mockdata[key]; - const faildata = ['none=name', 'none=extra data', 'none=num', 'none=Title', 'none=boolean', 'none=description', - 'none=num', 'none=type']; - // add type check for array ? - if (data !== null) { - return data; - } - return faildata; - } -} diff --git a/projects/cobbler-frontend/src/app/services/files.service.spec.js b/projects/cobbler-frontend/src/app/services/files.service.spec.js deleted file mode 100644 index 7f2d39ea..00000000 --- a/projects/cobbler-frontend/src/app/services/files.service.spec.js +++ /dev/null @@ -1,15 +0,0 @@ -"use strict"; -Object.defineProperty(exports, "__esModule", { value: true }); -var testing_1 = require("@angular/core/testing"); -var files_service_1 = require("./files.service"); -describe('FilesService', function () { - var service; - beforeEach(function () { - testing_1.TestBed.configureTestingModule({}); - service = testing_1.TestBed.inject(files_service_1.FilesService); - }); - it('should be created', function () { - expect(service).toBeTruthy(); - }); -}); -//# sourceMappingURL=files.service.spec.js.map \ No newline at end of file diff --git a/projects/cobbler-frontend/src/app/services/files.service.spec.js.map b/projects/cobbler-frontend/src/app/services/files.service.spec.js.map deleted file mode 100644 index 0b72cbee..00000000 --- a/projects/cobbler-frontend/src/app/services/files.service.spec.js.map +++ /dev/null @@ -1 +0,0 @@ -{"version":3,"file":"files.service.spec.js","sourceRoot":"","sources":["files.service.spec.ts"],"names":[],"mappings":";;AAAA,iDAAgD;AAEhD,iDAA+C;AAE/C,QAAQ,CAAC,cAAc,EAAE;IACvB,IAAI,OAAqB,CAAC;IAE1B,UAAU,CAAC;QACT,iBAAO,CAAC,sBAAsB,CAAC,EAAE,CAAC,CAAC;QACnC,OAAO,GAAG,iBAAO,CAAC,MAAM,CAAC,4BAAY,CAAC,CAAC;IACzC,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,mBAAmB,EAAE;QACtB,MAAM,CAAC,OAAO,CAAC,CAAC,UAAU,EAAE,CAAC;IAC/B,CAAC,CAAC,CAAC;AACL,CAAC,CAAC,CAAC"} \ No newline at end of file diff --git a/projects/cobbler-frontend/src/app/services/files.service.spec.ts b/projects/cobbler-frontend/src/app/services/files.service.spec.ts deleted file mode 100644 index 01acf0a3..00000000 --- a/projects/cobbler-frontend/src/app/services/files.service.spec.ts +++ /dev/null @@ -1,16 +0,0 @@ -import { TestBed } from '@angular/core/testing'; - -import { FilesService } from './files.service'; - -describe('FilesService', () => { - let service: FilesService; - - beforeEach(() => { - TestBed.configureTestingModule({}); - service = TestBed.inject(FilesService); - }); - - it('should be created', () => { - expect(service).toBeTruthy(); - }); -}); diff --git a/projects/cobbler-frontend/src/app/services/files.service.ts b/projects/cobbler-frontend/src/app/services/files.service.ts deleted file mode 100644 index 7ec38c46..00000000 --- a/projects/cobbler-frontend/src/app/services/files.service.ts +++ /dev/null @@ -1,35 +0,0 @@ -import {Injectable} from '@angular/core'; - -@Injectable({ - providedIn: 'root' -}) -export class FilesService { - // from: https://github.com/cobbler/cobbler/blob/master/cobbler/items/file.py - // index for this FIELDS[0-3] are not UI editable - // mockdata is FIELDS[4-13] - // mockdata: Replace(Python=>JS) - // 'True'=> 'true' - // 'None'=> 'Null' - // 'False'=>'false' - // Are we going to need a converter to swap these out in data request/post ? - mockdata = [ - ['action', 'create', 0, 'Action', true, 'Create or remove file resource', 0, 'str'], - ['comment', '', 0, 'Comment', true, 'Free form text description', 0, 'str'], - ['group', '', 0, 'Owner group in file system', true, 'File owner group in file system', 0, 'str'], - ['is_dir', false, 0, 'Is Directory', true, 'Treat file resource as a directory', 0, 'bool'], - ['mode', '', 0, 'Mode', true, 'The mode of the file', 0, 'str'], - ['name', '', 0, 'Name', true, 'Name of file resource', 0, 'str'], - ['owner', '', 0, 'Owner user in file system', true, 'File owner user in file system', 0, 'str'], - ['owners', 'SETTINGS:default_ownership', 0, 'Owners', true, 'Owners list for authz_ownership (space delimited)', - [], 'list'], - ['path', '', 0, 'Path', true, 'The path for the file', 0, 'str'], - ['template', '', 0, 'Template', true, 'The template for the file', 0, 'str'] - ]; - - constructor() { - } - - getAll(): any[] { - return this.mockdata; - } -} diff --git a/projects/cobbler-frontend/src/app/services/images.service.spec.js b/projects/cobbler-frontend/src/app/services/images.service.spec.js deleted file mode 100644 index 1f99ffeb..00000000 --- a/projects/cobbler-frontend/src/app/services/images.service.spec.js +++ /dev/null @@ -1,15 +0,0 @@ -"use strict"; -Object.defineProperty(exports, "__esModule", { value: true }); -var testing_1 = require("@angular/core/testing"); -var images_service_1 = require("./images.service"); -describe('ImagesService', function () { - var service; - beforeEach(function () { - testing_1.TestBed.configureTestingModule({}); - service = testing_1.TestBed.inject(images_service_1.ImagesService); - }); - it('should be created', function () { - expect(service).toBeTruthy(); - }); -}); -//# sourceMappingURL=images.service.spec.js.map \ No newline at end of file diff --git a/projects/cobbler-frontend/src/app/services/images.service.spec.js.map b/projects/cobbler-frontend/src/app/services/images.service.spec.js.map deleted file mode 100644 index 56027c0d..00000000 --- a/projects/cobbler-frontend/src/app/services/images.service.spec.js.map +++ /dev/null @@ -1 +0,0 @@ -{"version":3,"file":"images.service.spec.js","sourceRoot":"","sources":["images.service.spec.ts"],"names":[],"mappings":";;AAAA,iDAAgD;AAEhD,mDAAiD;AAEjD,QAAQ,CAAC,eAAe,EAAE;IACxB,IAAI,OAAsB,CAAC;IAE3B,UAAU,CAAC;QACT,iBAAO,CAAC,sBAAsB,CAAC,EAAE,CAAC,CAAC;QACnC,OAAO,GAAG,iBAAO,CAAC,MAAM,CAAC,8BAAa,CAAC,CAAC;IAC1C,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,mBAAmB,EAAE;QACtB,MAAM,CAAC,OAAO,CAAC,CAAC,UAAU,EAAE,CAAC;IAC/B,CAAC,CAAC,CAAC;AACL,CAAC,CAAC,CAAC"} \ No newline at end of file diff --git a/projects/cobbler-frontend/src/app/services/images.service.spec.ts b/projects/cobbler-frontend/src/app/services/images.service.spec.ts deleted file mode 100644 index 9bb2694f..00000000 --- a/projects/cobbler-frontend/src/app/services/images.service.spec.ts +++ /dev/null @@ -1,16 +0,0 @@ -import { TestBed } from '@angular/core/testing'; - -import { ImagesService } from './images.service'; - -describe('ImagesService', () => { - let service: ImagesService; - - beforeEach(() => { - TestBed.configureTestingModule({}); - service = TestBed.inject(ImagesService); - }); - - it('should be created', () => { - expect(service).toBeTruthy(); - }); -}); diff --git a/projects/cobbler-frontend/src/app/services/images.service.ts b/projects/cobbler-frontend/src/app/services/images.service.ts deleted file mode 100644 index 70614dbb..00000000 --- a/projects/cobbler-frontend/src/app/services/images.service.ts +++ /dev/null @@ -1,40 +0,0 @@ -import {Injectable} from '@angular/core'; - -@Injectable({ - providedIn: 'root' -}) -export class ImagesService { - // python True => true - // python None => null - // python methods => "methods" - mockdata = [ - ['arch', 'x86_64', 0, 'Architecture', true, '', 'utils.get_valid_archs()', 'str'], - ['autoinstall', '', 0, 'Automatic installation file', true, 'Path to autoinst/answer file template', 0, 'str'], - ['breed', 'redhat', 0, 'Breed', true, '', 'utils.get_valid_breeds()', 'str'], - ['comment', '', 0, 'Comment', true, 'Free form text description', 0, 'str'], - ['file', '', 0, 'File', true, 'Path to local file or nfs://user@host:path', 0, 'str'], - ['image_type', 'iso', 0, 'Image Type', true, '', ['iso', 'direct', 'memdisk', 'virt-image'], 'str'], - ['name', '', 0, 'Name', true, '', 0, 'str'], - ['network_count', 1, 0, 'Virt NICs', true, '', 0, 'int'], - ['os_version', '', 0, 'OS Version', true, 'ex: rhel4', 'utils.get_valid_os_versions()', 'str'], - ['owners', 'SETTINGS:default_ownership', 0, 'Owners', true, 'Owners list for authz_ownership (space delimited)', - [], 'list'], - ['virt_auto_boot', 'SETTINGS:virt_auto_boot', 0, 'Virt Auto Boot', true, 'Auto boot this VM?', 0, 'bool'], - ['virt_bridge', 'SETTINGS:default_virt_bridge', 0, 'Virt Bridge', true, '', 0, 'str'], - ['virt_cpus', 1, 0, 'Virt CPUs', true, '', 0, 'int'], - ['virt_disk_driver', 'SETTINGS:default_virt_disk_driver', 0, 'Virt Disk Driver Type', true, - 'The on-disk format for the virtualization disk', 'raw', 'str'], - ['virt_file_size', 'SETTINGS:default_virt_file_size', 0, 'Virt File Size (GB)', true, '', 0, 'float'], - ['virt_path', '', 0, 'Virt Path', true, 'Ex: /directory or VolGroup00', 0, 'str'], - ['virt_ram', 'SETTINGS:default_virt_ram', 0, 'Virt RAM (MB)', true, '', 0, 'int'], - ['virt_type', 'SETTINGS:default_virt_type', 0, 'Virt Type', true, '', ['xenpv', 'xenfv', 'qemu', 'kvm', 'vmware'], - 'str'], - ]; - - constructor() { - } - - getAll(): any[] { - return this.mockdata; - } -} diff --git a/projects/cobbler-frontend/src/app/services/mngclasses.service.spec.js b/projects/cobbler-frontend/src/app/services/mngclasses.service.spec.js deleted file mode 100644 index 602a58e9..00000000 --- a/projects/cobbler-frontend/src/app/services/mngclasses.service.spec.js +++ /dev/null @@ -1,15 +0,0 @@ -"use strict"; -Object.defineProperty(exports, "__esModule", { value: true }); -var testing_1 = require("@angular/core/testing"); -var mngclasses_service_1 = require("./mngclasses.service"); -describe('MngclassesService', function () { - var service; - beforeEach(function () { - testing_1.TestBed.configureTestingModule({}); - service = testing_1.TestBed.inject(mngclasses_service_1.MngclassesService); - }); - it('should be created', function () { - expect(service).toBeTruthy(); - }); -}); -//# sourceMappingURL=mngclasses.service.spec.js.map \ No newline at end of file diff --git a/projects/cobbler-frontend/src/app/services/mngclasses.service.spec.js.map b/projects/cobbler-frontend/src/app/services/mngclasses.service.spec.js.map deleted file mode 100644 index 2f796963..00000000 --- a/projects/cobbler-frontend/src/app/services/mngclasses.service.spec.js.map +++ /dev/null @@ -1 +0,0 @@ -{"version":3,"file":"mngclasses.service.spec.js","sourceRoot":"","sources":["mngclasses.service.spec.ts"],"names":[],"mappings":";;AAAA,iDAAgD;AAEhD,2DAAyD;AAEzD,QAAQ,CAAC,mBAAmB,EAAE;IAC5B,IAAI,OAA0B,CAAC;IAE/B,UAAU,CAAC;QACT,iBAAO,CAAC,sBAAsB,CAAC,EAAE,CAAC,CAAC;QACnC,OAAO,GAAG,iBAAO,CAAC,MAAM,CAAC,sCAAiB,CAAC,CAAC;IAC9C,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,mBAAmB,EAAE;QACtB,MAAM,CAAC,OAAO,CAAC,CAAC,UAAU,EAAE,CAAC;IAC/B,CAAC,CAAC,CAAC;AACL,CAAC,CAAC,CAAC"} \ No newline at end of file diff --git a/projects/cobbler-frontend/src/app/services/mngclasses.service.spec.ts b/projects/cobbler-frontend/src/app/services/mngclasses.service.spec.ts deleted file mode 100644 index 4d18aeb6..00000000 --- a/projects/cobbler-frontend/src/app/services/mngclasses.service.spec.ts +++ /dev/null @@ -1,16 +0,0 @@ -import { TestBed } from '@angular/core/testing'; - -import { MngclassesService } from './mngclasses.service'; - -describe('MngclassesService', () => { - let service: MngclassesService; - - beforeEach(() => { - TestBed.configureTestingModule({}); - service = TestBed.inject(MngclassesService); - }); - - it('should be created', () => { - expect(service).toBeTruthy(); - }); -}); diff --git a/projects/cobbler-frontend/src/app/services/mngclasses.service.ts b/projects/cobbler-frontend/src/app/services/mngclasses.service.ts deleted file mode 100644 index e6c22d4b..00000000 --- a/projects/cobbler-frontend/src/app/services/mngclasses.service.ts +++ /dev/null @@ -1,27 +0,0 @@ -import { Injectable } from '@angular/core'; - -@Injectable({ - providedIn: 'root' -}) -export class MngclassesService { - // mockdata python=>JS conversion - // python Bool => JS bool - // python None => 'None' - // python method() => 'method()' - mockdata = [ - ['class_name', '', 0, 'Class Name', true, 'Actual Class Name (leave blank to use the name field)', 0, 'str'], - ['comment', '', 0, 'Comment', true, 'Free form text description', 0, 'str'], - ['files', [], 0, 'Files', true, 'File resources', 0, 'list'], - ['name', '', 0, 'Name', true, 'Ex: F10-i386-webserver', 0, 'str'], - ['owners', 'SETTINGS:default_ownership', 'SETTINGS:default_ownership', 'Owners', true, - 'Owners list for authz_ownership (space delimited)', 0, 'list'], - ['packages', [], 0, 'Packages', true, 'Package resources', 0, 'list'], - ['params', {}, 0, 'Parameters/Variables', true, 'List of parameters/variables', 0, 'dict'], -]; - - constructor() { } - - getAll(): any[] { - return this.mockdata; - } -} diff --git a/projects/cobbler-frontend/src/app/services/packages.service.spec.js b/projects/cobbler-frontend/src/app/services/packages.service.spec.js deleted file mode 100644 index 97b087de..00000000 --- a/projects/cobbler-frontend/src/app/services/packages.service.spec.js +++ /dev/null @@ -1,15 +0,0 @@ -"use strict"; -Object.defineProperty(exports, "__esModule", { value: true }); -var testing_1 = require("@angular/core/testing"); -var packages_service_1 = require("./packages.service"); -describe('PackagesService', function () { - var service; - beforeEach(function () { - testing_1.TestBed.configureTestingModule({}); - service = testing_1.TestBed.inject(packages_service_1.PackagesService); - }); - it('should be created', function () { - expect(service).toBeTruthy(); - }); -}); -//# sourceMappingURL=packages.service.spec.js.map \ No newline at end of file diff --git a/projects/cobbler-frontend/src/app/services/packages.service.spec.js.map b/projects/cobbler-frontend/src/app/services/packages.service.spec.js.map deleted file mode 100644 index 4b6523bc..00000000 --- a/projects/cobbler-frontend/src/app/services/packages.service.spec.js.map +++ /dev/null @@ -1 +0,0 @@ -{"version":3,"file":"packages.service.spec.js","sourceRoot":"","sources":["packages.service.spec.ts"],"names":[],"mappings":";;AAAA,iDAAgD;AAEhD,uDAAqD;AAErD,QAAQ,CAAC,iBAAiB,EAAE;IAC1B,IAAI,OAAwB,CAAC;IAE7B,UAAU,CAAC;QACT,iBAAO,CAAC,sBAAsB,CAAC,EAAE,CAAC,CAAC;QACnC,OAAO,GAAG,iBAAO,CAAC,MAAM,CAAC,kCAAe,CAAC,CAAC;IAC5C,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,mBAAmB,EAAE;QACtB,MAAM,CAAC,OAAO,CAAC,CAAC,UAAU,EAAE,CAAC;IAC/B,CAAC,CAAC,CAAC;AACL,CAAC,CAAC,CAAC"} \ No newline at end of file diff --git a/projects/cobbler-frontend/src/app/services/packages.service.spec.ts b/projects/cobbler-frontend/src/app/services/packages.service.spec.ts deleted file mode 100644 index 26ea404d..00000000 --- a/projects/cobbler-frontend/src/app/services/packages.service.spec.ts +++ /dev/null @@ -1,16 +0,0 @@ -import { TestBed } from '@angular/core/testing'; - -import { PackagesService } from './packages.service'; - -describe('PackagesService', () => { - let service: PackagesService; - - beforeEach(() => { - TestBed.configureTestingModule({}); - service = TestBed.inject(PackagesService); - }); - - it('should be created', () => { - expect(service).toBeTruthy(); - }); -}); diff --git a/projects/cobbler-frontend/src/app/services/packages.service.ts b/projects/cobbler-frontend/src/app/services/packages.service.ts deleted file mode 100644 index 150cd30d..00000000 --- a/projects/cobbler-frontend/src/app/services/packages.service.ts +++ /dev/null @@ -1,27 +0,0 @@ -import {Injectable} from '@angular/core'; - -@Injectable({ - providedIn: 'root' -}) -export class PackagesService { - // mockdata python=>JS conversion - // python Bool => JS bool - // python None => 'None' - // python method() => 'method()' - mockdata = [ - ['action', 'create', 0, 'Action', true, 'Install or remove package resource', 0, 'str'], - ['comment', '', 0, 'Comment', true, 'Free form text description', 0, 'str'], - ['installer', 'yum', 0, 'Installer', true, 'Package Manager', 0, 'str'], - ['name', '', 0, 'Name', true, 'Name of file resource', 0, 'str'], - ['owners', 'SETTINGS:default_ownership', 0, 'Owners', true, 'Owners list for authz_ownership (space delimited)', - [], 'list'], - ['version', '', 0, 'Version', true, 'Package Version', 0, 'str'], - ]; - - constructor() { - } - - getAll(): any[] { - return this.mockdata; - } -} diff --git a/projects/cobbler-frontend/src/app/services/profile.service.spec.js b/projects/cobbler-frontend/src/app/services/profile.service.spec.js deleted file mode 100644 index 8aac6406..00000000 --- a/projects/cobbler-frontend/src/app/services/profile.service.spec.js +++ /dev/null @@ -1,15 +0,0 @@ -"use strict"; -Object.defineProperty(exports, "__esModule", { value: true }); -var testing_1 = require("@angular/core/testing"); -var profile_service_1 = require("./profile.service"); -describe('ProfileService', function () { - var service; - beforeEach(function () { - testing_1.TestBed.configureTestingModule({}); - service = testing_1.TestBed.inject(profile_service_1.ProfileService); - }); - it('should be created', function () { - expect(service).toBeTruthy(); - }); -}); -//# sourceMappingURL=profile.service.spec.js.map \ No newline at end of file diff --git a/projects/cobbler-frontend/src/app/services/profile.service.spec.js.map b/projects/cobbler-frontend/src/app/services/profile.service.spec.js.map deleted file mode 100644 index f5c369e8..00000000 --- a/projects/cobbler-frontend/src/app/services/profile.service.spec.js.map +++ /dev/null @@ -1 +0,0 @@ -{"version":3,"file":"profile.service.spec.js","sourceRoot":"","sources":["profile.service.spec.ts"],"names":[],"mappings":";;AAAA,iDAAgD;AAEhD,qDAAmD;AAEnD,QAAQ,CAAC,gBAAgB,EAAE;IACzB,IAAI,OAAuB,CAAC;IAE5B,UAAU,CAAC;QACT,iBAAO,CAAC,sBAAsB,CAAC,EAAE,CAAC,CAAC;QACnC,OAAO,GAAG,iBAAO,CAAC,MAAM,CAAC,gCAAc,CAAC,CAAC;IAC3C,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,mBAAmB,EAAE;QACtB,MAAM,CAAC,OAAO,CAAC,CAAC,UAAU,EAAE,CAAC;IAC/B,CAAC,CAAC,CAAC;AACL,CAAC,CAAC,CAAC"} \ No newline at end of file diff --git a/projects/cobbler-frontend/src/app/services/profile.service.spec.ts b/projects/cobbler-frontend/src/app/services/profile.service.spec.ts deleted file mode 100644 index 2ddf7f2f..00000000 --- a/projects/cobbler-frontend/src/app/services/profile.service.spec.ts +++ /dev/null @@ -1,16 +0,0 @@ -import { TestBed } from '@angular/core/testing'; - -import { ProfileService } from './profile.service'; - -describe('ProfileService', () => { - let service: ProfileService; - - beforeEach(() => { - TestBed.configureTestingModule({}); - service = TestBed.inject(ProfileService); - }); - - it('should be created', () => { - expect(service).toBeTruthy(); - }); -}); diff --git a/projects/cobbler-frontend/src/app/services/profile.service.ts b/projects/cobbler-frontend/src/app/services/profile.service.ts deleted file mode 100644 index e3146648..00000000 --- a/projects/cobbler-frontend/src/app/services/profile.service.ts +++ /dev/null @@ -1,70 +0,0 @@ -import {Injectable} from '@angular/core'; - -@Injectable({ - providedIn: 'root' -}) -export class ProfileService { - // mockdata python=>JS conversion - // python Bool => JS bool - // python None => ''None'' - // python method() => 'method()' - - mockdata = [ - ['autoinstall', 'SETTINGS:default_autoinstall', '<>', 'Automatic Installation Template', true, - 'Path to automatic installation template', 0, 'str'], - ['autoinstall_meta', {}, '<>', 'Automatic Installation Metadata', true, 'Ex: dog=fang agent=86', 0, - 'dict'], - ['boot_files', {}, '<>', 'TFTP Boot Files', true, 'Files copied into tftpboot beyond the kernel/initrd', - 0, 'list'], - ['comment', '', '', 'Comment', true, 'Free form text description', 0, 'str'], - ['dhcp_tag', 'default', '<>', 'DHCP Tag', true, 'See manpage or leave blank', 0, 'str'], - ['distro', 'None', '<>', 'Distribution', true, 'Parent distribution', [], 'str'], - ['enable_gpxe', 'SETTINGS:enable_gpxe', 0, 'Enable gPXE?', true, - 'Use gPXE instead of PXELINUX for advanced booting options', 0, 'bool'], - ['enable_menu', 'SETTINGS:enable_menu', '<>', 'Enable PXE Menu?', true, - 'Show this profile in the PXE menu?', 0, 'bool'], - ['fetchable_files', {}, '<>', 'Fetchable Files', true, 'Templates for tftp or wget/curl', 0, 'dict'], - ['kernel_options', {}, '<>', 'Kernel Options', true, 'Ex: selinux=permissive', 0, 'dict'], - ['kernel_options_post', {}, '<>', 'Kernel Options (Post Install)', true, 'Ex: clocksource=pit noapic', 0, - 'dict'], - ['mgmt_classes', [], '<>', 'Management Classes', true, 'For external configuration management', 0, 'list'], - ['mgmt_parameters', '<>', '<>', 'Management Parameters', true, - 'Parameters which will be handed to your management application (Must be valid YAML dictionary)', 0, 'str'], - ['name', '', 'None', 'Name', true, 'Ex: F10-i386-webserver', 0, 'str'], - ['name_servers', 'SETTINGS:default_name_servers', [], 'Name Servers', true, 'space delimited', 0, 'list'], - ['name_servers_search', 'SETTINGS:default_name_servers_search', [], 'Name Servers Search Path', true, - 'space delimited', 0, 'list'], - ['next_server', '<>', '<>', 'Next Server Override', true, 'See manpage or leave blank', 0, 'str'], - ['filename', '<>', '<>', 'DHCP Filename Override', true, 'Use to boot non-default bootloaders', - 0, 'str'], - ['owners', 'SETTINGS:default_ownership', 'SETTINGS:default_ownership', 'Owners', true, - 'Owners list for authz_ownership (space delimited)', 0, 'list'], - ['parent', '', '', 'Parent Profile', true, '', [], 'str'], - ['proxy', 'SETTINGS:proxy_url_int', '<>', 'Proxy', true, 'Proxy URL', 0, 'str'], - ['redhat_management_key', '<>', '<>', 'Red Hat Management Key', true, - 'Registration key for RHN, Spacewalk, or Satellite', 0, 'str'], - ['repos', [], '<>', 'Repos', true, 'Repos to auto-assign to this profile', [], 'list'], - ['server', '<>', '<>', 'Server Override', true, 'See manpage or leave blank', 0, 'str'], - ['template_files', {}, '<>', 'Template Files', true, 'File mappings for built-in config management', 0, - 'dict'], - ['virt_auto_boot', 'SETTINGS:virt_auto_boot', '<>', 'Virt Auto Boot', true, 'Auto boot this VM?', 0, - 'bool'], - ['virt_bridge', 'SETTINGS:default_virt_bridge', '<>', 'Virt Bridge', true, '', 0, 'str'], - ['virt_cpus', 1, '<>', 'Virt CPUs', true, 'integer', 0, 'int'], - ['virt_disk_driver', 'SETTINGS:default_virt_disk_driver', '<>', 'Virt Disk Driver Type', true, - 'The on-disk format for the virtualization disk', 'validate.VIRT_DISK_DRIVERS', 'str'], - ['virt_file_size', 'SETTINGS:default_virt_file_size', '<>', 'Virt File Size(GB)', true, '', 0, 'int'], - ['virt_path', '', '<>', 'Virt Path', true, 'Ex: /directory OR VolGroup00', 0, 'str'], - ['virt_ram', 'SETTINGS:default_virt_ram', '<>', 'Virt RAM (MB)', true, '', 0, 'int'], - ['virt_type', 'SETTINGS:default_virt_type', '<>', 'Virt Type', true, 'Virtualization technology to use', - 'validate.VIRT_TYPES', 'str'], - - ]; - - constructor() { - } - - getAll(): any[] { - return this.mockdata; - } -} diff --git a/projects/cobbler-frontend/src/app/services/repos.service.spec.js b/projects/cobbler-frontend/src/app/services/repos.service.spec.js deleted file mode 100644 index 9e74c89a..00000000 --- a/projects/cobbler-frontend/src/app/services/repos.service.spec.js +++ /dev/null @@ -1,15 +0,0 @@ -"use strict"; -Object.defineProperty(exports, "__esModule", { value: true }); -var testing_1 = require("@angular/core/testing"); -var repos_service_1 = require("./repos.service"); -describe('ReposService', function () { - var service; - beforeEach(function () { - testing_1.TestBed.configureTestingModule({}); - service = testing_1.TestBed.inject(repos_service_1.ReposService); - }); - it('should be created', function () { - expect(service).toBeTruthy(); - }); -}); -//# sourceMappingURL=repos.service.spec.js.map \ No newline at end of file diff --git a/projects/cobbler-frontend/src/app/services/repos.service.spec.js.map b/projects/cobbler-frontend/src/app/services/repos.service.spec.js.map deleted file mode 100644 index 707603b7..00000000 --- a/projects/cobbler-frontend/src/app/services/repos.service.spec.js.map +++ /dev/null @@ -1 +0,0 @@ -{"version":3,"file":"repos.service.spec.js","sourceRoot":"","sources":["repos.service.spec.ts"],"names":[],"mappings":";;AAAA,iDAAgD;AAEhD,iDAA+C;AAE/C,QAAQ,CAAC,cAAc,EAAE;IACvB,IAAI,OAAqB,CAAC;IAE1B,UAAU,CAAC;QACT,iBAAO,CAAC,sBAAsB,CAAC,EAAE,CAAC,CAAC;QACnC,OAAO,GAAG,iBAAO,CAAC,MAAM,CAAC,4BAAY,CAAC,CAAC;IACzC,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,mBAAmB,EAAE;QACtB,MAAM,CAAC,OAAO,CAAC,CAAC,UAAU,EAAE,CAAC;IAC/B,CAAC,CAAC,CAAC;AACL,CAAC,CAAC,CAAC"} \ No newline at end of file diff --git a/projects/cobbler-frontend/src/app/services/repos.service.spec.ts b/projects/cobbler-frontend/src/app/services/repos.service.spec.ts deleted file mode 100644 index 2b1bfb84..00000000 --- a/projects/cobbler-frontend/src/app/services/repos.service.spec.ts +++ /dev/null @@ -1,16 +0,0 @@ -import { TestBed } from '@angular/core/testing'; - -import { ReposService } from './repos.service'; - -describe('ReposService', () => { - let service: ReposService; - - beforeEach(() => { - TestBed.configureTestingModule({}); - service = TestBed.inject(ReposService); - }); - - it('should be created', () => { - expect(service).toBeTruthy(); - }); -}); diff --git a/projects/cobbler-frontend/src/app/services/repos.service.ts b/projects/cobbler-frontend/src/app/services/repos.service.ts deleted file mode 100644 index 9c4abb6f..00000000 --- a/projects/cobbler-frontend/src/app/services/repos.service.ts +++ /dev/null @@ -1,44 +0,0 @@ -import {Injectable} from '@angular/core'; - -@Injectable({ - providedIn: 'root' -}) -export class ReposService { - // mockdata python=>JS conversion - // python Bool => JS bool - // python None => ''None'' - // python method() => 'method()' - mockdata = [ - ['apt_components', '', 0, 'Apt Components (apt only)', true, 'ex: main restricted universe', [], 'list'], - ['apt_dists', '', 0, 'Apt Dist Names (apt only)', true, 'ex: precise precise-updates', [], 'list'], - ['arch', 'x86_64', 0, 'Arch', true, 'ex: i386, x86_64', ['i386', 'x86_64', 'ia64', 'ppc', 'ppc64', 'ppc64le', - 'ppc64el', 's390', 's390x', 'arm', 'aarch64', 'noarch', 'src'], 'str'], - ['breed', 'rsync', 0, 'Breed', true, '', 'validate.REPO_BREEDS', 'str'], - ['comment', '', 0, 'Comment', true, 'Free form text description', 0, 'str'], - ['createrepo_flags', '<>', 0, 'Createrepo Flags', true, 'Flags to use with createrepo', 0, 'dict'], - ['environment', {}, 0, 'Environment Variables', true, - 'Use these environment variables during commands (key=value, space delimited)', 0, 'dict'], - ['keep_updated', true, 0, 'Keep Updated', true, 'Update this repo on next \'cobbler reposync\'?', 0, 'bool'], - ['mirror', 'None', 0, 'Mirror', true, 'Address of yum or rsync repo to mirror', 0, 'str'], - ['mirror_type', 'baseurl', 0, 'Mirror Type', true, '', ['metalink', 'mirrorlist', 'baseurl'], 'str'], - ['mirror_locally', true, 0, 'Mirror locally', true, 'Copy files or just reference the repo externally?', 0, 'bool'], - ['name', '', 0, 'Name', true, 'Ex: f10-i386-updates', 0, 'str'], - ['owners', 'SETTINGS:default_ownership', 0, 'Owners', true, 'Owners list for authz_ownership (space delimited)', - [], 'list'], - ['priority', 99, 0, 'Priority', true, 'Value for yum priorities plugin, if installed', 0, 'int'], - ['proxy', '<>', 0, 'Proxy information', true, - 'http://example.com:8080, or <> to use proxy_url_ext from settings, blank or <> for no proxy', [], - 'str'], - ['rpm_list', [], 0, 'RPM List', true, 'Mirror just these RPMs (yum only)', 0, 'list'], - ['yumopts', {}, 0, 'Yum Options', true, 'Options to write to yum config file', 0, 'dict'], - ['rsyncopts', '', 0, 'Rsync Options', true, 'Options to use with rsync repo', 0, 'dict'], - ]; - - - constructor() { - } - - getAll(): any[] { - return this.mockdata; - } -}