@omnsight/osint-entity-components 0.1.4 → 0.2.1

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.
@@ -0,0 +1,2 @@
1
+ .entity-avatar{border:2px solid var(--mantine-color-body);transition:all .2s}.entity-avatar:hover{transform:scale(1.25);box-shadow:0 4px 8px #0003;z-index:100!important}
2
+ /*$vite$:1*/
package/package.json CHANGED
@@ -3,7 +3,7 @@
3
3
  "publishConfig": {
4
4
  "access": "public"
5
5
  },
6
- "version": "0.1.4",
6
+ "version": "0.2.1",
7
7
  "engines": {
8
8
  "node": ">=24.0.0"
9
9
  },
@@ -54,9 +54,11 @@
54
54
  "@mantine/hooks": "^8.3.18",
55
55
  "@svgr/plugin-jsx": "^8.1.0",
56
56
  "@svgr/plugin-svgo": "^8.1.0",
57
+ "omni-monitoring-client": "latest",
57
58
  "omni-osint-crud-client": "latest",
58
59
  "react": "^19.2.4",
59
60
  "react-dom": "^19.2.4",
61
+ "react-hook-form": "^7.72.0",
60
62
  "react-i18next": "^16.6.6"
61
63
  },
62
64
  "devDependencies": {
package/src/App.tsx CHANGED
@@ -42,12 +42,14 @@ import type {
42
42
  Website,
43
43
  Relation,
44
44
  } from "omni-osint-crud-client";
45
+ import type { MonitoringSource } from "omni-monitoring-client";
45
46
  import {
46
47
  EventCard,
47
48
  OrganizationCard,
48
49
  PersonCard,
49
50
  SourceCard,
50
51
  WebsiteCard,
52
+ MonitoringSourceCard,
51
53
  } from "./cards";
52
54
  import { ArrowRightIcon } from "@heroicons/react/24/solid";
53
55
 
@@ -87,6 +89,13 @@ function App() {
87
89
  description: "An example website.",
88
90
  tags: ["website", "example"],
89
91
  });
