diff --git a/src/actionbar/TreeActionBar.tsx b/src/actionbar/TreeActionBar.tsx
index 5871e2719..f85ca2882 100644
--- a/src/actionbar/TreeActionBar.tsx
+++ b/src/actionbar/TreeActionBar.tsx
@@ -43,6 +43,7 @@ import {
import { ActionBarSeparator } from "./ActionBarSeparator";
import { ShareUrlButton } from "./ShareUrlButton";
import { useErrorNotification } from "@/hooks/useErrorNotification";
+import { ACTION_TYPE_REPORT } from "@/models/constants";
import { getVisibleTreeFields } from "@/helpers/treeHelper";
type Props = {
@@ -246,7 +247,7 @@ function TreeActionBarComponent({
id: -1,
model: currentModel,
report_name: "printscreen.list",
- type: "ir.actions.report.xml",
+ type: ACTION_TYPE_REPORT,
datas: {
view_id: currentView?.view_id,
fields:
diff --git a/src/context/ContentRootContext.tsx b/src/context/ContentRootContext.tsx
index b9fea37d5..e95b80859 100644
--- a/src/context/ContentRootContext.tsx
+++ b/src/context/ContentRootContext.tsx
@@ -22,6 +22,11 @@ import { transformPlainMany2Ones, stringFormat } from "@/helpers/formHelper";
import { useFeatureData } from "./ConfigContext";
import { ErpFeatureKeys } from "@/models/erpFeature";
import { useNetworkRequest } from "@/hooks/useNetworkRequest";
+import {
+ ACTION_TYPE_REPORT,
+ ACTION_TYPE_WINDOW,
+ ACTION_TYPE_URL,
+} from "@/models/constants";
import { getVisibleTreeFields } from "@/helpers/treeHelper";
export type ContentRootContextType = {
@@ -34,8 +39,8 @@ export type ContentRootContextType = {
view_id,
}: {
actionData: any;
- fields: any;
- values: any;
+ fields?: any;
+ values?: any;
context?: any;
onRefreshParentValues?: () => void;
treeView?: any;
@@ -136,7 +141,15 @@ const ContentRootProvider = (
}
}
- if (type !== "ir.actions.report.xml") {
+ // If view_id doesn't exist and we have a treeView, extract fields and add them to datas
+ if (!view_id && treeView) {
+ const fieldsToRetrieve = getVisibleTreeFields(treeView);
+ if (fieldsToRetrieve && fieldsToRetrieve.length > 0) {
+ datas.fields = fieldsToRetrieve;
+ }
+ }
+
+ if (type !== ACTION_TYPE_REPORT) {
showErrorNotification({
type: "error",
title: "Error",
@@ -227,8 +240,8 @@ const ContentRootProvider = (
view_id,
}: {
actionData: any;
- fields: any;
- values: any;
+ fields?: any;
+ values?: any;
context?: any;
onRefreshParentValues?: any;
treeView?: any;
@@ -239,7 +252,7 @@ const ContentRootProvider = (
onRefreshParentValues.current.push(onRefreshParentValuesFn);
}
- if (type === "ir.actions.report.xml") {
+ if (type === ACTION_TYPE_REPORT) {
return await generateReport({
reportData: actionData,
fields,
@@ -248,9 +261,9 @@ const ContentRootProvider = (
treeView,
view_id,
});
- } else if (type === "ir.actions.act_window") {
+ } else if (type === ACTION_TYPE_WINDOW) {
return await runAction({ actionData, fields, values, context });
- } else if (type === "ir.actions.act_url") {
+ } else if (type === ACTION_TYPE_URL) {
window.open(
stringFormat(actionData.url, { ...values, context }),
"_blank",
@@ -281,7 +294,7 @@ const ContentRootProvider = (
if (!_actionData.res_model) {
actionData = (
await ConnectionProvider.getHandler().readObjects({
- model: "ir.actions.act_window",
+ model: ACTION_TYPE_WINDOW,
ids: [parseInt(_actionData.id)],
context,
})
diff --git a/src/ui/FavouriteButton.tsx b/src/ui/FavouriteButton.tsx
index 2bf085214..bd1d07ba2 100644
--- a/src/ui/FavouriteButton.tsx
+++ b/src/ui/FavouriteButton.tsx
@@ -22,6 +22,7 @@ import {
DropdownMenuGroup,
DropdownMenuItem,
} from "@gisce/react-formiga-components";
+import { ACTION_TYPE_WIZARD } from "@/models/constants";
const { useToken } = theme;
export type ShortcutApi = {
@@ -124,7 +125,7 @@ const FavouriteButton = (props: Props) => {
function handleMenuClick(item: DropdownMenuItem) {
const shortcut = item as ShortcutApi;
- if (shortcut?.action_type === "ir.actions.wizard") {
+ if (shortcut?.action_type === ACTION_TYPE_WIZARD) {
return;
}
openShortcut(shortcut);
diff --git a/src/views/RootView.tsx b/src/views/RootView.tsx
index b88233b9e..9496e5667 100644
--- a/src/views/RootView.tsx
+++ b/src/views/RootView.tsx
@@ -19,7 +19,11 @@ import { transformPlainMany2Ones } from "@/helpers/formHelper";
import { nanoid } from "nanoid";
import { useLocale } from "@gisce/react-formiga-components";
import { useConfigContext, useFeatureData } from "@/context/ConfigContext";
-import { DEFAULT_SEARCH_LIMIT } from "@/models/constants";
+import {
+ DEFAULT_SEARCH_LIMIT,
+ ACTION_TYPE_WINDOW,
+ ACTION_TYPE_WIZARD,
+} from "@/models/constants";
import { filterAllowedValues } from "@/helpers/shareUrlHelper";
import { ErpFeatureKeys } from "@/models/erpFeature";
import { useNetworkRequest } from "@/hooks/useNetworkRequest";
@@ -215,7 +219,7 @@ function RootView(props: RootViewProps, ref: any) {
return await openAction({
action_id: -1,
- action_type: "ir.actions.act_window",
+ action_type: ACTION_TYPE_WINDOW,
model,
views: [[view.view_id, "form"]],
context: rootContext,
@@ -249,7 +253,7 @@ function RootView(props: RootViewProps, ref: any) {
context: rootContext,
});
- if (dataForAction.type === "ir.actions.wizard") {
+ if (dataForAction.type === ACTION_TYPE_WIZARD) {
showErrorNotification({
type: "error",
title: "Error",
@@ -722,7 +726,7 @@ function RootView(props: RootViewProps, ref: any) {
return await openAction({
action_id: -1,
- action_type: "ir.actions.act_window",
+ action_type: ACTION_TYPE_WINDOW,
model,
views: finalViews,
context: rootContext,
diff --git a/src/widgets/WidgetFactory.tsx b/src/widgets/WidgetFactory.tsx
index 77661bd32..0ed1a3058 100644
--- a/src/widgets/WidgetFactory.tsx
+++ b/src/widgets/WidgetFactory.tsx
@@ -44,6 +44,7 @@ import { FiberGrid } from "./custom/FiberGrid";
import { Timeline } from "./custom/Timeline";
import { Indicator } from "./custom/Indicator";
import { Tags } from "./custom/Tags";
+import { ActionButtons } from "./custom/ActionButtons";
import { QRCode } from "./custom/QRCode";
import { createElement } from "react";
@@ -140,6 +141,8 @@ const getWidgetType = (type: string) => {
return Carousel;
case "colorPicker":
return ColorPicker;
+ case "action_buttons":
+ return ActionButtons;
case "qrcode":
return QRCode;
default:
diff --git a/src/widgets/base/many2one/Many2oneSuffix.tsx b/src/widgets/base/many2one/Many2oneSuffix.tsx
index 35626ac58..d28531d33 100644
--- a/src/widgets/base/many2one/Many2oneSuffix.tsx
+++ b/src/widgets/base/many2one/Many2oneSuffix.tsx
@@ -19,6 +19,7 @@ import {
import { useNetworkRequest } from "@/hooks/useNetworkRequest";
import { useFeatureIsEnabled } from "@/context/ConfigContext";
import { ErpFeatureKeys } from "@/models/erpFeature";
+import { ACTION_TYPE_WINDOW } from "@/models/constants";
type Props = {
id: number;
@@ -155,7 +156,7 @@ export const Many2oneSuffix = (props: Props) => {
target: "current",
initialView: { type: "form" },
action_id: -1,
- action_type: "ir.actions.act_window",
+ action_type: ACTION_TYPE_WINDOW,
});
break;
case "action":
diff --git a/src/widgets/custom/ActionButtons.tsx b/src/widgets/custom/ActionButtons.tsx
new file mode 100644
index 000000000..61b2027ee
--- /dev/null
+++ b/src/widgets/custom/ActionButtons.tsx
@@ -0,0 +1,261 @@
+import React, {
+ useState,
+ useMemo,
+ useCallback,
+ useEffect,
+ useContext,
+} from "react";
+import { Button as AntButton, Space } from "antd";
+import { LoadingOutlined } from "@ant-design/icons";
+import Field from "@/common/Field";
+import { iconMapper, Icon, FieldSet } from "@gisce/react-formiga-components";
+import { WidgetProps } from "@/types";
+import ErrorBoundary from "antd/es/alert/ErrorBoundary";
+import { Field as FieldOoui } from "@gisce/ooui";
+import ConnectionProvider from "@/ConnectionProvider";
+import { useNetworkRequest } from "@/hooks/useNetworkRequest";
+import { ACTION_TYPE_WINDOW } from "@/models/constants";
+import {
+ ContentRootContext,
+ ContentRootContextType,
+} from "@/context/ContentRootContext";
+import { FormContext, FormContextType } from "@/context/FormContext";
+
+export interface ActionButtonAction {
+ id?: number;
+ name?: string;
+ type?: string;
+ res_model?: string;
+ view_id?: number;
+ view_type?: string;
+ view_mode?: string;
+ res_id?: number;
+ [key: string]: any;
+}
+
+export interface ActionButtonMethod {
+ name: string;
+ res_model: string;
+ args?: any[];
+}
+
+export interface ActionButtonItem {
+ name: string;
+ icon?: string;
+ action?: ActionButtonAction;
+ method?: ActionButtonMethod;
+}
+
+type ActionButtonsProps = WidgetProps & {
+ ooui: FieldOoui;
+};
+
+type ActionButtonsInputProps = ActionButtonsProps & {
+ value?: any;
+};
+
+export const ActionButtons = (props: ActionButtonsProps) => {
+ const { ooui } = props;
+
+ return (
+