Skip to content

Actions for JS Console #1846

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

Merged
Merged
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
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,8 @@ import {
configureComponentAction,
changeLayoutAction,
addEventHandlerAction,
applyStyleAction
applyStyleAction,
nestComponentAction
} from "./actions";

export const actionCategories: ActionCategory[] = [
Expand All @@ -20,7 +21,8 @@ export const actionCategories: ActionCategory[] = [
moveComponentAction,
deleteComponentAction,
resizeComponentAction,
renameComponentAction
renameComponentAction,
nestComponentAction
]
},
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,10 @@ export function ActionInputSection() {
const [placeholderText, setPlaceholderText] = useState<string>("");
const [selectedComponent, setSelectedComponent] = useState<string | null>(null);
const [showComponentDropdown, setShowComponentDropdown] = useState<boolean>(false);
const [isNestedComponent, setIsNestedComponent] = useState<boolean>(false);
const [selectedNestComponent, setSelectedNestComponent] = useState<string | null>(null);
const [showEditorComponentsDropdown, setShowEditorComponentsDropdown] = useState<boolean>(false);
const [showStylingInput, setShowStylingInput] = useState<boolean>(false);
const [selectedEditorComponent, setSelectedEditorComponent] = useState<string | null>(null);
const [validationError, setValidationError] = useState<string | null>(null);
const inputRef = useRef<InputRef>(null);
Expand Down Expand Up @@ -73,44 +76,55 @@ export function ActionInputSection() {

setShowComponentDropdown(false);
setShowEditorComponentsDropdown(false);
setShowStylingInput(false);
setSelectedComponent(null);
setSelectedEditorComponent(null);
setIsNestedComponent(false);
setSelectedNestComponent(null);
setActionValue("");

if (action.requiresComponentSelection) {
setShowComponentDropdown(true);
setPlaceholderText("Select a component to add");
} else if (action.requiresEditorComponentSelection) {
}
if (action.requiresEditorComponentSelection) {
setShowEditorComponentsDropdown(true);
setPlaceholderText(`Select a component to ${action.label.toLowerCase()}`);
} else if (action.requiresInput) {
}
if (action.requiresInput) {
setPlaceholderText(action.inputPlaceholder || `Enter ${action.label.toLowerCase()} value`);
} else {
setPlaceholderText(`Execute ${action.label.toLowerCase()}`);
}
if (action.requiresStyle) {
setShowStylingInput(true);
setPlaceholderText(`Select a component to style`);
}
if (action.isNested) {
setIsNestedComponent(true);
}
}, []);

const handleComponentSelection = useCallback((key: string) => {
if (key.startsWith('comp-')) {
const compName = key.replace('comp-', '');
setSelectedComponent(compName);
isNestedComponent ? setSelectedNestComponent(compName) : setSelectedComponent(compName);
setPlaceholderText(`Configure ${compName} component`);
}
}, []);
}, [isNestedComponent]);

const handleEditorComponentSelection = useCallback((key: string) => {
setSelectedEditorComponent(key);
if (currentAction) {
setPlaceholderText(`${currentAction.label}`);
}
setPlaceholderText(`${currentAction?.label}`);
}, [currentAction]);


const validateInput = useCallback((value: string): string | null => {
if (!currentAction?.validation) return null;
return currentAction.validation(value);
}, [currentAction]);

