Skip to content

Commit

Permalink
added docs for some frontend code
Browse files Browse the repository at this point in the history
  • Loading branch information
Mizcky committed Apr 22, 2024
1 parent 8e5dc25 commit 7f7f4a5
Show file tree
Hide file tree
Showing 41 changed files with 623 additions and 66 deletions.
2 changes: 1 addition & 1 deletion kraken_frontend/src/components/textarea.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import React from "react";

/** React props for [`<Textarea />`]{@link Textarea} */
export type TextareaProps = {
/** The textarea's current value */
/** The text area's current value */
value: string;
/** Callback invoked when the user changed the value */
onChange: (newValue: string) => void;
Expand Down
2 changes: 1 addition & 1 deletion kraken_frontend/src/context/user.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import React from "react";
import { toast } from "react-toastify";
import { Api } from "../api/api";
import { ApiError, StatusCode } from "../api/error";
import { FullUser, UserPermission } from "../api/generated/models";
import { FullUser, UserPermission } from "../api/generated";
import WS from "../api/websocket";
import Loading from "../components/loading";
import CONSOLE from "../utils/console";
Expand Down
6 changes: 5 additions & 1 deletion kraken_frontend/src/views/admin/users.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,11 @@ import Input from "../../components/input";
import Loading from "../../components/loading";
import { check, handleApiError } from "../../utils/helper";

/** View to expose the `/api/v1/admin/users` endpoints */
/**
* View to expose the `/api/v1/admin/users` endpoints
*
* @returns JSX.Element
*/
export default function AdminUsers() {
/** Store a user to ask for confirmation before deleting him */
const [confirmDelete, setConfirmDelete] = React.useState<FullUser | null>(null);
Expand Down
6 changes: 5 additions & 1 deletion kraken_frontend/src/views/admin/workspaces.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,11 @@ import { SimpleWorkspace } from "../../api/generated";
import Loading from "../../components/loading";
import { handleApiError } from "../../utils/helper";

/** View to expose the `/api/v1/admin/workspaces` endpoints */
/**
* View to expose the `/api/v1/admin/workspaces` endpoints
*
* @returns JSX.Element
*/
export default function AdminWorkspaces() {
const [workspaces, setWorkspaces] = React.useState<Array<SimpleWorkspace> | undefined>(undefined);

Expand Down
27 changes: 27 additions & 0 deletions kraken_frontend/src/views/gobal-popup.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,15 +6,37 @@ import WS from "../api/websocket";
import { handleApiError } from "../utils/helper";
import Invitation from "./workspace/invitation/invitation";

/** workspace invitation popup */
type Popup = WsInvitationToWorkspace;

/** type for workspace invitation*/
type WsInvitationToWorkspace = {
/**
* popup type
*/
type: "invitation";
/**
* UUID of invitation
*/
invitationUuid: UUID;
/**
* workspace the invitation is for
*/
workspace: SimpleWorkspace;
/**
* user who sent out workspace invitation
*/
from: SimpleUser;
};

/**
* Handle all global popups (currently only invitations)
* and display them on top of kraken
*
* new popup types can be added here
*
* @returns JSX.Element displayed popup
*/
export default function GlobalPopup() {
const [popups, setPopups] = React.useState<Array<Popup>>([]);

Expand Down Expand Up @@ -46,6 +68,11 @@ export default function GlobalPopup() {
popup = popups[0];
}

/**
* switch trough popup type to select the displayed popup
*
* @returns <Invitation/>
*/
const popupDisplay = () => {
switch (popup.type) {
case "invitation":
Expand Down
29 changes: 29 additions & 0 deletions kraken_frontend/src/views/settings.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,13 @@ import CloseIcon from "../svg/close";
import CopyIcon from "../svg/copy";
import { copyToClipboard, handleApiError } from "../utils/helper";

/**
* Page showing the kraken settings
*
* Only visible for admin user
*
* @returns JSX.Element
*/
export default function Settings() {
const [settings, setSettings] = React.useState<SettingsFull | null>(null);
const [oauthApplications, setOauthApplications] = React.useState<Array<FullOauthClient>>([]);
Expand All @@ -19,10 +26,16 @@ export default function Settings() {
const [wordlistPath, setWordlistPath] = React.useState<string>("");
const [wordlistDescription, setWordlistDescription] = React.useState<string>("");

/**
* Api call to get the currently active settings
*/
async function retrieveSettings() {
await Api.admin.settings.get().then(handleApiError((settings) => setSettings(settings)));
}

/**
* Api call to get the current existing OAuth apps
*/
async function getOAuthApps() {
await Api.admin.oauthApplications.all().then(
handleApiError((apps) => {
Expand All @@ -31,6 +44,9 @@ export default function Settings() {
);
}

/**
* Api call to get all wordlists including their paths
*/
async function updateWordlists() {
await Api.admin.wordlists.all().then(
handleApiError((wordlists) => {
Expand All @@ -43,6 +59,11 @@ export default function Settings() {
Promise.all([getOAuthApps(), retrieveSettings(), updateWordlists()]).then();
}, []);

/**
* Api call to create a new wordlist
*
* Name and path are required
*/
async function createWordlist() {
if (wordlistName === "") {
toast.error("Name of the wordlist must not be empty");
Expand All @@ -62,6 +83,9 @@ export default function Settings() {
.then(handleApiError((_) => toast.success("Created wordlist")));
}

/**
* Api call to save the updated settings
*/
async function saveSettings() {
if (settings === null) {
return;
Expand All @@ -70,6 +94,11 @@ export default function Settings() {
await Api.admin.settings.update(settings).then(handleApiError((_) => toast.success("Settings updated")));
}

/**
* Api call to create a new application
*
* Name and uri are required
*/
async function createOAuthApp() {
if (newOAuthAppName === "" || newOAuthAppRedirectUrl === "") {
toast.error("App name and redirect uri must not be empty");
Expand Down
23 changes: 17 additions & 6 deletions kraken_frontend/src/views/workspace-overview.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -12,18 +12,25 @@ import "../styling/workspace-overview.css";
import WorkspaceIcon from "../svg/workspace";
import { check, handleApiError } from "../utils/helper";

/**
* type to select how the displayed workspaces are sorted
*/
type Sorting = "none" | "name" | "createdAt";

/** View to expose the `/api/v1/workspaces` endpoints */
/**
* View to expose the `/api/v1/workspaces` endpoints
*
* @returns JSX.Element
*/
export default function WorkspaceOverview() {
const context = React.useContext(USER_CONTEXT);
// queried data
const [workspaces, setWorkspaces] = React.useState<Array<SimpleWorkspace> | undefined>(undefined);

// controlled state
/** New workspace's name */
/** New workspace name */
const [newName, setNewName] = React.useState<string>("");
/** New workspace's description */
/** New workspace description */
const [newDesc, setNewDesc] = React.useState<string>("");
/** The search query */
const [search, setSearch] = React.useState<string>("");
Expand All @@ -34,12 +41,18 @@ export default function WorkspaceOverview() {

const [sorting, setSorting] = React.useState<Sorting>("none");

/**
* Api call to get all the existing workspaces
*/
function retrieveAllWorkspaces() {
Api.workspaces.all().then(handleApiError(({ workspaces }) => setWorkspaces(workspaces)));
}

React.useEffect(() => retrieveAllWorkspaces(), []);

/**
* Api call to create a new workspace
*/
async function createWorkspace() {
if (!check([[newName.length > 0, "Empty name"]])) return;

Expand Down Expand Up @@ -165,9 +178,7 @@ export default function WorkspaceOverview() {
if (onlyOwner && !isOwner) return false;
if (onlyMember && isOwner) return false;

if (onlyArchived != (e.archived ?? false)) return false;

return true;
return onlyArchived == (e.archived ?? false);
})
.sort((a, b) => {
switch (sorting) {
Expand Down
20 changes: 20 additions & 0 deletions kraken_frontend/src/views/workspace/components/certainty-icon.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,17 +6,33 @@ import UnknownIcon from "../../../svg/unknown";
import UnverifiedIcon from "../../../svg/unverified";
import VerifiedIcon from "../../../svg/verified";

/** React props for {@link CertaintyIcon `<CertaintyIcon />`} */
type CertaintyIconProps = {
/**
* type of certainty
*/
certainty: DomainCertainty | HostCertainty | PortCertainty | ServiceCertainty;
/**
* toggle if name is visible next to the certainty icon
*/
nameVisible?: boolean | undefined;
};

/** Global lookup of certainties' icons, names and descriptions */
const CERTAINTIES: Record<
DomainCertainty | HostCertainty | PortCertainty | ServiceCertainty,
{
/**
* Svg icon for certainty
*/
icon: React.ReactNode;
/**
* displayed certainty name
*/
name: string;
/**
* displayed certainty description
*/
description: string;
}
> = {
Expand Down Expand Up @@ -73,6 +89,10 @@ const CERTAINTIES: Record<
},
};

/**
* Displays certainty icon.
* On hover displays popup with certainty name and description
*/
export default function CertaintyIcon(props: CertaintyIconProps) {
const { certainty, nameVisible } = props;
const { icon, name, description } = CERTAINTIES[certainty];
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,21 +2,28 @@ import React, { HTMLProps, ReactNode, useEffect } from "react";
import "../../../styling/collapsible-section.css";
import ArrowDownIcon from "../../../svg/arrow-down";

/** React props for {@link CollapsibleSection `<CollapsibleSection />`} */
export type CollapsibleSectionProps = {
/**
* ReactNode used for section heading
*/
summary: ReactNode;
/**
* if section content is initially visible or not
*/
defaultVisible?: boolean;
visible?: boolean;
/**
* Optional callback when visibility of body is toggled
*/
onChangeVisible?: (visible: boolean) => void;
} & Omit<HTMLProps<HTMLDivElement>, "summary">;

export default function CollapsibleSection({
summary,
children,
defaultVisible,
visible: wantVisible,
onChangeVisible,
...props
}: CollapsibleSectionProps) {
/**
* Component for section with heading which is collapsible through an arrow.
*/
export default function CollapsibleSection(props: CollapsibleSectionProps) {
const { summary, children, defaultVisible, visible: wantVisible, onChangeVisible } = props;
const [visible, setVisible] = React.useState(defaultVisible ?? true);

useEffect(() => {
Expand Down
8 changes: 8 additions & 0 deletions kraken_frontend/src/views/workspace/components/data-tabs.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,12 @@ const TABS: Record<AggregationType, string> = {
[AggregationType.HttpService]: "HTTP Services",
} as const;

/** React props for <DataTabsSelector /> */
export type DataTabsSelectorProps = {
value: AggregationType;
/**
* callback when new tab is selected
*/
onChange: (newValue: AggregationType) => void;
};

Expand All @@ -35,6 +39,10 @@ export function useDataTabs(): [AggregationType, React.Dispatch<React.SetStateAc
return [value, setValue];
}

/**
* Tab selector for AggregationTypes,
* used in combination with {@link StatelessWorkspaceTable}
*/
export function DataTabsSelector(props: DataTabsSelectorProps) {
const { value, onChange } = props;

Expand Down
17 changes: 16 additions & 1 deletion kraken_frontend/src/views/workspace/components/domain.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,22 @@ import SelectableText from "../../../components/selectable-text";
import { handleApiError } from "../../../utils/helper";
import { DomainRelationsList } from "./relations-list";

export default function Domain({ domain, pretty: _ }: { domain: FullDomain | SimpleDomain; pretty?: boolean }) {
/** React props for [`<Domain />`]{@link Domain} */
type DomainProps = {
/**
* Domain to display
*/
domain: FullDomain | SimpleDomain;
pretty?: boolean;
};

/**
* Component to display domain.
*
* On hover display popup with list of domain relation
*/
export default function Domain(props: DomainProps) {
const { domain } = props;
const [relations, setRelations] = useState<DomainRelations | undefined>(undefined);

const ensureDataLoaded = useCallback(() => {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,10 @@ import React from "react";
import Creatable from "react-select/creatable";
import { toast } from "react-toastify";
import { Api } from "../../../api/api";
import { FullDomain, FullHost, FullPort, FullService } from "../../../api/generated";
import { FullHttpService } from "../../../api/generated/models/FullHttpService";
import { FullDomain, FullHost, FullHttpService, FullPort, FullService } from "../../../api/generated";
import { selectStyles } from "../../../components/select-menu";

/**
* Props for `<EditableDataList<T>>`
*/
/** Props for `<EditableDataList<T>>`*/
export type EditableDataListProps<T extends FullHost | FullPort | FullDomain | FullService | FullHttpService> = {
/**
* The workspace containing the item whose items to list
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import { selectStyles } from "../../../components/select-menu";
import Tag from "../../../components/tag";
import WorkspaceCreateTag from "./workspace-create-tag";

/** React props for <EditableTags />*/
export type EditableTagsProps = {
/**
* The workspace containing the item whose tags to edit
Expand Down
Loading

0 comments on commit 7f7f4a5

Please sign in to comment.