@oneuptime/common 7.0.4676 → 7.0.4707
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/Server/Middleware/ProjectAuthorization.ts +31 -29
- package/Server/Services/StatusPageService.ts +1 -1
- package/Tests/UI/Components/NavBar.test.tsx +12 -3
- package/UI/Components/ActionButton/ActionButtonSchema.ts +1 -0
- package/UI/Components/Banner/Banner.tsx +4 -1
- package/UI/Components/Breadcrumbs/Breadcrumbs.tsx +1 -1
- package/UI/Components/Card/Card.tsx +57 -46
- package/UI/Components/Detail/Detail.tsx +22 -1
- package/UI/Components/Detail/Field.ts +1 -0
- package/UI/Components/EventHistoryList/EventHistoryDayList.tsx +32 -25
- package/UI/Components/Feed/FeedItem.tsx +1 -1
- package/UI/Components/Footer/Footer.tsx +1 -1
- package/UI/Components/Forms/BasicForm.tsx +4 -1
- package/UI/Components/Icon/Icon.tsx +5 -3
- package/UI/Components/List/ListRow.tsx +22 -1
- package/UI/Components/ModelTable/BaseModelTable.tsx +2 -0
- package/UI/Components/ModelTable/Column.ts +1 -0
- package/UI/Components/Navbar/NavBar.tsx +309 -7
- package/UI/Components/OrderedStatesList/Item.tsx +22 -1
- package/UI/Components/Page/Page.tsx +2 -2
- package/UI/Components/Pagination/Pagination.tsx +1 -1
- package/UI/Components/SideMenu/SideMenu.tsx +289 -13
- package/UI/Components/SideMenu/SideMenuSection.tsx +2 -2
- package/UI/Components/Table/TableHeader.tsx +73 -53
- package/UI/Components/Table/TableRow.tsx +174 -148
- package/UI/Components/Table/Types/Column.ts +1 -0
- package/build/dist/Server/Middleware/ProjectAuthorization.js +19 -17
- package/build/dist/Server/Middleware/ProjectAuthorization.js.map +1 -1
- package/build/dist/Server/Services/StatusPageService.js +2 -1
- package/build/dist/Server/Services/StatusPageService.js.map +1 -1
- package/build/dist/Tests/UI/Components/NavBar.test.js +8 -1
- package/build/dist/Tests/UI/Components/NavBar.test.js.map +1 -1
- package/build/dist/UI/Components/Banner/Banner.js +1 -1
- package/build/dist/UI/Components/Banner/Banner.js.map +1 -1
- package/build/dist/UI/Components/Breadcrumbs/Breadcrumbs.js +1 -1
- package/build/dist/UI/Components/Breadcrumbs/Breadcrumbs.js.map +1 -1
- package/build/dist/UI/Components/Card/Card.js +9 -13
- package/build/dist/UI/Components/Card/Card.js.map +1 -1
- package/build/dist/UI/Components/Detail/Detail.js +17 -1
- package/build/dist/UI/Components/Detail/Detail.js.map +1 -1
- package/build/dist/UI/Components/EventHistoryList/EventHistoryDayList.js +2 -2
- package/build/dist/UI/Components/EventHistoryList/EventHistoryDayList.js.map +1 -1
- package/build/dist/UI/Components/Feed/FeedItem.js +1 -1
- package/build/dist/UI/Components/Feed/FeedItem.js.map +1 -1
- package/build/dist/UI/Components/Footer/Footer.js +1 -1
- package/build/dist/UI/Components/Footer/Footer.js.map +1 -1
- package/build/dist/UI/Components/Forms/BasicForm.js +1 -1
- package/build/dist/UI/Components/Forms/BasicForm.js.map +1 -1
- package/build/dist/UI/Components/Icon/Icon.js.map +1 -1
- package/build/dist/UI/Components/List/ListRow.js +17 -1
- package/build/dist/UI/Components/List/ListRow.js.map +1 -1
- package/build/dist/UI/Components/ModelTable/BaseModelTable.js +2 -0
- package/build/dist/UI/Components/ModelTable/BaseModelTable.js.map +1 -1
- package/build/dist/UI/Components/Navbar/NavBar.js +134 -4
- package/build/dist/UI/Components/Navbar/NavBar.js.map +1 -1
- package/build/dist/UI/Components/OrderedStatesList/Item.js +17 -1
- package/build/dist/UI/Components/OrderedStatesList/Item.js.map +1 -1
- package/build/dist/UI/Components/Page/Page.js +2 -2
- package/build/dist/UI/Components/Page/Page.js.map +1 -1
- package/build/dist/UI/Components/Pagination/Pagination.js +1 -1
- package/build/dist/UI/Components/Pagination/Pagination.js.map +1 -1
- package/build/dist/UI/Components/SideMenu/SideMenu.js +125 -11
- package/build/dist/UI/Components/SideMenu/SideMenu.js.map +1 -1
- package/build/dist/UI/Components/SideMenu/SideMenuSection.js +2 -2
- package/build/dist/UI/Components/SideMenu/SideMenuSection.js.map +1 -1
- package/build/dist/UI/Components/Table/TableHeader.js +18 -2
- package/build/dist/UI/Components/Table/TableHeader.js.map +1 -1
- package/build/dist/UI/Components/Table/TableRow.js +24 -3
- package/build/dist/UI/Components/Table/TableRow.js.map +1 -1
- package/package.json +1 -1
|
@@ -96,38 +96,40 @@ export default class ProjectMiddleware {
|
|
|
96
96
|
props: { isRoot: true },
|
|
97
97
|
});
|
|
98
98
|
|
|
99
|
-
tenantId = apiKeyModel?.projectId || null;
|
|
100
|
-
|
|
101
|
-
if (!tenantId) {
|
|
102
|
-
throw new BadDataException("Invalid API Key");
|
|
103
|
-
}
|
|
104
|
-
|
|
105
|
-
(req as OneUptimeRequest).tenantId = tenantId;
|
|
106
|
-
|
|
107
99
|
if (apiKeyModel) {
|
|
108
|
-
|
|
109
|
-
// TODO: Add API key permissions.
|
|
110
|
-
// (req as OneUptimeRequest).permissions =
|
|
111
|
-
// apiKeyModel.permissions || [];
|
|
112
|
-
(req as OneUptimeRequest).userGlobalAccessPermission =
|
|
113
|
-
await APIKeyAccessPermission.getDefaultApiGlobalPermission(
|
|
114
|
-
tenantId,
|
|
115
|
-
);
|
|
116
|
-
|
|
117
|
-
const userTenantAccessPermission: UserTenantAccessPermission | null =
|
|
118
|
-
await APIKeyAccessPermission.getApiTenantAccessPermission(
|
|
119
|
-
tenantId,
|
|
120
|
-
apiKeyModel.id!,
|
|
121
|
-
);
|
|
100
|
+
tenantId = apiKeyModel?.projectId || null;
|
|
122
101
|
|
|
123
|
-
if (
|
|
124
|
-
(
|
|
125
|
-
|
|
126
|
-
(req as OneUptimeRequest)
|
|
127
|
-
.userTenantAccessPermission as Dictionary<UserTenantAccessPermission>
|
|
128
|
-
)[tenantId.toString()] = userTenantAccessPermission;
|
|
102
|
+
if (!tenantId) {
|
|
103
|
+
throw new BadDataException("Invalid API Key");
|
|
104
|
+
}
|
|
129
105
|
|
|
130
|
-
|
|
106
|
+
(req as OneUptimeRequest).tenantId = tenantId;
|
|
107
|
+
|
|
108
|
+
if (apiKeyModel) {
|
|
109
|
+
(req as OneUptimeRequest).userType = UserType.API;
|
|
110
|
+
// TODO: Add API key permissions.
|
|
111
|
+
// (req as OneUptimeRequest).permissions =
|
|
112
|
+
// apiKeyModel.permissions || [];
|
|
113
|
+
(req as OneUptimeRequest).userGlobalAccessPermission =
|
|
114
|
+
await APIKeyAccessPermission.getDefaultApiGlobalPermission(
|
|
115
|
+
tenantId,
|
|
116
|
+
);
|
|
117
|
+
|
|
118
|
+
const userTenantAccessPermission: UserTenantAccessPermission | null =
|
|
119
|
+
await APIKeyAccessPermission.getApiTenantAccessPermission(
|
|
120
|
+
tenantId,
|
|
121
|
+
apiKeyModel.id!,
|
|
122
|
+
);
|
|
123
|
+
|
|
124
|
+
if (userTenantAccessPermission) {
|
|
125
|
+
(req as OneUptimeRequest).userTenantAccessPermission = {};
|
|
126
|
+
(
|
|
127
|
+
(req as OneUptimeRequest)
|
|
128
|
+
.userTenantAccessPermission as Dictionary<UserTenantAccessPermission>
|
|
129
|
+
)[tenantId.toString()] = userTenantAccessPermission;
|
|
130
|
+
|
|
131
|
+
return next();
|
|
132
|
+
}
|
|
131
133
|
}
|
|
132
134
|
}
|
|
133
135
|
}
|
|
@@ -157,7 +157,7 @@ export class Service extends DatabaseService<StatusPage> {
|
|
|
157
157
|
if (!createBy.data.subscriberEmailNotificationFooterText) {
|
|
158
158
|
createBy.data.subscriberEmailNotificationFooterText =
|
|
159
159
|
"This is an automated email sent to you because you are subscribed to " +
|
|
160
|
-
createBy.data.name;
|
|
160
|
+
(createBy.data?.pageTitle || createBy.data?.name || "Status Page");
|
|
161
161
|
}
|
|
162
162
|
|
|
163
163
|
return {
|
|
@@ -1,9 +1,13 @@
|
|
|
1
|
-
import Navbar, {
|
|
1
|
+
import Navbar, {
|
|
2
|
+
ComponentProps,
|
|
3
|
+
NavItem,
|
|
4
|
+
} from "../../../UI/Components/Navbar/NavBar";
|
|
2
5
|
import { describe, expect, it } from "@jest/globals";
|
|
3
6
|
import "@testing-library/jest-dom/extend-expect";
|
|
4
7
|
import { render, screen } from "@testing-library/react";
|
|
5
8
|
import React from "react";
|
|
6
|
-
import
|
|
9
|
+
import Route from "../../../Types/API/Route";
|
|
10
|
+
import IconProp from "../../../Types/Icon/IconProp";
|
|
7
11
|
|
|
8
12
|
describe("Navbar", () => {
|
|
9
13
|
const defaultProps: ComponentProps = {
|
|
@@ -26,7 +30,12 @@ describe("Navbar", () => {
|
|
|
26
30
|
});
|
|
27
31
|
|
|
28
32
|
it("renders with a rightElement", () => {
|
|
29
|
-
const rightElement:
|
|
33
|
+
const rightElement: NavItem = {
|
|
34
|
+
id: "test-right-element",
|
|
35
|
+
title: "Right Element",
|
|
36
|
+
icon: IconProp.User,
|
|
37
|
+
route: new Route("/test"),
|
|
38
|
+
};
|
|
30
39
|
const customProps: ComponentProps = { ...defaultProps, rightElement };
|
|
31
40
|
render(<Navbar {...customProps} />);
|
|
32
41
|
expect(screen.getByText("Right Element")).toBeInTheDocument();
|
|
@@ -9,6 +9,7 @@ interface ActionButtonSchema<T extends GenericObject> {
|
|
|
9
9
|
buttonStyleType: ButtonStyleType;
|
|
10
10
|
isLoading?: boolean | undefined;
|
|
11
11
|
isVisible?: (item: T) => boolean | undefined;
|
|
12
|
+
hideOnMobile?: boolean | undefined;
|
|
12
13
|
onClick: (
|
|
13
14
|
item: T,
|
|
14
15
|
onCompleteAction: VoidFunction,
|
|
@@ -9,6 +9,7 @@ export interface ComponentProps {
|
|
|
9
9
|
description: string;
|
|
10
10
|
link?: URL | Route | undefined;
|
|
11
11
|
openInNewTab?: boolean | undefined;
|
|
12
|
+
hideOnMobile?: boolean | undefined;
|
|
12
13
|
}
|
|
13
14
|
|
|
14
15
|
const Banner: FunctionComponent<ComponentProps> = (
|
|
@@ -32,7 +33,9 @@ const Banner: FunctionComponent<ComponentProps> = (
|
|
|
32
33
|
};
|
|
33
34
|
|
|
34
35
|
return (
|
|
35
|
-
<div
|
|
36
|
+
<div
|
|
37
|
+
className={`flex border-gray-200 rounded-xl border-2 py-2.5 px-6 sm:px-3.5${props.hideOnMobile ? " hidden md:flex" : ""}`}
|
|
38
|
+
>
|
|
36
39
|
<p className="text-sm text-gray-400 hover:text-gray-500">
|
|
37
40
|
{props.link && (
|
|
38
41
|
<Link to={props.link} openInNewTab={props.openInNewTab}>
|
|
@@ -14,7 +14,7 @@ const Breadcrumbs: FunctionComponent<ComponentProps> = ({
|
|
|
14
14
|
links,
|
|
15
15
|
}: ComponentProps): ReactElement => {
|
|
16
16
|
return (
|
|
17
|
-
<nav className="flex" aria-label="Breadcrumb">
|
|
17
|
+
<nav className="flex hidden md:block" aria-label="Breadcrumb">
|
|
18
18
|
<ol role="list" className="flex items-center space-x-1">
|
|
19
19
|
{links &&
|
|
20
20
|
links.length > 0 &&
|
|
@@ -33,9 +33,9 @@ const Card: FunctionComponent<ComponentProps> = (
|
|
|
33
33
|
return (
|
|
34
34
|
<React.Fragment>
|
|
35
35
|
<div data-testid="card" className={props.className}>
|
|
36
|
-
<div className="shadow
|
|
37
|
-
<div className="bg-white py-6 px-4
|
|
38
|
-
<div className="flex justify-between">
|
|
36
|
+
<div className="shadow md:rounded-md">
|
|
37
|
+
<div className="bg-white py-6 px-4 md:p-6">
|
|
38
|
+
<div className="flex flex-col md:flex-row md:justify-between">
|
|
39
39
|
<div className={`${noRightElementsOrButtons ? "w-full" : ""}`}>
|
|
40
40
|
{props.title && (
|
|
41
41
|
<h2
|
|
@@ -55,49 +55,60 @@ const Card: FunctionComponent<ComponentProps> = (
|
|
|
55
55
|
</p>
|
|
56
56
|
)}
|
|
57
57
|
</div>
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
58
|
+
{(props.rightElement ||
|
|
59
|
+
(props.buttons && props.buttons.length > 0)) && (
|
|
60
|
+
<div className="flex flex-col md:flex-row md:w-fit mt-4 md:mt-0 gap-2 md:gap-0">
|
|
61
|
+
{props.rightElement && (
|
|
62
|
+
<div className="mb-2 md:mb-0 md:mr-2">
|
|
63
|
+
{props.rightElement}
|
|
64
|
+
</div>
|
|
65
|
+
)}
|
|
66
|
+
{props.buttons && props.buttons.length > 0 && (
|
|
67
|
+
<div className="flex flex-wrap gap-2 md:gap-0">
|
|
68
|
+
{props.buttons.map(
|
|
69
|
+
(
|
|
70
|
+
button: CardButtonSchema | ReactElement,
|
|
71
|
+
i: number,
|
|
72
|
+
) => {
|
|
73
|
+
return (
|
|
74
|
+
<div className="md:ml-2 first:md:ml-0" key={i}>
|
|
75
|
+
{React.isValidElement(button) ? button : null}
|
|
76
|
+
{React.isValidElement(button) ? null : (
|
|
77
|
+
<Button
|
|
78
|
+
key={i}
|
|
79
|
+
title={(button as CardButtonSchema).title}
|
|
80
|
+
buttonStyle={
|
|
81
|
+
(button as CardButtonSchema).buttonStyle
|
|
82
|
+
}
|
|
83
|
+
className={
|
|
84
|
+
(button as CardButtonSchema).className
|
|
85
|
+
}
|
|
86
|
+
onClick={() => {
|
|
87
|
+
if ((button as CardButtonSchema).onClick) {
|
|
88
|
+
(button as CardButtonSchema).onClick();
|
|
89
|
+
}
|
|
90
|
+
}}
|
|
91
|
+
disabled={
|
|
92
|
+
(button as CardButtonSchema).disabled
|
|
93
|
+
}
|
|
94
|
+
icon={(button as CardButtonSchema).icon}
|
|
95
|
+
shortcutKey={
|
|
96
|
+
(button as CardButtonSchema).shortcutKey
|
|
97
|
+
}
|
|
98
|
+
dataTestId="card-button"
|
|
99
|
+
isLoading={
|
|
100
|
+
(button as CardButtonSchema).isLoading
|
|
101
|
+
}
|
|
102
|
+
/>
|
|
103
|
+
)}
|
|
104
|
+
</div>
|
|
105
|
+
);
|
|
106
|
+
},
|
|
107
|
+
)}
|
|
108
|
+
</div>
|
|
109
|
+
)}
|
|
110
|
+
</div>
|
|
111
|
+
)}
|
|
101
112
|
</div>
|
|
102
113
|
|
|
103
114
|
{props.children && (
|
|
@@ -20,7 +20,7 @@ import Dictionary from "../../../Types/Dictionary";
|
|
|
20
20
|
import BadDataException from "../../../Types/Exception/BadDataException";
|
|
21
21
|
import GenericObject from "../../../Types/GenericObject";
|
|
22
22
|
import get from "lodash/get";
|
|
23
|
-
import React, { ReactElement } from "react";
|
|
23
|
+
import React, { ReactElement, useEffect, useState } from "react";
|
|
24
24
|
|
|
25
25
|
export interface ComponentProps<T extends GenericObject> {
|
|
26
26
|
item: T;
|
|
@@ -36,6 +36,22 @@ type DetailFunction = <T extends GenericObject>(
|
|
|
36
36
|
const Detail: DetailFunction = <T extends GenericObject>(
|
|
37
37
|
props: ComponentProps<T>,
|
|
38
38
|
): ReactElement => {
|
|
39
|
+
// Track mobile view for responsive behavior
|
|
40
|
+
const [isMobile, setIsMobile] = useState<boolean>(false);
|
|
41
|
+
|
|
42
|
+
useEffect(() => {
|
|
43
|
+
const checkMobile: () => void = (): void => {
|
|
44
|
+
setIsMobile(window.innerWidth < 768); // md breakpoint
|
|
45
|
+
};
|
|
46
|
+
|
|
47
|
+
checkMobile();
|
|
48
|
+
window.addEventListener("resize", checkMobile);
|
|
49
|
+
|
|
50
|
+
return () => {
|
|
51
|
+
window.removeEventListener("resize", checkMobile);
|
|
52
|
+
};
|
|
53
|
+
}, []);
|
|
54
|
+
|
|
39
55
|
type GetMarkdownViewerFunction = (text: string) => ReactElement;
|
|
40
56
|
|
|
41
57
|
const getMarkdownViewer: GetMarkdownViewerFunction = (
|
|
@@ -410,6 +426,11 @@ const Detail: DetailFunction = <T extends GenericObject>(
|
|
|
410
426
|
props.fields.length > 0 &&
|
|
411
427
|
props.fields
|
|
412
428
|
.filter((field: Field<T>) => {
|
|
429
|
+
// Filter out fields with hideOnMobile on mobile devices
|
|
430
|
+
if (field.hideOnMobile && isMobile) {
|
|
431
|
+
return false;
|
|
432
|
+
}
|
|
433
|
+
|
|
413
434
|
// check if showIf exists.
|
|
414
435
|
if (field.showIf) {
|
|
415
436
|
return field.showIf(props.item);
|
|
@@ -23,6 +23,7 @@ export interface FieldBase<T> {
|
|
|
23
23
|
alignItem?: AlignItem | undefined;
|
|
24
24
|
contentClassName?: string | undefined;
|
|
25
25
|
showIf?: ((item: T) => boolean) | undefined;
|
|
26
|
+
hideOnMobile?: boolean | undefined; // Hide field on mobile devices
|
|
26
27
|
getElement?:
|
|
27
28
|
| ((
|
|
28
29
|
item: T,
|
|
@@ -2,7 +2,12 @@ import EventHistoryItem, {
|
|
|
2
2
|
ComponentProps as ItemComponentProps,
|
|
3
3
|
} from "../EventItem/EventItem";
|
|
4
4
|
import OneUptimeDate from "../../../Types/Date";
|
|
5
|
-
import React, {
|
|
5
|
+
import React, {
|
|
6
|
+
FunctionComponent,
|
|
7
|
+
ReactElement,
|
|
8
|
+
useState,
|
|
9
|
+
useEffect,
|
|
10
|
+
} from "react";
|
|
6
11
|
|
|
7
12
|
export interface ComponentProps {
|
|
8
13
|
date: Date;
|
|
@@ -14,52 +19,54 @@ const EventHistoryDayList: FunctionComponent<ComponentProps> = (
|
|
|
14
19
|
props: ComponentProps,
|
|
15
20
|
): ReactElement => {
|
|
16
21
|
const [windowWidth, setWindowWidth] = useState<number>(
|
|
17
|
-
typeof window !== "undefined" ? window.innerWidth : 1024
|
|
22
|
+
typeof window !== "undefined" ? window.innerWidth : 1024,
|
|
18
23
|
);
|
|
19
24
|
|
|
20
25
|
useEffect(() => {
|
|
21
|
-
const handleResize = () => {
|
|
26
|
+
const handleResize: () => void = (): void => {
|
|
22
27
|
setWindowWidth(window.innerWidth);
|
|
23
28
|
};
|
|
24
29
|
|
|
25
30
|
window.addEventListener("resize", handleResize);
|
|
26
|
-
|
|
31
|
+
|
|
27
32
|
// Cleanup event listener on component unmount
|
|
28
33
|
return () => {
|
|
29
34
|
window.removeEventListener("resize", handleResize);
|
|
30
35
|
};
|
|
31
36
|
}, []);
|
|
32
37
|
|
|
33
|
-
const isMobile = windowWidth <= 768;
|
|
38
|
+
const isMobile: boolean = windowWidth <= 768;
|
|
34
39
|
return (
|
|
35
40
|
<div
|
|
36
41
|
className="md:flex bottom-Gray500-border"
|
|
37
42
|
style={{
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
43
|
+
marginLeft: "-10px",
|
|
44
|
+
marginRight: "-10px",
|
|
45
|
+
marginBottom: props.isLastItem ? "0px" : "20px",
|
|
46
|
+
borderBottomWidth: props.isLastItem ? "0px" : "1px",
|
|
42
47
|
}}
|
|
43
48
|
>
|
|
44
49
|
<div
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
50
|
+
className="text-gray-400 mt-2 text-sm"
|
|
51
|
+
style={{
|
|
52
|
+
padding: "20px",
|
|
53
|
+
paddingLeft: "10px",
|
|
54
|
+
paddingRight: "0px",
|
|
55
|
+
width: isMobile ? "100%" : "15%",
|
|
56
|
+
}}
|
|
52
57
|
>
|
|
53
|
-
|
|
58
|
+
{OneUptimeDate.getDateAsLocalFormattedString(props.date, true)}
|
|
54
59
|
</div>
|
|
55
|
-
<div
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
60
|
+
<div
|
|
61
|
+
style={{
|
|
62
|
+
padding: "10px",
|
|
63
|
+
paddingTop: "0px",
|
|
64
|
+
width: isMobile ? "100%" : "85%",
|
|
65
|
+
}}
|
|
66
|
+
>
|
|
67
|
+
{props.items.map((item: ItemComponentProps, i: number) => {
|
|
68
|
+
return <EventHistoryItem key={i} {...item} />;
|
|
69
|
+
})}
|
|
63
70
|
</div>
|
|
64
71
|
</div>
|
|
65
72
|
);
|
|
@@ -135,7 +135,7 @@ const FeedItem: FunctionComponent<ComponentProps> = (
|
|
|
135
135
|
)}
|
|
136
136
|
{props.element && <div>{props.element}</div>}
|
|
137
137
|
{props.moreTextInMarkdown && (
|
|
138
|
-
<div className="-ml-3">
|
|
138
|
+
<div className="-ml-3 w-fit">
|
|
139
139
|
<Button
|
|
140
140
|
onClick={() => {
|
|
141
141
|
return setShowMoreInformationModal(true);
|
|
@@ -23,7 +23,7 @@ const Footer: FunctionComponent<ComponentProps> = (
|
|
|
23
23
|
return (
|
|
24
24
|
<React.Fragment>
|
|
25
25
|
<footer
|
|
26
|
-
className={props.className || "bg-white h-16
|
|
26
|
+
className={props.className || "bg-white min-h-16"}
|
|
27
27
|
style={props.style}
|
|
28
28
|
>
|
|
29
29
|
<div className="mx-auto w-full py-5 px-6 md:flex md:items-center md:justify-between lg:px-0">
|
|
@@ -592,7 +592,10 @@ const BasicForm: ForwardRefExoticComponent<any> = forwardRef(
|
|
|
592
592
|
|
|
593
593
|
<div className="flex">
|
|
594
594
|
{formSteps && currentFormStepId && (
|
|
595
|
-
<div
|
|
595
|
+
<div
|
|
596
|
+
style={{ flex: "0 1 auto" }}
|
|
597
|
+
className="mr-10 hidden lg:block"
|
|
598
|
+
>
|
|
596
599
|
{/* Form Steps */}
|
|
597
600
|
|
|
598
601
|
<Steps
|
|
@@ -187,9 +187,11 @@ const Icon: FunctionComponent<ComponentProps> = ({
|
|
|
187
187
|
});
|
|
188
188
|
} else if (icon === IconProp.Bars3) {
|
|
189
189
|
return getSvgWrapper(
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
190
|
+
<path
|
|
191
|
+
strokeLinecap="round"
|
|
192
|
+
strokeLinejoin="round"
|
|
193
|
+
d="M3.75 6.75h16.5M3.75 12h16.5m-16.5 5.25h16.5"
|
|
194
|
+
/>,
|
|
193
195
|
);
|
|
194
196
|
} else if (icon === IconProp.ShieldCheck) {
|
|
195
197
|
return getSvgWrapper(
|
|
@@ -6,7 +6,7 @@ import Icon, { ThickProp } from "../Icon/Icon";
|
|
|
6
6
|
import ConfirmModal from "../Modal/ConfirmModal";
|
|
7
7
|
import GenericObject from "../../../Types/GenericObject";
|
|
8
8
|
import IconProp from "../../../Types/Icon/IconProp";
|
|
9
|
-
import React, { ReactElement, useState } from "react";
|
|
9
|
+
import React, { ReactElement, useState, useEffect } from "react";
|
|
10
10
|
import { Draggable, DraggableProvided } from "react-beautiful-dnd";
|
|
11
11
|
|
|
12
12
|
export interface ListDetailProps {
|
|
@@ -39,6 +39,22 @@ const ListRow: ListRowFunction = <T extends GenericObject>(
|
|
|
39
39
|
|
|
40
40
|
const [error, setError] = useState<string>("");
|
|
41
41
|
|
|
42
|
+
// Track mobile view for responsive behavior
|
|
43
|
+
const [isMobile, setIsMobile] = useState<boolean>(false);
|
|
44
|
+
|
|
45
|
+
useEffect(() => {
|
|
46
|
+
const checkMobile: () => void = (): void => {
|
|
47
|
+
setIsMobile(window.innerWidth < 768); // md breakpoint
|
|
48
|
+
};
|
|
49
|
+
|
|
50
|
+
checkMobile();
|
|
51
|
+
window.addEventListener("resize", checkMobile);
|
|
52
|
+
|
|
53
|
+
return () => {
|
|
54
|
+
window.removeEventListener("resize", checkMobile);
|
|
55
|
+
};
|
|
56
|
+
}, []);
|
|
57
|
+
|
|
42
58
|
type GetRowFunction = (provided?: DraggableProvided) => ReactElement;
|
|
43
59
|
|
|
44
60
|
const getRow: GetRowFunction = (
|
|
@@ -91,6 +107,11 @@ const ListRow: ListRowFunction = <T extends GenericObject>(
|
|
|
91
107
|
return <></>;
|
|
92
108
|
}
|
|
93
109
|
|
|
110
|
+
// Hide button on mobile if hideOnMobile is true
|
|
111
|
+
if (button.hideOnMobile && isMobile) {
|
|
112
|
+
return <></>;
|
|
113
|
+
}
|
|
114
|
+
|
|
94
115
|
return (
|
|
95
116
|
<div key={i}>
|
|
96
117
|
<Button
|
|
@@ -398,6 +398,7 @@ const BaseModelTable: <TBaseModel extends BaseModel | AnalyticsBaseModel>(
|
|
|
398
398
|
colSpan: column.colSpan,
|
|
399
399
|
contentClassName: column.contentClassName,
|
|
400
400
|
alignItem: column.alignItem,
|
|
401
|
+
hideOnMobile: column.hideOnMobile, // Propagate hideOnMobile property
|
|
401
402
|
getElement: column.getElement
|
|
402
403
|
? (item: TBaseModel): ReactElement => {
|
|
403
404
|
return column.getElement!(item, onBeforeFetchData);
|
|
@@ -1130,6 +1131,7 @@ const BaseModelTable: <TBaseModel extends BaseModel | AnalyticsBaseModel>(
|
|
|
1130
1131
|
actionsSchema.push({
|
|
1131
1132
|
title: "Show ID",
|
|
1132
1133
|
buttonStyleType: ButtonStyleType.OUTLINE,
|
|
1134
|
+
hideOnMobile: true,
|
|
1133
1135
|
onClick: async (
|
|
1134
1136
|
item: TBaseModel,
|
|
1135
1137
|
onCompleteAction: VoidFunction,
|
|
@@ -28,6 +28,7 @@ export default interface Columns<
|
|
|
28
28
|
actionButtons?: Array<ActionButton>;
|
|
29
29
|
alignItem?: AlignItem | undefined;
|
|
30
30
|
noValueMessage?: string | undefined;
|
|
31
|
+
hideOnMobile?: boolean | undefined; // Hide column on mobile devices
|
|
31
32
|
getElement?:
|
|
32
33
|
| ((item: TEntity, onBeforeFetchData?: TEntity | undefined) => ReactElement)
|
|
33
34
|
| undefined;
|