diff --git a/src/gmp/commands/resourcenames.js b/src/gmp/commands/resourcenames.js
new file mode 100644
index 0000000000..c7d233b975
--- /dev/null
+++ b/src/gmp/commands/resourcenames.js
@@ -0,0 +1,85 @@
+/* Copyright (C) 2023 Greenbone AG
+ *
+ * SPDX-License-Identifier: AGPL-3.0-or-later
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Affero General Public License
+ * as published by the Free Software Foundation, either version 3
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see .
+ */
+
+import registerCommand from 'gmp/command';
+
+import ResourceName from 'gmp/models/resourcename';
+import EntitiesCommand from './entities';
+
+export class ResourceNamesCommand extends EntitiesCommand {
+ constructor(http) {
+ super(http, 'resource_name', ResourceName);
+ this.name = 'resource';
+ }
+
+ getEntitiesResponse(root) {
+ return root.get_resource_names.get_resource_names_response;
+ }
+
+ export(entities) {
+ throw new Error('export not implemented in ' + this.constructor.name);
+ }
+
+ exportByIds(ids) {
+ throw new Error('exportByIds not implemented in ' + this.constructor.name);
+ }
+
+ exportByFilter(filter) {
+ throw new Error(
+ 'exportByFilter not implemented in ' + this.constructor.name,
+ );
+ }
+
+ delete(entities, extraParams) {
+ throw new Error('delete not implemented in ' + this.constructor.name);
+ }
+
+ deleteByIds(ids, extraParams = {}) {
+ throw new Error('deleteByIds not implemented in ' + this.constructor.name);
+ }
+
+ deleteByFilter(filter, extraParams) {
+ throw new Error(
+ 'deleteByFilter not implemented in ' + this.constructor.name,
+ );
+ }
+
+ transformAggregates(response) {
+ throw new Error(
+ 'transformAggregates not implemented in ' + this.constructor.name,
+ );
+ }
+
+ getAggregates({
+ dataColumns = [],
+ textColumns = [],
+ sort = [],
+ aggregateMode,
+ maxGroups,
+ subgroupColumn,
+ ...params
+ } = {}) {
+ throw new Error(
+ 'getAggregates not implemented in ' + this.constructor.name,
+ );
+ }
+}
+
+registerCommand('resourcenames', ResourceNamesCommand);
+
+// vim: set ts=2 sw=2 tw=80:
diff --git a/src/gmp/gmp.js b/src/gmp/gmp.js
index 6511092d67..844b0d5368 100644
--- a/src/gmp/gmp.js
+++ b/src/gmp/gmp.js
@@ -36,6 +36,7 @@ import 'gmp/commands/filters';
import 'gmp/commands/groups';
import 'gmp/commands/hosts';
import 'gmp/commands/license';
+import 'gmp/commands/resourcenames';
import 'gmp/commands/notes';
import 'gmp/commands/nvt';
import 'gmp/commands/nvtfamilies';
diff --git a/src/gmp/models/resourcename.js b/src/gmp/models/resourcename.js
new file mode 100644
index 0000000000..a8fd61f8c0
--- /dev/null
+++ b/src/gmp/models/resourcename.js
@@ -0,0 +1,36 @@
+/* Copyright (C) 2023 Greenbone AG
+ *
+ * SPDX-License-Identifier: AGPL-3.0-or-later
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Affero General Public License
+ * as published by the Free Software Foundation, either version 3
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see .
+ */
+import {isDefined} from 'gmp/utils/identity';
+
+export class ResourceName {
+ constructor({id, name}) {
+ this.id = id;
+ this.name = name;
+ }
+
+ static fromElement(element) {
+ const {_id, name} = element;
+
+ return new ResourceName({
+ id: isDefined(_id) ? _id : '',
+ name: isDefined(name) ? name : '',
+ });
+ }
+}
+
+export default ResourceName;
diff --git a/src/web/pages/tags/dialog.js b/src/web/pages/tags/dialog.js
index 824af77222..c7574ea215 100644
--- a/src/web/pages/tags/dialog.js
+++ b/src/web/pages/tags/dialog.js
@@ -25,7 +25,6 @@ import _ from 'gmp/locale';
import {isDefined} from 'gmp/utils/identity';
import {map} from 'gmp/utils/array';
import {isEmpty} from 'gmp/utils/string';
-import {pluralizeType, normalizeType} from 'gmp/utils/entitytype';
import {YES_VALUE} from 'gmp/parser';
@@ -54,11 +53,30 @@ const ScrollableContent = styled.div`
overflow: auto;
`;
+const types = {
+ operatingsystem: 'os',
+ certbund: 'cert_bund_adv',
+ dfncert: 'dfn_cert_adv',
+ portlist: 'port_list',
+ reportformat: 'report_format',
+ scanconfig: 'config',
+ tlscertificate: 'tls_certificate',
+};
+
+const convertType = type => {
+ const ctype = types[type];
+ if (isDefined(ctype)) {
+ return ctype;
+ }
+ return type;
+};
+
class TagDialog extends React.Component {
constructor(...args) {
super(...args);
const {resource_ids = []} = this.props;
+ this.isLoading = false;
this.state = {
resourceIdText: '',
@@ -81,24 +99,27 @@ class TagDialog extends React.Component {
return;
}
const {gmp} = this.props;
- const plType = pluralizeType(normalizeType(type));
- gmp[plType].getAll().then(response => {
- const {data} = response;
- let id = this.state.resourceIdText;
- const idPresent = data.includes(res => res.id === id);
- if (!idPresent && !isEmpty(id)) {
- data.push({
- name: '----',
- id: id,
+ this.isLoading = true;
+ gmp.resourcenames
+ .getAll({resource_type: convertType(type)})
+ .then(response => {
+ const {data} = response;
+ let id = this.state.resourceIdText;
+ const idPresent = data.includes(res => res.id === id);
+ if (!idPresent && !isEmpty(id)) {
+ data.push({
+ name: '----',
+ id: id,
+ });
+ }
+ if (isEmpty(id)) {
+ id = undefined;
+ }
+ this.isLoading = false;
+ this.setState({
+ resourceOptions: data,
});
- }
- if (isEmpty(id)) {
- id = undefined;
- }
- this.setState({
- resourceOptions: data,
});
- });
}
handleResourceTypeChange(type, onValueChange) {
@@ -107,6 +128,7 @@ class TagDialog extends React.Component {
this.loadResourcesByType(type);
this.setState({
resourceIdsSelected: [],
+ resourceOptions: [],
resourceType: type,
});
}
@@ -123,8 +145,8 @@ class TagDialog extends React.Component {
const {gmp} = this.props;
const {resourceIdsSelected, resourceType} = this.state;
- gmp[pluralizeType(normalizeType(resourceType))]
- .get({filter: 'uuid=' + id})
+ gmp.resourcenames
+ .get({resource_type: convertType(resourceType), filter: 'uuid=' + id})
.then(response => {
const ids = isDefined(resourceIdsSelected) ? resourceIdsSelected : [];
if (response.data.length === 0) {
@@ -265,6 +287,10 @@ class TagDialog extends React.Component {
fixed ||
resourceTypesOptions.length === 0
}
+ isLoading={
+ this.isLoading &&
+ this.state.resourceOptions.length === 0
+ }
onChange={ids => this.handleIdChange(ids, onValueChange)}
/>