@oneuptime/common 8.0.5177 → 8.0.5181
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/API/SlackAPI.ts +69 -0
- package/UI/Components/CopyTextButton/CopyTextButton.tsx +66 -5
- package/UI/Components/LogsViewer/LogItem.tsx +250 -165
- package/UI/Components/LogsViewer/LogsViewer.tsx +137 -39
- package/build/dist/Server/API/SlackAPI.js +35 -0
- package/build/dist/Server/API/SlackAPI.js.map +1 -1
- package/build/dist/UI/Components/CopyTextButton/CopyTextButton.js +29 -2
- package/build/dist/UI/Components/CopyTextButton/CopyTextButton.js.map +1 -1
- package/build/dist/UI/Components/LogsViewer/LogItem.js +109 -75
- package/build/dist/UI/Components/LogsViewer/LogItem.js.map +1 -1
- package/build/dist/UI/Components/LogsViewer/LogsViewer.js +65 -22
- package/build/dist/UI/Components/LogsViewer/LogsViewer.js.map +1 -1
- package/package.json +1 -1
package/Server/API/SlackAPI.ts
CHANGED
|
@@ -38,6 +38,10 @@ import SlackOnCallDutyActions from "../Utils/Workspace/Slack/Actions/OnCallDutyP
|
|
|
38
38
|
import WorkspaceProjectAuthToken, {
|
|
39
39
|
SlackMiscData,
|
|
40
40
|
} from "../../Models/DatabaseModels/WorkspaceProjectAuthToken";
|
|
41
|
+
import UserMiddleware from "../Middleware/UserAuthorization";
|
|
42
|
+
import CommonAPI from "./CommonAPI";
|
|
43
|
+
import SlackUtil from "../Utils/Workspace/Slack/Slack";
|
|
44
|
+
import DatabaseCommonInteractionProps from "../../Types/BaseDatabase/DatabaseCommonInteractionProps";
|
|
41
45
|
|
|
42
46
|
export default class SlackAPI {
|
|
43
47
|
public getRouter(): ExpressRouter {
|
|
@@ -656,6 +660,71 @@ export default class SlackAPI {
|
|
|
656
660
|
},
|
|
657
661
|
);
|
|
658
662
|
|
|
663
|
+
// Fetch and cache all Slack channels for current tenant's project
|
|
664
|
+
router.get(
|
|
665
|
+
"/slack/get-all-channels",
|
|
666
|
+
UserMiddleware.getUserMiddleware,
|
|
667
|
+
async (req: ExpressRequest, res: ExpressResponse) => {
|
|
668
|
+
const props: DatabaseCommonInteractionProps =
|
|
669
|
+
await CommonAPI.getDatabaseCommonInteractionProps(req);
|
|
670
|
+
|
|
671
|
+
if (!props.tenantId) {
|
|
672
|
+
return Response.sendErrorResponse(
|
|
673
|
+
req,
|
|
674
|
+
res,
|
|
675
|
+
new BadRequestException("ProjectId (tenant) not found in request"),
|
|
676
|
+
);
|
|
677
|
+
}
|
|
678
|
+
|
|
679
|
+
// Get Slack project auth
|
|
680
|
+
const projectAuth: WorkspaceProjectAuthToken | null =
|
|
681
|
+
await WorkspaceProjectAuthTokenService.getProjectAuth({
|
|
682
|
+
projectId: props.tenantId,
|
|
683
|
+
workspaceType: WorkspaceType.Slack,
|
|
684
|
+
});
|
|
685
|
+
|
|
686
|
+
if (!projectAuth || !projectAuth.authToken) {
|
|
687
|
+
return Response.sendErrorResponse(
|
|
688
|
+
req,
|
|
689
|
+
res,
|
|
690
|
+
new BadRequestException(
|
|
691
|
+
"Slack is not connected for this project. Please connect Slack first.",
|
|
692
|
+
),
|
|
693
|
+
);
|
|
694
|
+
}
|
|
695
|
+
|
|
696
|
+
// Fetch all channels (also updates cache under miscData.channelCache)
|
|
697
|
+
|
|
698
|
+
let updatedProjectAuth: WorkspaceProjectAuthToken | null = projectAuth;
|
|
699
|
+
|
|
700
|
+
if (!(projectAuth.miscData as SlackMiscData)?.channelCache) {
|
|
701
|
+
await SlackUtil.getAllWorkspaceChannels({
|
|
702
|
+
authToken: projectAuth.authToken,
|
|
703
|
+
projectId: props.tenantId,
|
|
704
|
+
});
|
|
705
|
+
|
|
706
|
+
// Re-fetch to return the latest cached object
|
|
707
|
+
updatedProjectAuth =
|
|
708
|
+
await WorkspaceProjectAuthTokenService.getProjectAuth({
|
|
709
|
+
projectId: props.tenantId,
|
|
710
|
+
workspaceType: WorkspaceType.Slack,
|
|
711
|
+
});
|
|
712
|
+
}
|
|
713
|
+
|
|
714
|
+
const channelCache: {
|
|
715
|
+
[channelName: string]: {
|
|
716
|
+
id: string;
|
|
717
|
+
name: string;
|
|
718
|
+
lastUpdated: string;
|
|
719
|
+
};
|
|
720
|
+
} =
|
|
721
|
+
((updatedProjectAuth?.miscData as SlackMiscData | undefined) || {})
|
|
722
|
+
?.channelCache || {};
|
|
723
|
+
|
|
724
|
+
return Response.sendJsonObjectResponse(req, res, channelCache as any);
|
|
725
|
+
},
|
|
726
|
+
);
|
|
727
|
+
|
|
659
728
|
// options load endpoint.
|
|
660
729
|
|
|
661
730
|
router.post(
|
|
@@ -4,10 +4,18 @@ import React, {
|
|
|
4
4
|
MouseEventHandler,
|
|
5
5
|
ReactElement,
|
|
6
6
|
} from "react";
|
|
7
|
+
import Icon from "../Icon/Icon";
|
|
8
|
+
import IconProp from "../../../Types/Icon/IconProp";
|
|
7
9
|
|
|
8
10
|
export interface ComponentProps {
|
|
9
11
|
textToBeCopied: string;
|
|
10
12
|
className?: string | undefined;
|
|
13
|
+
size?: "xs" | "sm" | "md"; // visual size
|
|
14
|
+
variant?: "ghost" | "soft" | "solid"; // visual style
|
|
15
|
+
iconOnly?: boolean; // render only icon without label
|
|
16
|
+
label?: string; // default: "Copy"
|
|
17
|
+
copiedLabel?: string; // default: "Copied!"
|
|
18
|
+
title?: string; // tooltip
|
|
11
19
|
}
|
|
12
20
|
|
|
13
21
|
const CopyTextButton: FunctionComponent<ComponentProps> = (
|
|
@@ -15,8 +23,13 @@ const CopyTextButton: FunctionComponent<ComponentProps> = (
|
|
|
15
23
|
): ReactElement => {
|
|
16
24
|
const [copied, setCopied] = React.useState(false);
|
|
17
25
|
|
|
18
|
-
const
|
|
19
|
-
|
|
26
|
+
const size: "xs" | "sm" | "md" = props.size || "xs";
|
|
27
|
+
const variant: "ghost" | "soft" | "solid" = props.variant || "ghost";
|
|
28
|
+
const label: string = props.label || "Copy";
|
|
29
|
+
const copiedLabel: string = props.copiedLabel || "Copied!";
|
|
30
|
+
|
|
31
|
+
const handleCopy: MouseEventHandler<HTMLButtonElement> = async (
|
|
32
|
+
event: React.MouseEvent<HTMLButtonElement, MouseEvent>,
|
|
20
33
|
) => {
|
|
21
34
|
event.preventDefault();
|
|
22
35
|
event.stopPropagation();
|
|
@@ -27,10 +40,58 @@ const CopyTextButton: FunctionComponent<ComponentProps> = (
|
|
|
27
40
|
}, 1000);
|
|
28
41
|
};
|
|
29
42
|
|
|
43
|
+
const sizeClasses: Record<typeof size, string> = {
|
|
44
|
+
xs: "text-[10px] px-1.5 py-0.5 rounded",
|
|
45
|
+
sm: "text-xs px-2 py-1 rounded-md",
|
|
46
|
+
md: "text-sm px-2.5 py-1.5 rounded-md",
|
|
47
|
+
} as const;
|
|
48
|
+
|
|
49
|
+
const iconSizes: Record<typeof size, string> = {
|
|
50
|
+
xs: "w-3.5 h-3.5",
|
|
51
|
+
sm: "w-4 h-4",
|
|
52
|
+
md: "w-4.5 h-4.5",
|
|
53
|
+
} as const;
|
|
54
|
+
|
|
55
|
+
const variantClasses: Record<typeof variant, string> = {
|
|
56
|
+
ghost:
|
|
57
|
+
"bg-transparent border border-slate-600 text-slate-300 hover:bg-slate-700/40",
|
|
58
|
+
soft: "bg-slate-700 text-white border border-slate-600 hover:bg-slate-600",
|
|
59
|
+
solid:
|
|
60
|
+
"bg-indigo-600 text-white border border-indigo-600 hover:bg-indigo-500",
|
|
61
|
+
} as const;
|
|
62
|
+
|
|
63
|
+
const copiedClasses: string =
|
|
64
|
+
"bg-emerald-600/20 border border-emerald-500 text-emerald-300";
|
|
65
|
+
|
|
30
66
|
return (
|
|
31
|
-
<
|
|
32
|
-
|
|
33
|
-
|
|
67
|
+
<button
|
|
68
|
+
type="button"
|
|
69
|
+
className={`inline-flex items-center justify-center gap-1 transition-colors duration-150 cursor-pointer select-none ${
|
|
70
|
+
copied ? copiedClasses : variantClasses[variant]
|
|
71
|
+
} ${sizeClasses[size]} ${props.className || ""}`}
|
|
72
|
+
onClick={handleCopy}
|
|
73
|
+
onKeyDown={(e: React.KeyboardEvent<HTMLButtonElement>) => {
|
|
74
|
+
if (e.key === "Enter" || e.key === " ") {
|
|
75
|
+
handleCopy(e as unknown as React.MouseEvent<HTMLButtonElement>);
|
|
76
|
+
}
|
|
77
|
+
}}
|
|
78
|
+
title={props.title || label}
|
|
79
|
+
aria-label={props.title || label}
|
|
80
|
+
>
|
|
81
|
+
{/* Icon */}
|
|
82
|
+
<span aria-hidden="true" className="flex items-center justify-center">
|
|
83
|
+
{copied ? (
|
|
84
|
+
<Icon
|
|
85
|
+
icon={IconProp.Check}
|
|
86
|
+
className={`${iconSizes[size]} text-emerald-400`}
|
|
87
|
+
/>
|
|
88
|
+
) : (
|
|
89
|
+
<Icon icon={IconProp.Copy} className={`${iconSizes[size]}`} />
|
|
90
|
+
)}
|
|
91
|
+
</span>
|
|
92
|
+
{/* Label (optional) */}
|
|
93
|
+
{!props.iconOnly && <span>{copied ? copiedLabel : label}</span>}
|
|
94
|
+
</button>
|
|
34
95
|
);
|
|
35
96
|
};
|
|
36
97
|
|