const handleInputChange = useCallback((e: React.ChangeEvent<HTMLInputElement>) => {
const handleInputChange = useCallback((e: React.ChangeEvent<HTMLTextAreaElement | HTMLInputElement>) => {
const value = e.target.value;
setActionValue(value);

Expand Down Expand Up @@ -149,12 +163,18 @@ export function ActionInputSection() {
return;
}

if(currentAction.isNested && !selectedNestComponent) {
message.error('Please select a component to nest');
return;
}

try {
await currentAction.execute({
actionKey: selectedActionKey,
actionValue,
selectedComponent,
selectedEditorComponent,
selectedNestComponent,
editorState
});

Expand All @@ -167,6 +187,8 @@ export function ActionInputSection() {
setSelectedEditorComponent(null);
setPlaceholderText("");
setValidationError(null);
setIsNestedComponent(false);
setSelectedNestComponent(null);

} catch (error) {
console.error('Error executing action:', error);
Expand All @@ -177,6 +199,7 @@ export function ActionInputSection() {
actionValue,
selectedComponent,
selectedEditorComponent,
selectedNestComponent,
editorState,
currentAction,
validateInput
Expand Down Expand Up @@ -235,7 +258,7 @@ export function ActionInputSection() {
</Button>
</CustomDropdown>

{showComponentDropdown && (
{(showComponentDropdown || isNestedComponent) && (
<CustomDropdown
overlayStyle={{
maxHeight: '400px',
Expand All @@ -253,7 +276,13 @@ export function ActionInputSection() {
>
<Button size={"small"}>
<Space>
{selectedComponent ? selectedComponent : 'Select Component'}
{
selectedComponent
? selectedComponent
: selectedNestComponent
? selectedNestComponent
: 'New Component'
}
<DownOutlined />
</Space>
</Button>
Expand All @@ -278,23 +307,34 @@ export function ActionInputSection() {
>
<Button size={"small"}>
<Space>
{selectedEditorComponent ? selectedEditorComponent : 'Select Component'}
{selectedEditorComponent ? selectedEditorComponent : 'Editor Component'}
<DownOutlined />
</Space>
</Button>
</CustomDropdown>
)}

{shouldShowInput && (
<Input
ref={inputRef}
value={actionValue}
onChange={handleInputChange}
placeholder={placeholderText}
status={validationError ? 'error' : undefined}
/>
showStylingInput ? (
<Input.TextArea
ref={inputRef}
value={actionValue}
onChange={handleInputChange}
placeholder={placeholderText}
status={validationError ? 'error' : undefined}
autoSize={{ minRows: 1 }}
/>
) : (
<Input
ref={inputRef}
value={actionValue}
onChange={handleInputChange}
placeholder={placeholderText}
status={validationError ? 'error' : undefined}
/>
)
)}

{validationError && (
<div style={{ color: '#ff4d4f', fontSize: '12px', marginTop: '-8px' }}>
{validationError}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -108,6 +108,125 @@ export const addComponentAction: ActionConfig = {
}
};

export const nestComponentAction: ActionConfig = {
key: 'nest-components',
label: 'Nest a component',
category: 'component-management',
requiresEditorComponentSelection: true,
requiresInput: false,
isNested: true,
execute: async (params: ActionExecuteParams) => {
const { selectedEditorComponent, selectedNestComponent, editorState } = params;

if (!selectedEditorComponent || !selectedNestComponent || !editorState) {
message.error('Parent component, child component, and editor state are required');
return;
}

const parentComponentInfo = getEditorComponentInfo(editorState, selectedEditorComponent);

if (!parentComponentInfo) {
message.error(`Parent component "${selectedEditorComponent}" not found`);
return;
}

const { componentKey: parentKey, items } = parentComponentInfo;

if (!parentKey) {
message.error(`Parent component "${selectedEditorComponent}" not found in layout`);
return;
}

const parentItem = items[parentKey];
if (!parentItem) {
message.error(`Parent component "${selectedEditorComponent}" not found in items`);
return;
}

// Check if parent is a container
const parentCompType = parentItem.children.compType.getView();
const parentManifest = uiCompRegistry[parentCompType];

if (!parentManifest?.isContainer) {
message.error(`Component "${selectedEditorComponent}" is not a container and cannot nest components`);
return;
}

try {

const nameGenerator = editorState.getNameGenerator();
const compInfo = parseCompType(selectedNestComponent);
const compName = nameGenerator.genItemName(compInfo.compName);
const key = genRandomKey();

const manifest = uiCompRegistry[selectedNestComponent];
let defaultDataFn = undefined;

if (manifest?.lazyLoad) {
const { defaultDataFnName, defaultDataFnPath } = manifest;
if (defaultDataFnName && defaultDataFnPath) {
const module = await import(`../../../${defaultDataFnPath}.tsx`);
defaultDataFn = module[defaultDataFnName];
}
} else if (!compInfo.isRemote) {
defaultDataFn = manifest?.defaultDataFn;
}

const widgetValue: GridItemDataType = {
compType: selectedNestComponent,
name: compName,
comp: defaultDataFn ? defaultDataFn(compName, nameGenerator, editorState) : undefined,
};

const parentContainer = parentItem.children.comp;

const realContainer = parentContainer.realSimpleContainer();
if (!realContainer) {
message.error(`Container "${selectedEditorComponent}" cannot accept nested components`);
return;
}

const currentLayout = realContainer.children.layout.getView();
const layoutInfo = manifest?.layoutInfo || defaultLayout(selectedNestComponent as UICompType);

let itemPos = 0;
if (Object.keys(currentLayout).length > 0) {
itemPos = Math.max(...Object.values(currentLayout).map((l: any) => l.pos || 0)) + 1;
}

const layoutItem = {
i: key,
x: 0,
y: 0,
w: layoutInfo.w || 6,
h: layoutInfo.h || 5,
pos: itemPos,
isDragging: false,
};

realContainer.dispatch(
wrapActionExtraInfo(
multiChangeAction({
layout: changeValueAction({
...currentLayout,
[key]: layoutItem,
}, true),
items: addMapChildAction(key, widgetValue),
}),
{ compInfos: [{ compName: compName, compType: selectedNestComponent, type: "add" }] }
)
);

editorState.setSelectedCompNames(new Set([compName]), "nestComp");

message.success(`Component "${manifest?.name || selectedNestComponent}" nested in "${selectedEditorComponent}" successfully!`);
} catch (error) {
console.error('Error nesting component:', error);
message.error('Failed to nest component. Please try again.');
}
}
}

export const deleteComponentAction: ActionConfig = {
key: 'delete-components',
label: 'Delete a component',
Expand Down
Loading
Loading