Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: add ShareUrlButton functionality #823

Open
wants to merge 15 commits into
base: v2
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion src/actionbar/ActionButton.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import { ButtonProps } from "antd";

type Props = ButtonProps & {
tooltip: string;
onClick: any;
onClick?: any;
icon: any;
disabled?: boolean;
label?: string;
Expand Down
16 changes: 10 additions & 6 deletions src/actionbar/DashboardActionBar.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import React, { useContext } from "react";
import { useContext } from "react";
import {
DashboardActionContext,
DashboardActionContextType,
Expand All @@ -11,6 +11,12 @@ import {
BorderOuterOutlined,
} from "@ant-design/icons";
import { useLocale } from "@gisce/react-formiga-components";
import {
ActionViewContext,
ActionViewContextType,
} from "@/context/ActionViewContext";
import { ShareUrlButton } from "./ShareUrlButton";
import { ActionBarSeparator } from "./FormActionBar";

function DashboardActionBar() {
const { isLoading, dashboardRef, moveItemsEnabled, setMoveItemsEnabled } =
Expand All @@ -33,7 +39,7 @@ function DashboardActionBar() {
setMoveItemsEnabled(!moveItemsEnabled);
}}
/>
{separator()}
<ActionBarSeparator />
<ActionButton
icon={<SettingOutlined />}
tooltip={t("configDashboard")}
Expand All @@ -52,12 +58,10 @@ function DashboardActionBar() {
dashboardRef?.current.refresh();
}}
/>
<ActionBarSeparator />
<ShareUrlButton />
</Space>
);
}

function separator() {
return <div className="inline-block w-2" />;
}

