Skip to content

Commit

Permalink
Replacing use of store with useQuery for content packs. (#21358)
Browse files Browse the repository at this point in the history
* Replacing use of store with `useQuery` for content packs.

* Introducing hook, make `ContentPacksPage` use it instead of store.

* Adding license headers.

* Improving typing.

* Fixing linter hint.
  • Loading branch information
dennisoelkers authored Jan 20, 2025
1 parent bba32b0 commit 04214af
Show file tree
Hide file tree
Showing 11 changed files with 203 additions and 86 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -16,9 +16,12 @@
*/
package org.graylog2.contentpacks.model;

import com.fasterxml.jackson.annotation.JsonProperty;
import com.fasterxml.jackson.annotation.JsonSubTypes;
import com.fasterxml.jackson.annotation.JsonTypeInfo;

import java.net.URI;

@JsonTypeInfo(use = JsonTypeInfo.Id.NAME, include = JsonTypeInfo.As.EXISTING_PROPERTY, property = Versioned.FIELD_META_VERSION, defaultImpl = LegacyContentPack.class)
@JsonSubTypes({
@JsonSubTypes.Type(value = LegacyContentPack.class),
Expand All @@ -27,4 +30,19 @@
public interface ContentPack extends Identified, Revisioned, Versioned {
interface ContentPackBuilder<SELF> extends IdBuilder<SELF>, RevisionBuilder<SELF>, VersionBuilder<SELF> {
}

@JsonProperty
String name();

@JsonProperty
String description();

@JsonProperty
String summary();

@JsonProperty
URI url();

@JsonProperty
String vendor();
}
2 changes: 1 addition & 1 deletion graylog2-web-interface/src/components/common/router.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ type Props = {
target?: string,
};

const isLeftClickEvent = (e: React.MouseEvent<HTMLAnchorElement, MouseEvent>) => (e.button === 0);
const isLeftClickEvent = (e: React.MouseEvent<HTMLAnchorElement, MouseEvent>) => (e?.button === 0);

const isModifiedEvent = (e: React.MouseEvent<HTMLAnchorElement, MouseEvent>) => !!(e.metaKey || e.altKey || e.ctrlKey || e.shiftKey);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,19 +18,19 @@ import React from 'react';

import Spinner from 'components/common/Spinner';
import { DataTable } from 'components/common';

import 'components/content-packs/ContentPackDetails.css';
import type { InstalledEntity } from 'components/content-packs/Types';

type ContentPackInstallEntityListProps = {
entities?: any[];
entities?: InstalledEntity[];
uninstall?: boolean;
};

const ContentPackInstallEntityList = ({
entities,
entities = undefined,
uninstall = false,
}: ContentPackInstallEntityListProps) => {
const rowFormatter = (entity) => (<tr><td>{entity.title}</td><td>{entity.type.name}</td></tr>);
const rowFormatter = (entity: InstalledEntity) => (<tr><td>{entity.title}</td><td>{entity.type.name}</td></tr>);
const headers = ['Title', 'Type'];
const headerTitle = uninstall ? 'Entites to be uninstalled' : 'Installed Entities';

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,13 +23,16 @@ import 'components/content-packs/ContentPackDetails.css';
import ContentPackInstallEntityList from './ContentPackInstallEntityList';

type ContentPackInstallViewProps = {
install: any;
install: {
comment: string,
created_at: string,
created_by: string,
entities: any[],
};
};

const ContentPackInstallView = (props: ContentPackInstallViewProps) => {
const { comment } = props.install;
const createdAt = props.install.created_at;
const createdBy = props.install.created_by;
const ContentPackInstallView = ({ install }: ContentPackInstallViewProps) => {
const { comment, created_at: createdAt, created_by: createdBy, entities } = install;

return (
<div>
Expand All @@ -48,7 +51,7 @@ const ContentPackInstallView = (props: ContentPackInstallViewProps) => {
</Row>
<Row>
<Col smOffset={1} sm={10}>
<ContentPackInstallEntityList entities={props.install.entities} />
<ContentPackInstallEntityList entities={entities} />
</Col>
</Row>
</div>
Expand Down
19 changes: 13 additions & 6 deletions graylog2-web-interface/src/components/content-packs/Types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,17 +16,17 @@
*/

export type ContentPackInstallation = {
created_at: string,
created_at?: string,
description: string,
entities?: Array<ContentPackEntity>,
id: string,
name: string,
parameters?: Array<any>,
rev: number,
server_version: string,
server_version?: string,
summary: string,
url: string,
v: number,
v: string,
vendor: string,
}

Expand Down Expand Up @@ -70,9 +70,16 @@ export interface Constraint {
}

export type ContentPackMetadata = {
[key: number]: {
[key: number]: {
[key: string]: number,
[string: number]: {
[string: number]: {
installation_count: number,
},
},
}

export type InstalledEntity = {
title: string,
type: {
name: string
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ describe('<ContentPackListItem />', () => {
server_version: '6.0.0-SNAPSHOT',
summary: 'The Open Thread Exchange Lookup Table of the Threat Intel Plugin',
url: 'https://github.com/Graylog2/graylog2-server',
v: 1,
v: '1',
vendor: 'Graylog <[email protected]>',
};

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
/*
* Copyright (C) 2020 Graylog, Inc.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the Server Side Public License, version 1,
* as published by MongoDB, Inc.
*
* 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
* Server Side Public License for more details.
*
* You should have received a copy of the Server Side Public License
* along with this program. If not, see
* <http://www.mongodb.com/licensing/server-side-public-license>.
*/
import { useQuery } from '@tanstack/react-query';

import { SystemContentPacks } from '@graylog/server-api';

const useContentPackInstallations = (id: string) => useQuery(
['content-packs', 'installations', id],
() => SystemContentPacks.listContentPackInstallationsById(id),
);
export default useContentPackInstallations;
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
/*
* Copyright (C) 2020 Graylog, Inc.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the Server Side Public License, version 1,
* as published by MongoDB, Inc.
*
* 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
* Server Side Public License for more details.
*
* You should have received a copy of the Server Side Public License
* along with this program. If not, see
* <http://www.mongodb.com/licensing/server-side-public-license>.
*/
import { useQuery } from '@tanstack/react-query';

import { SystemContentPacks } from '@graylog/server-api';

import ContentPackRevisions from 'logic/content-packs/ContentPackRevisions';
import { onError } from 'util/conditional/onError';
import UserNotification from 'util/UserNotification';

const fetchContentPackRevisions = async (id: string) => {
const response = await SystemContentPacks.listContentPackRevisions(id);
const contentPackRevision = new ContentPackRevisions(response.content_pack_revisions);
const constraints = response.constraints_result;

return {
contentPackRevisions: contentPackRevision,
selectedVersion: contentPackRevision.latestRevision,
constraints: constraints,
};
};

const defaultErrorHandler = (error: Error) => UserNotification.error(`Error while fetching content pack revisions: ${error}`, 'Unable to fetch content pack');

const useContentPackRevisions = (id: string, onFetchError: (e: Error) => void = defaultErrorHandler) => useQuery(
['content-packs', 'revisions', id],
() => onError(fetchContentPackRevisions(id), onFetchError),
);
export default useContentPackRevisions;
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
/*
* Copyright (C) 2020 Graylog, Inc.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the Server Side Public License, version 1,
* as published by MongoDB, Inc.
*
* 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
* Server Side Public License for more details.
*
* You should have received a copy of the Server Side Public License
* along with this program. If not, see
* <http://www.mongodb.com/licensing/server-side-public-license>.
*/
import { useQuery } from '@tanstack/react-query';

import { SystemContentPacks } from '@graylog/server-api';

const useContentPacks = () => useQuery(['content-packs', 'list'], () => SystemContentPacks.listContentPacks());
export default useContentPacks;
69 changes: 34 additions & 35 deletions graylog2-web-interface/src/pages/ContentPacksPage.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,8 @@
* along with this program. If not, see
* <http://www.mongodb.com/licensing/server-side-public-license>.
*/
import React, { useEffect } from 'react';
import * as React from 'react';
import { useCallback } from 'react';
import styled, { css } from 'styled-components';

import { LinkContainer } from 'components/common/router';
Expand All @@ -25,55 +26,53 @@ import UserNotification from 'util/UserNotification';
import { DocumentTitle, PageHeader } from 'components/common';
import ContentPacksList from 'components/content-packs/ContentPacksList';
import ContentPackUploadControls from 'components/content-packs/ContentPackUploadControls';
import { ContentPacksActions, ContentPacksStore } from 'stores/content-packs/ContentPacksStore';
import { useStore } from 'stores/connect';
import { ContentPacksActions } from 'stores/content-packs/ContentPacksStore';
import useContentPacks from 'components/content-packs/hooks/useContentPacks';

const ConfigurationBundles = styled.div(({ theme }) => css`
font-size: ${theme.fonts.size.body};
font-weight: normal;
margin-top: 15px;
`);

const _deleteContentPack = (contentPackId: string) => {
// eslint-disable-next-line no-alert
if (window.confirm('You are about to delete this Content Pack, are you sure?')) {
ContentPacksActions.delete(contentPackId).then(() => {
UserNotification.success('Content Pack deleted successfully.', 'Success');
ContentPacksActions.list();
}, (error) => {
let err_message = error.message;
const err_body = error.additional.body;
const ContentPacksPage = () => {
const { data, isInitialLoading, refetch } = useContentPacks();

if (err_body && err_body.message) {
err_message = error.additional.body.message;
}
const _deleteContentPack = useCallback((contentPackId: string) => {
// eslint-disable-next-line no-alert
if (window.confirm('You are about to delete this Content Pack, are you sure?')) {
ContentPacksActions.delete(contentPackId).then(() => {
UserNotification.success('Content Pack deleted successfully.', 'Success');
refetch();
}, (error) => {
let err_message = error.message;
const err_body = error.additional.body;

UserNotification.error(`Deleting bundle failed: ${err_message}`, 'Error');
});
}
};
if (err_body && err_body.message) {
err_message = error.additional.body.message;
}

const _installContentPack = (contentPackId: string, contentPackRev: string, parameters: unknown) => {
ContentPacksActions.install(contentPackId, contentPackRev, parameters).then(() => {
UserNotification.success('Content Pack installed successfully.', 'Success');
ContentPacksActions.list();
}, (error) => {
UserNotification.error(`Installing content pack failed with status: ${error}.
Could not install Content Pack with ID: ${contentPackId}`);
});
};
UserNotification.error(`Deleting bundle failed: ${err_message}`, 'Error');
});
}
}, [refetch]);

const ContentPacksPage = () => {
const { contentPacks, contentPackMetadata } = useStore(ContentPacksStore);

useEffect(() => {
ContentPacksActions.list();
}, []);
const _installContentPack = useCallback((contentPackId: string, contentPackRev: string, parameters: unknown) => {
ContentPacksActions.install(contentPackId, contentPackRev, parameters).then(() => {
UserNotification.success('Content Pack installed successfully.', 'Success');
refetch();
}, (error) => {
UserNotification.error(`Installing content pack failed with status: ${error}.
Could not install Content Pack with ID: ${contentPackId}`);
});
}, [refetch]);

if (!contentPacks) {
if (isInitialLoading) {
return (<Spinner />);
}

const { content_packs: contentPacks, content_packs_metadata: contentPackMetadata } = data;

return (
<DocumentTitle title="Content Packs">
<span>
Expand Down
Loading

0 comments on commit 04214af

Please sign in to comment.