92
+ const [monitoringSource] = useState<MonitoringSource>({
93
+ name: "Test Monitoring Source",
94
+ description:
95
+ "This is a test description for the monitoring source card. It should truncate after a certain point to avoid overflowing the card.",
96
+ reliability: 75,
97
+ owner: "test-owner",
98
+ });
90
99
  const [relation] = useState<Relation>({
91
100
  _id: "relation-1",
92
101
  _from: "person-1",
@@ -112,7 +121,13 @@ function App() {
112
121
  >
113
122
  Toggle Language
114
123
  </Button>
115
- <Button onClick={() => setColorScheme(colorScheme === "dark" ? "light" : "dark")}>Toggle Theme</Button>
124
+ <Button
125
+ onClick={() =>
126
+ setColorScheme(colorScheme === "dark" ? "light" : "dark")
127
+ }
128
+ >
129
+ Toggle Theme
130
+ </Button>
116
131
  </Group>
117
132
  <ScrollArea style={{ height: "100vh" }}>
118
133
  <SimpleGrid
@@ -233,9 +248,14 @@ function App() {
233
248
  <OrganizationCard organization={{}} />
234
249
  <SourceCard source={{}} />
235
250
  <WebsiteCard website={{}} />
251
+ <MonitoringSourceCard monitoringSource={{ owner: "" }} />
236
252
  </Stack>
237
253
  </ScrollArea>
238
254
  </Card>
255
+
256
+ <Card withBorder style={cardStyle}>
257
+ <MonitoringSourceCard monitoringSource={monitoringSource} />
258
+ </Card>
239
259
  </SimpleGrid>
240
260
  </ScrollArea>
241
261
  </>
@@ -1,4 +1,4 @@
1
- import { Badge, Group, Paper, Stack, Text, Title } from "@mantine/core";
1
+ import { Badge, Group, Paper, ScrollArea, Stack, Text, Title } from "@mantine/core";
2
2
  import { type Event } from "omni-osint-crud-client";
3
3
  import { useTranslation } from "react-i18next";
4
4
  import React from "react";
@@ -22,15 +22,17 @@ export const EventCard: React.FC<Props> = ({
22
22
  <Paper p="xs" bg={background} withBorder={withBorder}>
23
23
  <Group justify="space-between" wrap="nowrap" align="flex-start">
24
24
  <Stack gap={0}>
25
- <Title>{event.title || t("event.title")}</Title>
25
+ <Title order={2}>{event.title || t("event.title")}</Title>
26
26
  {event.happened_at && (
27
27
  <Text c="dimmed">
28
28
  {new Date(event.happened_at * 1000).toLocaleString()}
29
29
  </Text>
30
30
  )}
31
- <Text truncate="end">
32
- {event.description || t("event.description")}
33
- </Text>
31
+ <ScrollArea h={50} type="auto" offsetScrollbars>
32
+ <Text>
33
+ {event.description || t("event.description")}
34
+ </Text>
35
+ </ScrollArea>
34
36
  {event.tags && (
35
37
  <Group gap="xs" mt="xs">
36
38
  {event.tags.map((tag) => (
@@ -0,0 +1,61 @@
1
+ import { Group, Paper, RingProgress, Stack, Text, Title, ScrollArea } from "@mantine/core";
2
+ import { type MonitoringSource } from "omni-monitoring-client";
3
+ import { useTranslation } from "react-i18next";
4
+ import React from "react";
5
+
6
+ interface Props {
7
+ monitoringSource: MonitoringSource;
8
+ background?: string;
9
+ withBorder?: boolean;
10
+ action?: React.ReactNode;
11
+ }
12
+
13
+ export const MonitoringSourceCard: React.FC<Props> = ({
14
+ monitoringSource,
15
+ background,
16
+ withBorder = true,
17
+ action,
18
+ }) => {
19
+ const { t } = useTranslation();
20
+
21
+ const reliability = monitoringSource.reliability || 0;
22
+ const color = reliability < 50 ? "red" : reliability < 80 ? "yellow" : "green";
23
+
24
+ return (
25
+ <Paper p="xs" bg={background} withBorder={withBorder}>
26
+ <Group justify="space-between" wrap="nowrap" align="flex-start">
27
+ <Stack gap={0}>
28
+ <Group>
29
+ <Title order={2}>
30
+ {monitoringSource.name || t("monitoringSource.name")}
31
+ </Title>
32
+ {monitoringSource.reliability && (
33
+ <RingProgress
34
+ size={36}
35
+ thickness={3}
36
+ roundCaps
37
+ sections={[{ value: reliability, color }]}
38
+ label={
39
+ <Text c={color} fw={700} ta="center" size="xs" style={{ fontSize: 9 }}>
40
+ {`${reliability}%`}
41
+ </Text>
42
+ }
43
+ />
44
+ )}
45
+ </Group>
46
+ {monitoringSource.type && (
47
+ <Text c="dimmed">
48
+ {monitoringSource.type || t("monitoringSource.type")}
49
+ </Text>
50
+ )}
51
+ <ScrollArea h={50} type="auto" offsetScrollbars>
52
+ <Text>
53
+ {monitoringSource.description || t("monitoringSource.description")}
54
+ </Text>
55
+ </ScrollArea>
56
+ </Stack>
57
+ {action}
58
+ </Group>
59
+ </Paper>
60
+ );
61
+ };
@@ -22,7 +22,7 @@ export const OrganizationCard: React.FC<Props> = ({
22
22
  <Paper withBorder={withBorder} p="xs" bg={background}>
23
23
  <Group justify="space-between" wrap="nowrap" align="flex-start">
24
24
  <Stack gap={0}>
25
- <Title>{organization.name || t("organization.name")}</Title>
25
+ <Title order={2}>{organization.name || t("organization.name")}</Title>
26
26
  {organization.tags && (
27
27
  <Group gap="xs" mt="xs">
28
28
  {organization.tags.map((tag) => (
@@ -22,7 +22,7 @@ export const PersonCard: React.FC<Props> = ({
22
22
  <Paper withBorder={withBorder} p="xs" bg={background}>
23
23
  <Group justify="space-between" wrap="nowrap" align="flex-start">
24
24
  <Stack gap={0}>
25
- <Title>{person.name || t("person.name")}</Title>
25
+ <Title order={2}>{person.name || t("person.name")}</Title>
26
26
  {person.role && (
27
27
  <Text c="dimmed">{person.role || t("person.role")}</Text>
28
28
  )}
@@ -3,6 +3,7 @@ import {
3
3
  Badge,
4
4
  Group,
5
5
  Paper,
6
+ ScrollArea,
6
7
  Stack,
7
8
  Text,
8
9
  Title,
@@ -32,7 +33,7 @@ export const SourceCard: React.FC<Props> = ({
32
33
  <Group justify="space-between" wrap="nowrap" align="flex-start">
33
34
  <Stack gap={0}>
34
35
  <Group>
35
- <Title>{source.name || t("source.name")}</Title>
36
+ <Title order={2}>{source.name || t("source.name")}</Title>
36
37
  {source.url && (
37
38
  <ActionIcon
38
39
  variant="subtle"
@@ -45,9 +46,11 @@ export const SourceCard: React.FC<Props> = ({
45
46
  </ActionIcon>
46
47
  )}
47
48
  </Group>
48
- <Text truncate="end">
49
- {source.description || t("source.description")}
50
- </Text>
49
+ <ScrollArea h={50} type="auto" offsetScrollbars>
50
+ <Text>
51
+ {source.description || t("source.description")}
52
+ </Text>
53
+ </ScrollArea>
51
54
  {source.tags && (
52
55
  <Group gap="xs" mt="xs">
53
56
  {source.tags.map((tag) => (
@@ -3,6 +3,7 @@ import {
3
3
  Badge,
4
4
  Group,
5
5
  Paper,
6
+ ScrollArea,
6
7
  Stack,
7
8
  Text,
8
9
  Title,
@@ -32,7 +33,7 @@ export const WebsiteCard: React.FC<Props> = ({
32
33
  <Group justify="space-between" wrap="nowrap" align="flex-start">
33
34
  <Stack gap={0}>
34
35
  <Group>
35
- <Title>{website.title || t("website.title")}</Title>
36
+ <Title order={2}>{website.title || t("website.title")}</Title>
36
37
  {website.url && (
37
38
  <ActionIcon
38
39
  variant="subtle"
@@ -45,9 +46,11 @@ export const WebsiteCard: React.FC<Props> = ({
45
46
  </ActionIcon>
46
47
  )}
47
48
  </Group>
48
- <Text truncate="end">
49
- {website.description || t("website.description")}
50
- </Text>
49
+ <ScrollArea h={50} type="auto" offsetScrollbars>
50
+ <Text>
51
+ {website.description || t("website.description")}
52
+ </Text>
53
+ </ScrollArea>
51
54
  {website.tags && (
52
55
  <Group gap="xs" mt="xs">
53
56
  {website.tags.map((tag) => (
@@ -3,3 +3,4 @@ export * from './PersonCard';
3
3
  export * from './OrganizationCard';
4
4
  export * from './WebsiteCard';
5
5
  export * from './SourceCard';
6
+ export * from './MonittoringSourceCard';
@@ -26,7 +26,7 @@ export const EventIconSelector: React.FC<EventIconSelectorProps> = ({
26
26
  <Select
27
27
  leftSection={<EventIcon event={data} />}
28
28
  defaultValue={translatedOptions[0].value}
29
- value={value}
29
+ value={value ?? ""}
30
30
  onChange={onChange}
31
31
  data={translatedOptions}
32
32
  style={{ flex: 1 }}
@@ -55,7 +55,8 @@ export const EventColorSelector: React.FC<EventColorSelectorProps> = ({
55
55
 
56
56
  return (
57
57
  <ColorInput
58
- value={value || colors[0]}
58
+ defaultValue={colors[0]}
59
+ value={value ?? ""}
59
60
  onChange={onChange}
60
61
  swatches={colors}
61
62
  style={{ flex: 1 }}
@@ -90,7 +91,7 @@ export const EventIconSelect: React.FC<EventIconSelectProps> = ({
90
91
  value={value.type}
91
92
  onChange={handleTypeChange}
92
93
  />
93
- <EventColorSelector
94
+ <EventColorSelector
94
95
  value={String(value.attributes?.icon_color)}
95
96
  onChange={handleColorChange}
96
97
  />
@@ -24,7 +24,7 @@ export const OrganizationIconSelector: React.FC<
24
24
  <Select
25
25
  leftSection={<OrganizationIcon organization={data} />}
26
26
  defaultValue={translatedOptions[0].value}
27
- value={value}
27
+ value={value ?? ""}
28
28
  onChange={onChange}
29
29
  data={translatedOptions}
30
30
  style={{ flex: 1 }}
@@ -52,7 +52,8 @@ export const OrganizationColorSelector: React.FC<
52
52
 
53
53
  return (
54
54
  <ColorInput
55
- value={value || colors[0]}
55
+ defaultValue={colors[0]}
56
+ value={value ?? ""}
56
57
  onChange={onChange}
57
58
  swatches={colors}
58
59
  style={{ flex: 1 }}
@@ -1,8 +1,8 @@
1
- import { type Person } from 'omni-osint-crud-client';
2
- import { useTranslation } from 'react-i18next';
3
- import { Group, Select, ColorInput } from '@mantine/core';
4
- import { ICON_OPTIONS } from './icons';
5
- import { PersonIcon } from './Icon';
1
+ import { type Person } from "omni-osint-crud-client";
2
+ import { useTranslation } from "react-i18next";
3
+ import { Group, Select, ColorInput } from "@mantine/core";
4
+ import { ICON_OPTIONS } from "./icons";
5
+ import { PersonIcon } from "./Icon";
6
6
 
7
7
  interface PersonIconSelectorProps {
8
8
  data: Person;
@@ -26,7 +26,7 @@ export const PersonIconSelector: React.FC<PersonIconSelectorProps> = ({
26
26
  <Select
27
27
  leftSection={<PersonIcon person={data} />}
28
28
  defaultValue={translatedOptions[0].value}
29
- value={value}
29
+ value={value ?? ""}
30
30
  onChange={onChange}
31
31
  data={translatedOptions}
32
32
  style={{ flex: 1 }}
@@ -55,7 +55,8 @@ export const PersonColorSelector: React.FC<PersonColorSelectorProps> = ({
55
55
 
56
56
  return (
57
57
  <ColorInput
58
- value={value || colors[0]}
58
+ defaultValue={colors[0]}
59
+ value={value ?? ""}
59
60
  onChange={onChange}
60
61
  swatches={colors}
61
62
  style={{ flex: 1 }}
@@ -26,7 +26,7 @@ export const SourceIconSelector: React.FC<SourceIconSelectorProps> = ({
26
26
  <Select
27
27
  leftSection={<SourceIcon source={data} />}
28
28
  defaultValue={translatedOptions[0].value}
29
- value={value}
29
+ value={value ?? ""}
30
30
  onChange={onChange}
31
31
  data={translatedOptions}
32
32
  style={{ flex: 1 }}
@@ -55,7 +55,8 @@ export const SourceColorSelector: React.FC<SourceColorSelectorProps> = ({
55
55
 
56
56
  return (
57
57
  <ColorInput
58
- value={value || colors[0]}
58
+ defaultValue={colors[0]}
59
+ value={value ?? ""}
59
60
  onChange={onChange}
60
61
  swatches={colors}
61
62
  style={{ flex: 1 }}
@@ -91,7 +92,7 @@ export const SourceIconSelect: React.FC<SourceIconSelectProps> = ({
91
92
  onChange={handleTypeChange}
92
93
  />
93
94
  <SourceColorSelector
94
- value={String(value.attributes?.icon_color)}
95
+ value={String(value.attributes?.icon_color ?? "")}
95
96
  onChange={handleColorChange}
96
97
  />
97
98
  </Group>
@@ -26,7 +26,7 @@ export const WebsiteIconSelector: React.FC<WebsiteIconSelectorProps> = ({
26
26
  <Select
27
27
  leftSection={<WebsiteIcon website={data} />}
28
28
  defaultValue={translatedOptions[0].value}
29
- value={value}
29
+ value={value ?? ""}
30
30
  onChange={onChange}
31
31
  data={translatedOptions}
32
32
  style={{ flex: 1 }}
@@ -55,7 +55,8 @@ export const WebsiteColorSelector: React.FC<WebsiteColorSelectorProps> = ({
55
55
 
56
56
  return (
57
57
  <ColorInput
58
- value={value || colors[0]}
58
+ defaultValue={colors[0]}
59
+ value={value ?? ""}
59
60
  onChange={onChange}
60
61
  swatches={colors}
61
62
  style={{ flex: 1 }}
@@ -66,6 +66,11 @@
66
66
  "title": "Title",
67
67
  "description": "Description"
68
68
  },
69
+ "monitoringSource": {
70
+ "name": "Name",
71
+ "type": "Type",
72
+ "description": "Description"
73
+ },
69
74
  "tooltip": {
70
75
  "relation": "Related",
71
76
  "confidence": "Confidence",
@@ -65,7 +65,11 @@
65
65
  },
66
66
  "title": "标题",
67
67
  "description": "描述"
68
-
68
+ },
69
+ "monitoringSource": {
70
+ "name": "名称",
71
+ "type": "类型",
72
+ "description": "描述"
69
73
  },
70
74
  "tooltip": {
71
75
  "relation": "相关",