export default DashboardActionBar;
17 changes: 10 additions & 7 deletions src/actionbar/FormActionBar.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ import {
import AttachmentsButton from "./AttachmentsButton";
import { Attachment } from "./AttachmentsButtonWrapper";
import { useNextPrevious } from "./useNextPrevious";
import { ShareUrlButton } from "./ShareUrlButton";

function FormActionBar({ toolbar }: { toolbar: any }) {
const contentRootContext = useContext(
Expand Down Expand Up @@ -197,8 +198,8 @@ function FormActionBar({ toolbar }: { toolbar: any }) {
{formIsLoading && (
<>
<Spin />
{separator()}
{separator()}
<ActionBarSeparator />
<ActionBarSeparator />
</>
)}
<NewButton disabled={mustDisableButtons} />
Expand Down Expand Up @@ -237,7 +238,7 @@ function FormActionBar({ toolbar }: { toolbar: any }) {
})
}
/>
{separator()}
<ActionBarSeparator />
<ActionButton
icon={<InfoCircleOutlined />}
tooltip={t("showLogs")}
Expand All @@ -250,7 +251,7 @@ function FormActionBar({ toolbar }: { toolbar: any }) {
disabled={mustDisableButtons || currentId === undefined}
onClick={() => tryAction(() => (formRef.current as any).fetchValues())}
/>
{separator()}
<ActionBarSeparator />
<ChangeViewButton
currentView={currentView}
previousView={previousView}
Expand All @@ -263,7 +264,7 @@ function FormActionBar({ toolbar }: { toolbar: any }) {
disabled={mustDisableButtons}
formHasChanges={formHasChanges}
/>
{separator()}
<ActionBarSeparator />
<Space>
<ActionButton
icon={<LeftOutlined />}
Expand All @@ -278,7 +279,7 @@ function FormActionBar({ toolbar }: { toolbar: any }) {
onClick={() => tryAction(onNextClick)}
/>
</Space>
{separator()}
<ActionBarSeparator />
<DropdownButton
icon={<ThunderboltOutlined />}
placement="bottomRight"
Expand Down Expand Up @@ -375,11 +376,13 @@ function FormActionBar({ toolbar }: { toolbar: any }) {
}
}}
/>
<ActionBarSeparator />
<ShareUrlButton res_id={currentId} />
</Space>
);
}

const separator = () => <div className="inline-block w-2" />;
export const ActionBarSeparator = () => <div className="inline-block w-2" />;

const saveDocument = async ({
onFormSave,
Expand Down
6 changes: 5 additions & 1 deletion src/actionbar/GraphActionBar.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import React, { useContext } from "react";
import { useContext } from "react";
import { Space } from "antd";
import ChangeViewButton from "./ChangeViewButton";
import {
Expand All @@ -10,6 +10,8 @@ import { useLocale } from "@gisce/react-formiga-components";
import ButtonWithBadge from "./ButtonWithBadge";
import { ReloadOutlined, FilterOutlined } from "@ant-design/icons";
import { View } from "@/types";
import { ShareUrlButton } from "./ShareUrlButton";
import { ActionBarSeparator } from "./FormActionBar";

function GraphActionBar({ refreshGraph }: { refreshGraph: () => void }) {
const { t } = useLocale();
Expand Down Expand Up @@ -60,6 +62,8 @@ function GraphActionBar({ refreshGraph }: { refreshGraph: () => void }) {
disabled={false}
previousView={previousView}
/>
<ActionBarSeparator />
<ShareUrlButton searchParams={searchParams} />
</Space>
);
}
Expand Down
130 changes: 130 additions & 0 deletions src/actionbar/ShareUrlButton.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,130 @@
import { useState, useCallback } from "react";
import { Button, Input, message, Space, Popover, theme } from "antd";
import { CopyOutlined, CheckOutlined } from "@ant-design/icons";
import { useLocale } from "@gisce/react-formiga-components";
import { createShareOpenUrl } from "@/helpers/shareUrlHelper";
import ActionButton from "./ActionButton";
import { IconExternalLink, IconShare2 } from "@tabler/icons-react";
import { useTabs } from "@/context/TabManagerContext";
import { useActionViewContext } from "@/context/ActionViewContext";
import { ActionInfo } from "@/types";

export type ShareUrlButtonProps = {
res_id?: number;
searchParams?: any[];
};

export function ShareUrlButton({ res_id, searchParams }: ShareUrlButtonProps) {
const { currentView } = useActionViewContext();
const initialView = {
id: currentView.view_id,
type: currentView.type,
};
const { token } = theme.useToken();
const { t } = useLocale();
const [isCopied, setIsCopied] = useState(false);
const { currentTab } = useTabs();

const copyToClipboard = useCallback(
(url: string) => {
try {
// Create a temporary textarea element
const tempInput = document.createElement("textarea");
tempInput.value = url;
document.body.appendChild(tempInput);

// Select the text in the textarea
tempInput.select();
tempInput.setSelectionRange(0, 99999); // For mobile devices

// Copy the text using execCommand

const successful = document.execCommand("copy");

// Clean up the temporary element
document.body.removeChild(tempInput);

// Handle success or failure
if (successful) {
setIsCopied(true);
message.success(t("urlCopiedToClipboard"));
setTimeout(() => setIsCopied(false), 2000);
} else {
throw new Error("Copy command was unsuccessful.");
}
} catch (err) {
console.error("Error copying to clipboard:", err);
message.error(t("errorCopyingToClipboard"));
}
},
[setIsCopied, t],
);

if (!currentTab?.action) return null;
const { action_id } = currentTab?.action || {};
const finalActionData: ActionInfo = {
...currentTab.action,
...(initialView && { initialView }),
...(searchParams && { searchParams }),
...(res_id && { res_id }),
};
const shareUrl = createShareOpenUrl(finalActionData);
const { type } = initialView || {};

let moreDataNeededForCopying = !action_id;
if (type === "form") {
moreDataNeededForCopying = !action_id || !res_id;
}

const popoverContent = (
<div style={{ padding: 2 }}>
<Space.Compact style={{ width: "100%" }}>
<Input
value={shareUrl}
readOnly
style={{
borderRadius: 6,
flex: 1,
marginRight: 8,
minWidth: 300,
}}
/>
<Button
title={t("copyToClipboard")}
type="text"
style={{
marginRight: 8,
}}
icon={
isCopied ? (
<CheckOutlined style={{ color: token.colorSuccess }} />
) : (
<CopyOutlined style={{ color: token.colorTextSecondary }} />
)
}
onClick={() => copyToClipboard(shareUrl)}
/>
<Button
title={t("openInNewTab")}
style={{ height: 28 }}
type="text"
icon={<IconExternalLink size={18} color={token.colorTextSecondary} />}
onClick={() => window.open(shareUrl, "_blank", "noopener,noreferrer")}
/>
</Space.Compact>
</div>
);

return (
<div style={{ maxHeight: 28 }}>
<Popover content={popoverContent} trigger="click" placement="bottom">
<ActionButton
style={{ height: 28 }}
icon={<IconShare2 size={16} color={token.colorTextSecondary} />}
disabled={moreDataNeededForCopying}
tooltip={t("share")}
/>
</Popover>
</div>
);
}
35 changes: 19 additions & 16 deletions src/actionbar/TreeActionBar.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { useContext, useEffect, useState, useRef } from "react";
import { useContext, useEffect, useState, useRef, useMemo } from "react";
import { Space, Spin } from "antd";
import ChangeViewButton from "./ChangeViewButton";
import {
Expand Down Expand Up @@ -32,6 +32,8 @@ import { mergeParams } from "@/helpers/searchHelper";
import { useFeatureIsEnabled } from "@/context/ConfigContext";
import { ErpFeatureKeys } from "@/models/erpFeature";
import { useHotkeys } from "react-hotkeys-hook";
import { ShareUrlButton } from "./ShareUrlButton";
import { ActionBarSeparator } from "./FormActionBar";

type Props = {
parentContext?: any;
Expand Down Expand Up @@ -205,13 +207,19 @@ function TreeActionBar(props: Props) {
});
}

const finalDomain = (() => {
const domain = searchTreeRef?.current?.getDomain();
const finalValues = mergeParams(domain || [], searchParams || []);
return finalValues;
})();

return (
<Space wrap={true}>
{treeIsLoading && (
<>
<Spin />
{separator()}
{separator()}
<ActionBarSeparator />
<ActionBarSeparator />
</>
)}
{treeExpandable ? null : (
Expand Down Expand Up @@ -246,7 +254,7 @@ function TreeActionBar(props: Props) {
badgeNumber={searchParams?.length}
/>
)}
{separator()}
<ActionBarSeparator />
<NewButton disabled={treeIsLoading} />
<ActionButton
icon={<CopyOutlined />}
Expand All @@ -270,7 +278,7 @@ function TreeActionBar(props: Props) {
loading={removingItem}
onClick={tryDelete}
/>
{separator()}
<ActionBarSeparator />
</>
)}
<ActionButton
Expand All @@ -295,7 +303,7 @@ function TreeActionBar(props: Props) {
/>
{!treeExpandable && (
<>
{separator()}
<ActionBarSeparator />
<ChangeViewButton
currentView={currentView}
availableViews={availableViews}
Expand All @@ -308,7 +316,7 @@ function TreeActionBar(props: Props) {
/>
</>
)}
{separator()}
<ActionBarSeparator />
<DropdownButton
icon={<ThunderboltOutlined />}
placement="bottomRight"
Expand Down Expand Up @@ -351,7 +359,7 @@ function TreeActionBar(props: Props) {
/>
{advancedExportEnabled && (
<>
{separator()}
<ActionBarSeparator />
<DropdownButton
placement="bottomRight"
icon={
Expand Down Expand Up @@ -424,10 +432,7 @@ function TreeActionBar(props: Props) {
visible={exportModalVisible}
onClose={() => setExportModalVisible(false)}
model={currentModel!}
domain={mergeParams(
searchTreeRef?.current?.getDomain() || [],
searchParams || [],
)}
domain={finalDomain}
limit={limit}
totalRegisters={totalItems || 0}
selectedRegistersToExport={selectedRowItems}
Expand All @@ -436,12 +441,10 @@ function TreeActionBar(props: Props) {
/>
</>
)}
<ActionBarSeparator />
<ShareUrlButton searchParams={searchParams} />
</Space>
);
}

function separator() {
return <div className="inline-block w-2" />;
}

export default TreeActionBar;
Loading
Loading