@omnsight/osint-entity-components 0.2.5 → 0.2.7
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.js +8 -8
- package/dist/index.mjs +1429 -1146
- package/package.json +23 -2
- package/src/App.tsx +397 -141
- package/src/assets/icons/generated/boxicons-file-report.tsx +20 -0
- package/src/assets/icons/generated/bx-plus-medical.tsx +8 -0
- package/src/assets/icons/generated/bx-run.tsx +8 -0
- package/src/assets/icons/generated/fa-solid-fist-raised.tsx +8 -0
- package/src/assets/icons/generated/fluent-emoji-high-contrast-ballot-box-with-ballot.tsx +8 -0
- package/src/assets/icons/generated/glyphs-handshake-bold.tsx +8 -0
- package/src/assets/icons/generated/icon-park-currency.tsx +8 -0
- package/src/assets/icons/generated/icon-park-great-wall.tsx +8 -0
- package/src/assets/icons/generated/iconoir-commodity.tsx +8 -0
- package/src/assets/icons/generated/lsicon-work-order-abnormal-outline.tsx +8 -0
- package/src/assets/icons/generated/material-symbols-light-drone.tsx +8 -0
- package/src/assets/icons/generated/material-symbols-satellite-alt.tsx +8 -0
- package/src/assets/icons/generated/mdi-anchor.tsx +19 -0
- package/src/assets/icons/generated/ph-mask-happy-fill.tsx +8 -0
- package/src/assets/icons/generated/streamline-ultimate-meeting-remote-bold.tsx +19 -0
- package/src/assets/icons/generated/tabler-barrier-block.tsx +8 -0
- package/src/assets/icons/generated/typcn-flash.tsx +8 -0
- package/src/avatars/layouts/AvatarDropdown.tsx +1 -1
- package/src/forms/BaseForm.tsx +138 -0
- package/src/forms/EditableAttributes.tsx +131 -0
- package/src/forms/EventForm/EditableForm.tsx +78 -0
- package/src/forms/EventForm/EditingForm.tsx +401 -0
- package/src/forms/EventForm/IconFormSection.tsx +54 -0
- package/src/forms/EventForm/StaticForm.tsx +272 -0
- package/src/forms/EventForm/index.ts +1 -0
- package/src/forms/InsightForm/EditableForm.tsx +70 -0
- package/src/forms/InsightForm/EditingForm.tsx +79 -0
- package/src/forms/InsightForm/StaticForm.tsx +139 -0
- package/src/forms/InsightForm/index.ts +1 -0
- package/src/forms/MonitoringSourceForm/EditableForm.tsx +59 -0
- package/src/forms/MonitoringSourceForm/EditingForm.tsx +192 -0
- package/src/forms/MonitoringSourceForm/StaticForm.tsx +107 -0
- package/src/forms/MonitoringSourceForm/index.ts +1 -0
- package/src/forms/OrganizationForm/EditableForm.tsx +74 -0
- package/src/forms/OrganizationForm/EditingForm.tsx +177 -0
- package/src/forms/OrganizationForm/IconFormSection.tsx +60 -0
- package/src/forms/OrganizationForm/StaticForm.tsx +209 -0
- package/src/forms/OrganizationForm/index.ts +1 -0
- package/src/forms/PersonForm/EditableForm.tsx +74 -0
- package/src/forms/PersonForm/EditingForm.tsx +187 -0
- package/src/forms/PersonForm/IconFormSection.tsx +54 -0
- package/src/forms/PersonForm/StaticForm.tsx +202 -0
- package/src/forms/PersonForm/index.ts +1 -0
- package/src/forms/RelationForm/EditableForm.tsx +74 -0
- package/src/forms/RelationForm/EditingForm.tsx +147 -0
- package/src/forms/RelationForm/StaticForm.tsx +182 -0
- package/src/forms/RelationForm/index.ts +1 -0
- package/src/forms/SourceForm/EditableForm.tsx +74 -0
- package/src/forms/SourceForm/EditingForm.tsx +199 -0
- package/src/forms/SourceForm/IconFormSection.tsx +54 -0
- package/src/forms/SourceForm/StaticForm.tsx +209 -0
- package/src/forms/SourceForm/index.ts +1 -0
- package/src/forms/WebsiteForm/EditableForm.tsx +74 -0
- package/src/forms/WebsiteForm/EditingForm.tsx +216 -0
- package/src/forms/WebsiteForm/IconFormSection.tsx +54 -0
- package/src/forms/WebsiteForm/StaticForm.tsx +225 -0
- package/src/forms/WebsiteForm/index.ts +1 -0
- package/src/forms/accessLevel.ts +48 -0
- package/src/forms/index.ts +8 -0
- package/src/icons/Event/Select.tsx +7 -6
- package/src/icons/Event/icons.ts +112 -4
- package/src/icons/Organization/Select.tsx +7 -6
- package/src/icons/Person/Select.tsx +7 -6
- package/src/icons/Source/Select.tsx +7 -6
- package/src/icons/Website/Select.tsx +9 -8
- package/src/icons/index.ts +1 -0
- package/src/inputs/CountrySelect.tsx +45 -0
- package/src/inputs/CustomDatePicker.tsx +51 -0
- package/src/inputs/CustomDateTimePicker.tsx +51 -0
- package/src/inputs/RangeDatePicker.tsx +99 -0
- package/src/inputs/TimezoneSelect.tsx +20 -0
- package/src/inputs/index.ts +5 -0
- package/src/locales/en.json +153 -1
- package/src/locales/zh.json +153 -1
- package/src/main.tsx +20 -4
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
// From: https://icon-sets.iconify.design/fa-solid/fist-raised
|
|
2
|
+
import type { SVGProps } from 'react';
|
|
3
|
+
export const IconFaSolidFistRaised = ({
|
|
4
|
+
size = 24,
|
|
5
|
+
...props
|
|
6
|
+
}: SVGProps<SVGSVGElement> & {
|
|
7
|
+
size?: number | string;
|
|
8
|
+
}) => <svg xmlns="http://www.w3.org/2000/svg" fill="currentColor" viewBox="0 0 512 512" width={size} height={size} {...props}><path d="M255.98 160V16c0-8.84-7.16-16-16-16h-32c-8.84 0-16 7.16-16 16v146.93c5.02-1.78 10.34-2.93 15.97-2.93zm128 95.99c-.01-35.34-28.66-63.99-63.99-63.99H207.85c-8.78 0-15.9 7.07-15.9 15.85v.56c0 26.27 21.3 47.59 47.57 47.59h35.26c9.68 0 13.2 3.58 13.2 8v16.2c0 4.29-3.59 7.78-7.88 8-44.52 2.28-64.16 24.71-96.05 72.55l-6.31 9.47a7.994 7.994 0 0 1-11.09 2.22l-13.31-8.88a7.994 7.994 0 0 1-2.22-11.09l6.31-9.47c15.73-23.6 30.2-43.26 47.31-58.08-17.27-5.51-31.4-18.12-38.87-34.45-6.59 3.41-13.96 5.52-21.87 5.52h-32c-12.34 0-23.49-4.81-32-12.48C71.48 251.19 60.33 256 48 256H16c-5.64 0-10.97-1.15-16-2.95v77.93c0 33.95 13.48 66.5 37.49 90.51L63.99 448v64h255.98v-63.96l35.91-35.92A96.04 96.04 0 0 0 384 344.21zm-32.01-90.09V48c0-8.84-7.16-16-16-16h-32c-8.84 0-16 7.16-16 16v112h32c11.28 0 21.94 2.31 32 5.9M16 224h32c8.84 0 16-7.16 16-16V80c0-8.84-7.16-16-16-16H16C7.16 64 0 71.16 0 80v128c0 8.84 7.16 16 16 16m95.99 0h32c8.84 0 16-7.16 16-16V48c0-8.84-7.16-16-16-16h-32c-8.84 0-16 7.16-16 16v160c0 8.84 7.16 16 16 16" /></svg>;
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
// From: https://icon-sets.iconify.design/fluent-emoji-high-contrast/ballot-box-with-ballot
|
|
2
|
+
import type { SVGProps } from 'react';
|
|
3
|
+
export const IconFluentEmojiHighContrastBallotBoxWithBallot = ({
|
|
4
|
+
size = 24,
|
|
5
|
+
...props
|
|
6
|
+
}: SVGProps<SVGSVGElement> & {
|
|
7
|
+
size?: number | string;
|
|
8
|
+
}) => <svg xmlns="http://www.w3.org/2000/svg" fill="currentColor" viewBox="0 0 32 32" width={size} height={size} {...props}><path d="M14.534 9.266h.007c.228 0 .446-.09.599-.247L19.83 4.2a.713.713 0 0 0-.058-1.06.85.85 0 0 0-1.14.054L14.55 7.387l-1.174-1.246a.85.85 0 0 0-1.14-.07.714.714 0 0 0-.075 1.058l1.771 1.881a.84.84 0 0 0 .602.256m10.269 16.611c0 .78.68 1.413 1.521 1.413s1.522-.633 1.522-1.413v-7.915c0-.78-.681-1.413-1.522-1.413-.84 0-1.522.632-1.522 1.413z" /><path d="M11.962 1.5c-.933 0-1.847.647-1.847 1.625V5H4.288C2.543 5 1 6.33 1 8.125V29a2 2 0 0 0 2 2h26a2 2 0 0 0 2-2V8.125C31 6.33 29.457 5 27.712 5h-5.759V3.125c0-.978-.914-1.625-1.846-1.625zm-.847 1.625c0-.265.291-.625.846-.625h8.146c.556 0 .846.36.846.625V10.5h-9.838zM21.953 7h5.759C28.494 7 29 7.572 29 8.125v5.846H3V8.125C3 7.572 3.506 7 4.288 7h5.827v2.582c-.526.167-.906.63-.906 1.176 0 .686.6 1.242 1.338 1.242h10.906c.74 0 1.338-.556 1.338-1.242 0-.521-.347-.968-.838-1.152zM3 16h26v13H3z" /></svg>;
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
// From: https://icon-sets.iconify.design/glyphs/handshake-bold
|
|
2
|
+
import type { SVGProps } from 'react';
|
|
3
|
+
export const IconGlyphsHandshakeBold = ({
|
|
4
|
+
size = 24,
|
|
5
|
+
...props
|
|
6
|
+
}: SVGProps<SVGSVGElement> & {
|
|
7
|
+
size?: number | string;
|
|
8
|
+
}) => <svg xmlns="http://www.w3.org/2000/svg" fill="currentColor" viewBox="0 0 80 80" width={size} height={size} {...props}><path fillRule="evenodd" d="M42.356 29.901 39.38 32.88l-2.29 2.29a2.954 2.954 0 1 1-4.138-4.216l6.806-6.555q.165-.158.34-.299a8 8 0 0 1 2.26 5.802m15.37 21.518-1.36 1.855A7.9 7.9 0 0 1 50 56.5l-1.113 1.113a6.44 6.44 0 0 1-8.678.394L39 57l-.702.702a7.846 7.846 0 0 1-11.096 0l-7.53-7.53A4 4 0 0 0 16.843 49H4V27h12.343a4 4 0 0 0 2.829-1.172l3.485-3.485A8 8 0 0 1 28.314 20h4.372c.877 0 1.739.144 2.554.419l-6.45 6.212A8.954 8.954 0 1 0 41.33 39.41l.418-.417 15.91 12.374.067.051" clipRule="evenodd" /><path d="M63.657 27H76v22H59.5l-18-14-2.29 2.29a5.954 5.954 0 1 1-8.34-8.498l6.806-6.555A8 8 0 0 1 43.226 20h8.46a8 8 0 0 1 5.657 2.343l3.485 3.485A4 4 0 0 0 63.657 27" /></svg>;
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
// From: https://icon-sets.iconify.design/icon-park/currency
|
|
2
|
+
import type { SVGProps } from 'react';
|
|
3
|
+
export const IconIconParkCurrency = ({
|
|
4
|
+
size = 24,
|
|
5
|
+
...props
|
|
6
|
+
}: SVGProps<SVGSVGElement> & {
|
|
7
|
+
size?: number | string;
|
|
8
|
+
}) => <svg xmlns="http://www.w3.org/2000/svg" fill="currentColor" viewBox="0 0 48 48" width={size} height={size} {...props}><g fill="none" stroke="currentColor" strokeLinecap="round" strokeLinejoin="round" strokeWidth={4}><path d="m19 16 5 6 5-6" /><path d="M9 14s7.5-11.5 20.5-7S42 24.5 42 24.5M39 34s-6 11-19.5 7.5S6 24 6 24M42 8v16M6 24v16M18 28h12M18 22h12M24 22v12" /></g></svg>;
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
// From: https://icon-sets.iconify.design/icon-park/great-wall
|
|
2
|
+
import type { SVGProps } from 'react';
|
|
3
|
+
export const IconIconParkGreatWall = ({
|
|
4
|
+
size = 24,
|
|
5
|
+
...props
|
|
6
|
+
}: SVGProps<SVGSVGElement> & {
|
|
7
|
+
size?: number | string;
|
|
8
|
+
}) => <svg xmlns="http://www.w3.org/2000/svg" fill="currentColor" viewBox="0 0 48 48" width={size} height={size} {...props}><g fill="none" stroke="currentColor" strokeLinecap="round" strokeLinejoin="round" strokeWidth={4}><path d="M4 9v31h40V9h-8v7h-8V9h-8v7h-8V9zM4 24h40M4 32h40M24 24v8M16 32v8M16 16v8M32 32v8M32 16v8" /></g></svg>;
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
// From: https://icon-sets.iconify.design/iconoir/commodity
|
|
2
|
+
import type { SVGProps } from 'react';
|
|
3
|
+
export const IconIconoirCommodity = ({
|
|
4
|
+
size = 24,
|
|
5
|
+
...props
|
|
6
|
+
}: SVGProps<SVGSVGElement> & {
|
|
7
|
+
size?: number | string;
|
|
8
|
+
}) => <svg xmlns="http://www.w3.org/2000/svg" fill="currentColor" viewBox="0 0 24 24" width={size} height={size} {...props}><g fill="none" stroke="currentColor" strokeLinecap="round" strokeWidth={1.5}><path d="m12.147 18.28 1.184-5.8a.6.6 0 0 1 .588-.48h6.162a.6.6 0 0 1 .588.48l1.184 5.8a.6.6 0 0 1-.588.72h-8.53a.6.6 0 0 1-.588-.72Z" /><path d="m7.147 11.28 1.184-5.8A.6.6 0 0 1 8.918 5h6.164a.6.6 0 0 1 .587.48l1.184 5.8a.6.6 0 0 1-.588.72h-8.53a.6.6 0 0 1-.588-.72Z" /><path d="m2.147 18.28 1.184-5.8a.6.6 0 0 1 .587-.48h6.163a.6.6 0 0 1 .588.48l1.184 5.8a.6.6 0 0 1-.588.72h-8.53a.6.6 0 0 1-.588-.72Z" /></g></svg>;
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
// From: https://icon-sets.iconify.design/lsicon/work-order-abnormal-outline
|
|
2
|
+
import type { SVGProps } from 'react';
|
|
3
|
+
export const IconLsiconWorkOrderAbnormalOutline = ({
|
|
4
|
+
size = 24,
|
|
5
|
+
...props
|
|
6
|
+
}: SVGProps<SVGSVGElement> & {
|
|
7
|
+
size?: number | string;
|
|
8
|
+
}) => <svg xmlns="http://www.w3.org/2000/svg" fill="currentColor" viewBox="0 0 16 16" width={size} height={size} {...props}><path fill="none" stroke="currentColor" strokeLinejoin="round" d="M7 14.5H3.5v-13h9V7M5 6.5h4m-4-2h6m-.5 7v-2m3 2a3 3 0 1 1-6 0 3 3 0 0 1 6 0Zm-3 1.25h.005v.005H10.5zm.25 0a.25.25 0 1 1-.5 0 .25.25 0 0 1 .5 0Z" /></svg>;
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
// From: https://icon-sets.iconify.design/material-symbols-light/drone
|
|
2
|
+
import type { SVGProps } from 'react';
|
|
3
|
+
export const IconMaterialSymbolsLightDrone = ({
|
|
4
|
+
size = 24,
|
|
5
|
+
...props
|
|
6
|
+
}: SVGProps<SVGSVGElement> & {
|
|
7
|
+
size?: number | string;
|
|
8
|
+
}) => <svg xmlns="http://www.w3.org/2000/svg" fill="currentColor" viewBox="0 0 24 24" width={size} height={size} {...props}><path d="M5 19q0-1.644.91-2.93.91-1.285 2.361-1.787l-.423-3.667H4.981V6H2.019V5h6.923v1H5.981v3.616h1.738l-.103-1h8.75l-.104 1h1.719V6h-2.962V5h6.948v1h-2.961v4.616h-2.848l-.424 3.667q1.453.502 2.36 1.787Q19 17.356 19 19h-1q0-1.65-1.117-2.825T14.135 15H9.846q-1.611 0-2.729 1.175T6 19z" /></svg>;
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
// From: https://icon-sets.iconify.design/material-symbols/satellite-alt
|
|
2
|
+
import type { SVGProps } from 'react';
|
|
3
|
+
export const IconMaterialSymbolsSatelliteAlt = ({
|
|
4
|
+
size = 24,
|
|
5
|
+
...props
|
|
6
|
+
}: SVGProps<SVGSVGElement> & {
|
|
7
|
+
size?: number | string;
|
|
8
|
+
}) => <svg xmlns="http://www.w3.org/2000/svg" fill="currentColor" viewBox="0 0 24 24" width={size} height={size} {...props}><path d="M14 23.2v-2q2.925 0 4.963-2.037T21 14.2h2q0 1.875-.712 3.513t-1.925 2.85-2.85 1.925T14 23.2m0-4v-2q1.25 0 2.125-.875T17 14.2h2q0 2.075-1.463 3.538T14 19.2m-8.45 3.375q-.375 0-.75-.15T4.125 22l-3.55-3.55q-.275-.3-.425-.675t-.15-.75q0-.4.15-.763t.425-.637L3.75 12.45q.575-.575 1.425-.587t1.425.562l1.25 1.25.7-.7-1.25-1.25q-.575-.575-.575-1.4t.575-1.4L8.725 7.5q.575-.575 1.413-.575t1.412.575l1.25 1.25.7-.7-1.25-1.25q-.575-.575-.575-1.412t.575-1.413L15.425.8q.3-.3.675-.45t.75-.15.738.15.662.45l3.55 3.55q.3.275.438.638t.137.762q0 .375-.137.75t-.438.675l-3.175 3.175q-.575.575-1.412.575T15.8 10.35L14.55 9.1l-.7.7 1.25 1.25q.575.575.563 1.413t-.588 1.412l-1.4 1.4q-.575.575-1.412.575t-1.413-.575l-1.25-1.25-.7.7 1.25 1.25q.575.575.563 1.425t-.588 1.425L6.95 22q-.275.275-.638.425t-.762.15m0-1.975 1.05-1.05L3.05 16 2 17.05zm2.125-2.125 1.05-1.05-3.55-3.55-1.05 1.05zm9.55-9.55 1.05-1.05-3.55-3.55-1.05 1.05zM19.35 6.8l1.05-1.05-3.55-3.55-1.05 1.05z" /></svg>;
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
// From: https://icon-sets.iconify.design/mdi/anchor
|
|
2
|
+
import type { SVGProps } from "react";
|
|
3
|
+
export const IconMdiAnchor = ({
|
|
4
|
+
size = 24,
|
|
5
|
+
...props
|
|
6
|
+
}: SVGProps<SVGSVGElement> & {
|
|
7
|
+
size?: number | string;
|
|
8
|
+
}) => (
|
|
9
|
+
<svg
|
|
10
|
+
xmlns="http://www.w3.org/2000/svg"
|
|
11
|
+
fill="currentColor"
|
|
12
|
+
viewBox="0 0 24 24"
|
|
13
|
+
width={size}
|
|
14
|
+
height={size}
|
|
15
|
+
{...props}
|
|
16
|
+
>
|
|
17
|
+
<path d="M12 2a3 3 0 0 0-3 3 3 3 0 0 0 2 2.83V9H8v2h3v8.92c-.74-.13-1.5-.34-2.21-.65-.74-.32-1.39-.71-1.97-1.18s-1.04-.98-1.38-1.54L7 15l-4-3v3c0 .97.27 1.88.82 2.72A8.2 8.2 0 0 0 6 19.95c.87.64 1.84 1.14 2.88 1.5 1.05.36 2.09.55 3.12.55s2.07-.2 3.12-.56c1.04-.36 2.01-.86 2.88-1.49.92-.64 1.63-1.38 2.18-2.23.55-.84.82-1.75.82-2.72v-3l-4 3 1.56 1.55c-.34.56-.8 1.07-1.38 1.54s-1.23.86-1.97 1.18c-.71.31-1.47.52-2.21.65V11h3V9h-3V7.82A3 3 0 0 0 15 5a3 3 0 0 0-3-3m0 2a1 1 0 0 1 1 1 1 1 0 0 1-1 1 1 1 0 0 1-1-1 1 1 0 0 1 1-1" />
|
|
18
|
+
</svg>
|
|
19
|
+
);
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
// From: https://icon-sets.iconify.design/ph/mask-happy-fill
|
|
2
|
+
import type { SVGProps } from 'react';
|
|
3
|
+
export const IconPhMaskHappyFill = ({
|
|
4
|
+
size = 24,
|
|
5
|
+
...props
|
|
6
|
+
}: SVGProps<SVGSVGElement> & {
|
|
7
|
+
size?: number | string;
|
|
8
|
+
}) => <svg xmlns="http://www.w3.org/2000/svg" fill="currentColor" viewBox="0 0 256 256" width={size} height={size} {...props}><path d="M217 34.8a15.94 15.94 0 0 0-14.82-1.71c-14.03 5.46-42.36 14.62-74.18 14.62s-60.16-9.16-74.21-14.62A16 16 0 0 0 32 48v55.77c0 35.84 9.65 69.65 27.18 95.18 18.16 26.46 42.6 41 68.82 41s50.66-14.57 68.82-41c17.53-25.51 27.18-59.32 27.18-95.16V48a16 16 0 0 0-7-13.2M78 133.33a8 8 0 1 1-12-10.67C71.75 116.28 82.18 112 92 112s20.25 4.28 26 10.66a8 8 0 1 1-12 10.67c-2.68-3-8.85-5.33-14-5.33s-11.36 2.34-14 5.33m90.49 47.86a52.9 52.9 0 0 1-80.9 0 8 8 0 1 1 12.13-10.39 36.89 36.89 0 0 0 56.56 0 8 8 0 0 1 12.17 10.39ZM189.34 134a8 8 0 0 1-11.3-.63c-2.68-3-8.85-5.33-14-5.33s-11.36 2.34-14 5.33A8 8 0 1 1 138 122.66c5.71-6.38 16.14-10.66 26-10.66s20.25 4.28 26 10.66a8 8 0 0 1-.66 11.34" /></svg>;
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
// From: https://icon-sets.iconify.design/streamline-ultimate/meeting-remote-bold
|
|
2
|
+
import type { SVGProps } from "react";
|
|
3
|
+
export const IconStreamlineUltimateMeetingRemoteBold = ({
|
|
4
|
+
size = 24,
|
|
5
|
+
...props
|
|
6
|
+
}: SVGProps<SVGSVGElement> & {
|
|
7
|
+
size?: number | string;
|
|
8
|
+
}) => (
|
|
9
|
+
<svg
|
|
10
|
+
xmlns="http://www.w3.org/2000/svg"
|
|
11
|
+
fill="currentColor"
|
|
12
|
+
viewBox="0 0 24 24"
|
|
13
|
+
width={size}
|
|
14
|
+
height={size}
|
|
15
|
+
{...props}
|
|
16
|
+
>
|
|
17
|
+
<path d="M6.76 12.59h11.48A2.77 2.77 0 0 0 21 9.82V2.76A2.77 2.77 0 0 0 18.24 0H6.76A2.77 2.77 0 0 0 4 2.76v7.06a2.77 2.77 0 0 0 2.76 2.77M6 2.76A.76.76 0 0 1 6.76 2h11.48a.76.76 0 0 1 .76.76v7.06a.77.77 0 0 1-.76.77h-1.76a.25.25 0 0 1-.18-.08 5.3 5.3 0 0 0-2.16-1.29A.25.25 0 0 1 14 9a.27.27 0 0 1 .12-.25 2.84 2.84 0 1 0-2.93 0 .24.24 0 0 1 .13.24.26.26 0 0 1-.18.21A5.3 5.3 0 0 0 9 10.51a.25.25 0 0 1-.18.08H6.76A.77.77 0 0 1 6 9.82Zm17.39 20.43a5.17 5.17 0 0 0-2.54-1.71.28.28 0 0 1-.18-.21.25.25 0 0 1 .12-.24 2.86 2.86 0 1 0-2.93 0 .26.26 0 0 1-.05.46 4.9 4.9 0 0 0-1.91 1.08.27.27 0 0 1-.34 0 5.2 5.2 0 0 0-2-1.1.28.28 0 0 1-.18-.21.25.25 0 0 1 .12-.24 2.86 2.86 0 1 0-2.93 0 .26.26 0 0 1 0 .46 5 5 0 0 0-2 1.18.26.26 0 0 1-.35 0 5 5 0 0 0-2-1.19.25.25 0 0 1-.22-.19.25.25 0 0 1 .11-.28 2.85 2.85 0 1 0-2.93 0 .24.24 0 0 1 .12.24.25.25 0 0 1-.17.21 5.16 5.16 0 0 0-2.52 1.7.51.51 0 0 0-.06.53A.5.5 0 0 0 1 24h22a.5.5 0 0 0 .45-.28.51.51 0 0 0-.06-.53" />
|
|
18
|
+
</svg>
|
|
19
|
+
);
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
// From: https://icon-sets.iconify.design/tabler/barrier-block
|
|
2
|
+
import type { SVGProps } from 'react';
|
|
3
|
+
export const IconTablerBarrierBlock = ({
|
|
4
|
+
size = 24,
|
|
5
|
+
...props
|
|
6
|
+
}: SVGProps<SVGSVGElement> & {
|
|
7
|
+
size?: number | string;
|
|
8
|
+
}) => <svg xmlns="http://www.w3.org/2000/svg" fill="currentColor" viewBox="0 0 24 24" width={size} height={size} {...props}><path fill="none" stroke="currentColor" strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M4 8a1 1 0 0 1 1-1h14a1 1 0 0 1 1 1v7a1 1 0 0 1-1 1H5a1 1 0 0 1-1-1zm3 8v4m.5-4 9-9m-3 9L20 9.5m-16 4L10.5 7m6.5 9v4M5 20h4m6 0h4M17 7V5M7 7V5" /></svg>;
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
// From: https://icon-sets.iconify.design/typcn/flash
|
|
2
|
+
import type { SVGProps } from 'react';
|
|
3
|
+
export const IconTypcnFlash = ({
|
|
4
|
+
size = 24,
|
|
5
|
+
...props
|
|
6
|
+
}: SVGProps<SVGSVGElement> & {
|
|
7
|
+
size?: number | string;
|
|
8
|
+
}) => <svg xmlns="http://www.w3.org/2000/svg" fill="currentColor" viewBox="0 0 24 24" width={size} height={size} {...props}><path d="m17.502 12.033-4.241-2.458 2.138-5.131A1.003 1.003 0 0 0 14.505 3a1 1 0 0 0-.622.214l-.07.06-7.5 7.1a1.002 1.002 0 0 0 .185 1.592l4.242 2.46-2.163 5.19a.999.999 0 0 0 1.611 1.11l7.5-7.102a1.002 1.002 0 0 0-.186-1.591" /></svg>;
|
|
@@ -28,7 +28,7 @@ export const AvatarDropdown: React.FC<Props> = ({ children, avatarOnOpen, avatar
|
|
|
28
28
|
radius="xl"
|
|
29
29
|
onClick={() => setOpened((o) => !o)}
|
|
30
30
|
>
|
|
31
|
-
{opened ?
|
|
31
|
+
{opened ? avatarOnClose : avatarOnOpen}
|
|
32
32
|
</ActionIcon>
|
|
33
33
|
</Popover.Target>
|
|
34
34
|
<Popover.Dropdown
|
|
@@ -0,0 +1,138 @@
|
|
|
1
|
+
import { modals } from '@mantine/modals';
|
|
2
|
+
import { Paper, Group, Title, ActionIcon, LoadingOverlay, Text, Tooltip } from '@mantine/core';
|
|
3
|
+
import { CheckCircleIcon, XMarkIcon } from '@heroicons/react/24/solid';
|
|
4
|
+
import {
|
|
5
|
+
useForm,
|
|
6
|
+
type DefaultValues,
|
|
7
|
+
type FieldValues,
|
|
8
|
+
type UseFormReturn,
|
|
9
|
+
type SubmitHandler,
|
|
10
|
+
FormProvider,
|
|
11
|
+
} from 'react-hook-form';
|
|
12
|
+
import { useTranslation } from 'react-i18next';
|
|
13
|
+
import { get } from 'lodash';
|
|
14
|
+
import { type CSSProperties } from 'react';
|
|
15
|
+
|
|
16
|
+
interface Props<T extends FieldValues> {
|
|
17
|
+
title: string;
|
|
18
|
+
icon?: React.ReactNode;
|
|
19
|
+
titleRight?: React.ReactNode;
|
|
20
|
+
onlyShowEditOnDirty: boolean;
|
|
21
|
+
onSubmit?: SubmitHandler<T>;
|
|
22
|
+
onUpdate?: (data: Partial<T>) => void;
|
|
23
|
+
onClose: () => void;
|
|
24
|
+
defaultValues: DefaultValues<T>;
|
|
25
|
+
exitButton?: React.ReactNode;
|
|
26
|
+
children: (methods: UseFormReturn<T>) => React.ReactNode;
|
|
27
|
+
style?: CSSProperties;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
export function BaseForm<T extends FieldValues>({
|
|
31
|
+
title,
|
|
32
|
+
icon,
|
|
33
|
+
titleRight,
|
|
34
|
+
onlyShowEditOnDirty,
|
|
35
|
+
onSubmit,
|
|
36
|
+
onUpdate,
|
|
37
|
+
onClose,
|
|
38
|
+
defaultValues,
|
|
39
|
+
exitButton,
|
|
40
|
+
children,
|
|
41
|
+
style,
|
|
42
|
+
}: Props<T>) {
|
|
43
|
+
const { t } = useTranslation();
|
|
44
|
+
const methods = useForm<T>({ defaultValues });
|
|
45
|
+
const {
|
|
46
|
+
handleSubmit,
|
|
47
|
+
reset,
|
|
48
|
+
formState: { isSubmitting, isDirty, dirtyFields },
|
|
49
|
+
} = methods;
|
|
50
|
+
|
|
51
|
+
const truncateString = (str: string, num: number) => {
|
|
52
|
+
if (str.length <= num) return str;
|
|
53
|
+
return str.slice(0, num) + '...';
|
|
54
|
+
};
|
|
55
|
+
|
|
56
|
+
const handleInternalSubmit = handleSubmit(async (data) => {
|
|
57
|
+
if (onUpdate) {
|
|
58
|
+
const dirtyValues: Partial<T> = {};
|
|
59
|
+
for (const key in dirtyFields) {
|
|
60
|
+
if (dirtyFields[key]) {
|
|
61
|
+
dirtyValues[key as keyof T] = get(data, key);
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
onUpdate(dirtyValues);
|
|
65
|
+
reset(data);
|
|
66
|
+
} else if (onSubmit) {
|
|
67
|
+
onSubmit(data);
|
|
68
|
+
}
|
|
69
|
+
onClose();
|
|
70
|
+
});
|
|
71
|
+
|
|
72
|
+
const handleCancel = () => {
|
|
73
|
+
if (!isDirty) {
|
|
74
|
+
onClose();
|
|
75
|
+
} else {
|
|
76
|
+
modals.openConfirmModal({
|
|
77
|
+
title: t('components.forms.BaseForm.discardChanges'),
|
|
78
|
+
centered: true,
|
|
79
|
+
children: <Text size="sm">{t('components.forms.BaseForm.unsavedChangesWarning')}</Text>,
|
|
80
|
+
labels: { confirm: t('common.confirm'), cancel: t('common.cancel') },
|
|
81
|
+
confirmProps: { color: 'red' },
|
|
82
|
+
zIndex: 10001,
|
|
83
|
+
onConfirm: () => {
|
|
84
|
+
reset();
|
|
85
|
+
onClose();
|
|
86
|
+
},
|
|
87
|
+
});
|
|
88
|
+
}
|
|
89
|
+
};
|
|
90
|
+
|
|
91
|
+
return (
|
|
92
|
+
<Paper
|
|
93
|
+
p="md"
|
|
94
|
+
shadow="sm"
|
|
95
|
+
pos="relative"
|
|
96
|
+
style={{
|
|
97
|
+
display: 'flex',
|
|
98
|
+
flexDirection: 'column',
|
|
99
|
+
border: '1px solid var(--mantine-color-default-border)',
|
|
100
|
+
...style,
|
|
101
|
+
}}
|
|
102
|
+
>
|
|
103
|
+
<LoadingOverlay visible={isSubmitting} overlayProps={{ radius: 'sm', blur: 1 }} />
|
|
104
|
+
<Group justify="space-between" mb="md">
|
|
105
|
+
<Group>
|
|
106
|
+
{icon}
|
|
107
|
+
<Tooltip label={title}>
|
|
108
|
+
<Title order={4}>{truncateString(title, 25)}</Title>
|
|
109
|
+
</Tooltip>
|
|
110
|
+
{titleRight}
|
|
111
|
+
{(!onlyShowEditOnDirty || isDirty) && (
|
|
112
|
+
<ActionIcon
|
|
113
|
+
radius="xl"
|
|
114
|
+
variant={isDirty ? 'filled' : 'subtle'}
|
|
115
|
+
color={isDirty ? 'green' : 'gray'}
|
|
116
|
+
onClick={handleInternalSubmit}
|
|
117
|
+
style={{
|
|
118
|
+
cursor: isDirty ? 'pointer' : 'not-allowed',
|
|
119
|
+
opacity: isDirty ? 1 : 0.5,
|
|
120
|
+
}}
|
|
121
|
+
disabled={!isDirty && !isSubmitting}
|
|
122
|
+
>
|
|
123
|
+
<CheckCircleIcon style={{ width: 16, height: 16 }} />
|
|
124
|
+
</ActionIcon>
|
|
125
|
+
)}
|
|
126
|
+
</Group>
|
|
127
|
+
{exitButton ? (exitButton) : (
|
|
128
|
+
<ActionIcon color="red" onClick={handleCancel}>
|
|
129
|
+
<XMarkIcon style={{ width: 16, height: 16 }} />
|
|
130
|
+
</ActionIcon>
|
|
131
|
+
)}
|
|
132
|
+
</Group>
|
|
133
|
+
<FormProvider {...methods}>
|
|
134
|
+
<form onSubmit={handleInternalSubmit}>{children(methods)}</form>
|
|
135
|
+
</FormProvider>
|
|
136
|
+
</Paper>
|
|
137
|
+
);
|
|
138
|
+
}
|
|
@@ -0,0 +1,131 @@
|
|
|
1
|
+
import { Button, Group, NumberInput, Select, Stack, Switch, Text, TextInput } from '@mantine/core';
|
|
2
|
+
import { useTranslation } from 'react-i18next';
|
|
3
|
+
import { randomId } from '@mantine/hooks';
|
|
4
|
+
|
|
5
|
+
interface Props {
|
|
6
|
+
value: Record<string, any>;
|
|
7
|
+
onChange: (value: Record<string, any>) => void;
|
|
8
|
+
isEditing?: boolean;
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
export const EditableAttributes: React.FC<Props> = ({ value, onChange, isEditing }) => {
|
|
12
|
+
const { t } = useTranslation();
|
|
13
|
+
|
|
14
|
+
const handleAdd = () => {
|
|
15
|
+
onChange({ ...value, [randomId()]: { key: '', value: '', type: 'text' } });
|
|
16
|
+
};
|
|
17
|
+
|
|
18
|
+
const handleKeyChange = (id: string, newKey: string) => {
|
|
19
|
+
onChange({ ...value, [id]: { ...value[id], key: newKey } });
|
|
20
|
+
};
|
|
21
|
+
|
|
22
|
+
const handleValueChange = (id: string, newValue: any) => {
|
|
23
|
+
onChange({ ...value, [id]: { ...value[id], value: newValue } });
|
|
24
|
+
};
|
|
25
|
+
|
|
26
|
+
const handleTypeChange = (id: string, newType: 'text' | 'number' | 'toggle') => {
|
|
27
|
+
let defaultValue: any = '';
|
|
28
|
+
if (newType === 'number') {
|
|
29
|
+
defaultValue = 0;
|
|
30
|
+
} else if (newType === 'toggle') {
|
|
31
|
+
defaultValue = false;
|
|
32
|
+
}
|
|
33
|
+
onChange({ ...value, [id]: { ...(value[id] || {}), type: newType, value: defaultValue } });
|
|
34
|
+
};
|
|
35
|
+
|
|
36
|
+
const handleRemove = (id: string) => {
|
|
37
|
+
const { [id]: _, ...rest } = value;
|
|
38
|
+
onChange(rest);
|
|
39
|
+
};
|
|
40
|
+
|
|
41
|
+
if (!isEditing) {
|
|
42
|
+
return (
|
|
43
|
+
<Stack gap="xs">
|
|
44
|
+
{Object.entries(value)
|
|
45
|
+
.filter(
|
|
46
|
+
([key, val]) =>
|
|
47
|
+
key !== 'icon_color' && val !== null && typeof val === 'object' && 'key' in val,
|
|
48
|
+
)
|
|
49
|
+
.map(([id, val]: [string, any]) => (
|
|
50
|
+
<Group key={id} gap="xs">
|
|
51
|
+
<Text size="sm" fw={500}>
|
|
52
|
+
{val.key}:
|
|
53
|
+
</Text>
|
|
54
|
+
<Text size="sm">{String(val.value)}</Text>
|
|
55
|
+
</Group>
|
|
56
|
+
))}
|
|
57
|
+
</Stack>
|
|
58
|
+
);
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
return (
|
|
62
|
+
<Stack gap="xs" pb="sm">
|
|
63
|
+
{Object.entries(value)
|
|
64
|
+
.filter(
|
|
65
|
+
([key, val]) =>
|
|
66
|
+
key !== 'icon_color' && val !== null && typeof val === 'object' && 'key' in val,
|
|
67
|
+
)
|
|
68
|
+
.map(([id, val]: [string, any]) => {
|
|
69
|
+
return (
|
|
70
|
+
<Group key={id} gap="xs">
|
|
71
|
+
<TextInput
|
|
72
|
+
w={75}
|
|
73
|
+
value={val.key}
|
|
74
|
+
onChange={(e) => handleKeyChange(id, e.currentTarget.value)}
|
|
75
|
+
placeholder={t('placeholder.key')}
|
|
76
|
+
/>
|
|
77
|
+
<Select
|
|
78
|
+
w={100}
|
|
79
|
+
value={val.type}
|
|
80
|
+
onChange={(newType) => {
|
|
81
|
+
if (newType) {
|
|
82
|
+
handleTypeChange(id, newType as 'text' | 'number' | 'toggle');
|
|
83
|
+
}
|
|
84
|
+
}}
|
|
85
|
+
placeholder={t('placeholder.type')}
|
|
86
|
+
data={[
|
|
87
|
+
{ value: 'text', label: t('common.types.text') },
|
|
88
|
+
{ value: 'number', label: t('common.types.number') },
|
|
89
|
+
{ value: 'toggle', label: t('common.types.toggle') },
|
|
90
|
+
]}
|
|
91
|
+
/>
|
|
92
|
+
{val.type === 'text' && (
|
|
93
|
+
<TextInput
|
|
94
|
+
w={150}
|
|
95
|
+
value={val.value}
|
|
96
|
+
onChange={(e) => handleValueChange(id, e.currentTarget.value)}
|
|
97
|
+
placeholder={t('placeholder.value')}
|
|
98
|
+
/>
|
|
99
|
+
)}
|
|
100
|
+
{val.type === 'number' && (
|
|
101
|
+
<NumberInput
|
|
102
|
+
w={150}
|
|
103
|
+
value={val.value}
|
|
104
|
+
onChange={(v) => handleValueChange(id, v)}
|
|
105
|
+
placeholder={t('placeholder.value')}
|
|
106
|
+
/>
|
|
107
|
+
)}
|
|
108
|
+
{val.type === 'toggle' && (
|
|
109
|
+
<Switch
|
|
110
|
+
w={150}
|
|
111
|
+
checked={val.value}
|
|
112
|
+
onChange={(e) => handleValueChange(id, e.currentTarget.checked)}
|
|
113
|
+
/>
|
|
114
|
+
)}
|
|
115
|
+
<Button color="red" variant="subtle" size="xs" onClick={() => handleRemove(id)}>
|
|
116
|
+
{t('common.remove')}
|
|
117
|
+
</Button>
|
|
118
|
+
</Group>
|
|
119
|
+
);
|
|
120
|
+
})}
|
|
121
|
+
<Button
|
|
122
|
+
onClick={handleAdd}
|
|
123
|
+
size="xs"
|
|
124
|
+
mt="sm"
|
|
125
|
+
disabled={Object.values(value).some((v: any) => v && v.key === '')}
|
|
126
|
+
>
|
|
127
|
+
{t('common.add')}
|
|
128
|
+
</Button>
|
|
129
|
+
</Stack>
|
|
130
|
+
);
|
|
131
|
+
};
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
import { useState, type PropsWithChildren, type CSSProperties } from "react";
|
|
2
|
+
import type { Event, Source, Permissive } from "omni-osint-crud-client";
|
|
3
|
+
import { EditingForm } from "./EditingForm";
|
|
4
|
+
import { StaticForm } from "./StaticForm";
|
|
5
|
+
|
|
6
|
+
interface Props extends PropsWithChildren {
|
|
7
|
+
event: Event;
|
|
8
|
+
sources?: Source[];
|
|
9
|
+
isAdmin?: boolean;
|
|
10
|
+
onSubmit?: (data: Event) => void;
|
|
11
|
+
onUpdate?: (data: Partial<Event>) => void;
|
|
12
|
+
onUpdatePermissive?: (data: Permissive) => void;
|
|
13
|
+
onClose?: () => void;
|
|
14
|
+
exitButton?: React.ReactNode;
|
|
15
|
+
style?: CSSProperties;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
export const EventForm: React.FC<Props> = ({
|
|
19
|
+
event,
|
|
20
|
+
sources = [],
|
|
21
|
+
isAdmin = false,
|
|
22
|
+
onSubmit,
|
|
23
|
+
onUpdate,
|
|
24
|
+
onUpdatePermissive,
|
|
25
|
+
onClose,
|
|
26
|
+
exitButton,
|
|
27
|
+
children,
|
|
28
|
+
style,
|
|
29
|
+
}) => {
|
|
30
|
+
const [isEditing, setIsEditing] = useState(onSubmit !== undefined || false);
|
|
31
|
+
|
|
32
|
+
if (
|
|
33
|
+
onSubmit !== undefined &&
|
|
34
|
+
(onUpdate !== undefined || onUpdatePermissive !== undefined)
|
|
35
|
+
) {
|
|
36
|
+
throw new Error(
|
|
37
|
+
"onSubmit cannot be defined at the same time with onUpdate or onUpdatePermissive",
|
|
38
|
+
);
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
const handlClose = () => {
|
|
42
|
+
if (onUpdate !== undefined) {
|
|
43
|
+
setIsEditing(false);
|
|
44
|
+
}
|
|
45
|
+
onClose?.();
|
|
46
|
+
};
|
|
47
|
+
|
|
48
|
+
const handleDoubleClick = () => {
|
|
49
|
+
if (onUpdate !== undefined) {
|
|
50
|
+
setIsEditing(true);
|
|
51
|
+
}
|
|
52
|
+
};
|
|
53
|
+
|
|
54
|
+
return isEditing ? (
|
|
55
|
+
<EditingForm
|
|
56
|
+
event={event}
|
|
57
|
+
sources={sources}
|
|
58
|
+
onSubmit={onSubmit}
|
|
59
|
+
onUpdate={onUpdate}
|
|
60
|
+
onClose={handlClose}
|
|
61
|
+
children={children}
|
|
62
|
+
style={style}
|
|
63
|
+
/>
|
|
64
|
+
) : (
|
|
65
|
+
<StaticForm
|
|
66
|
+
event={event}
|
|
67
|
+
sources={sources}
|
|
68
|
+
isAdmin={isAdmin}
|
|
69
|
+
onUpdate={onUpdatePermissive}
|
|
70
|
+
onClose={handlClose}
|
|
71
|
+
onDoubleClick={handleDoubleClick}
|
|
72
|
+
editModeEnabled={onUpdate !== undefined}
|
|
73
|
+
exitButton={exitButton || <></>}
|
|
74
|
+
children={children}
|
|
75
|
+
style={style}
|
|
76
|
+
/>
|
|
77
|
+
);
|
|
78
|
+
};
|