Skip to content

Commit

Permalink
Merge pull request #823 from gisce/feat/add-share-url-button
Browse files Browse the repository at this point in the history
feat: add ShareUrlButton functionality
  • Loading branch information
mguellsegarra authored Jan 22, 2025
2 parents 9281128 + 644e14e commit 4c09f98
Show file tree
Hide file tree
Showing 21 changed files with 776 additions and 225 deletions.
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

0 comments on commit 4c09f98

Please sign in to comment.