Skip to content

Ninja Tables integration added#144

Open
RishadAlam wants to merge 10 commits intomainfrom
feat/ninja-tables
Open

Ninja Tables integration added#144
RishadAlam wants to merge 10 commits intomainfrom
feat/ninja-tables

Conversation

@RishadAlam
Copy link
Copy Markdown
Member

No description provided.

Copilot AI review requested due to automatic review settings April 4, 2026 06:12
Copy link
Copy Markdown

@gemini-code-assist gemini-code-assist bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request introduces a new integration for NinjaTables, featuring a backend controller for data retrieval, a record helper for executing row actions, and a comprehensive frontend suite for authorization and field mapping. Additionally, the PR updates several existing integration components to a standard 500px minimum height and includes a minor dependency update. The review feedback highlights opportunities to align with WordPress database standards, correct a typo in a user-facing error message, and improve the robustness of the field mapping logic with additional safety checks.

Comment on lines +151 to +153
WHERE post_type = %s AND post_status = %s
ORDER BY post_title ASC",
self::POST_TYPE,
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

It is recommended to use the standard $wpdb->posts property instead of manually concatenating the prefix with the table name.

            "SELECT ID, post_title FROM $wpdb->posts 
            WHERE post_type = %s AND post_status = %s 
            ORDER BY post_title ASC",

return [
'success' => false,
'message' => wp_sprintf(
__('%s plugin is not installed or activate', 'bit-integrations'),
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

Typo in the error message: "activate" should be "activated".

                __('%s plugin is not installed or activated', 'bit-integrations'),

Comment on lines +392 to +401
foreach ($fieldMap as $value) {
$triggerValue = $value->formField;
$actionValue = $value->columnName;

if ($triggerValue === 'custom' && isset($value->customValue)) {
$dataFinal[$actionValue] = Common::replaceFieldWithValue($value->customValue, $fieldValues);
} elseif (isset($fieldValues[$triggerValue]) && !\is_null($fieldValues[$triggerValue])) {
$dataFinal[$actionValue] = $fieldValues[$triggerValue];
}
}
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

The generateReqDataFromFieldMap method lacks safety checks for columnName and formField. Mapping fields with an empty column name can lead to invalid keys in the resulting data array. Additionally, the logic here partially duplicates processRowFields; ensure consistency in how mapped data is handled.

        foreach ($fieldMap as $value) {
            $triggerValue = $value->formField ?? '';
            $actionValue = $value->columnName ?? '';

            if (empty($actionValue)) {
                continue;
            }

            if ($triggerValue === 'custom' && isset($value->customValue)) {
                $dataFinal[$actionValue] = Common::replaceFieldWithValue($value->customValue, $fieldValues);
            } elseif (isset($fieldValues[$triggerValue])) {
                $dataFinal[$actionValue] = $fieldValues[$triggerValue];
            }
        }

@github-actions
Copy link
Copy Markdown

github-actions bot commented Apr 4, 2026

🔍 WordPress Plugin Check Report

⚠️ Status: Passed with warnings

📊 Report

🎯 Total Issues ❌ Errors ⚠️ Warnings
2 0 2

⚠️ Warnings (2)

📁 readme.txt (2 warnings)
📍 Line 🔖 Check 💬 Message
0 mismatched_plugin_name Plugin name "Bit integrations - Easy Automator with no-code automation, integrate Webhook and automate 300+ Platform" is different from the name declared in plugin header "Bit Integrations".
0 readme_parser_warnings_trimmed_section_description The "Description" section is too long and was truncated. A maximum of 2500 characters is supported.

🤖 Generated by WordPress Plugin Check Action • Learn more about Plugin Check

Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Adds a new Ninja Tables action integration (frontend configuration UI + backend AJAX endpoints) and updates various integration step layouts.

Changes:

  • Introduces Ninja Tables integration UI (authorization, action selection, table/row/user pickers, field mapping, edit flow).
  • Adds backend Ninja Tables routes/controller + record execution helper for add/update row actions.
  • Standardizes step-2 container minHeight across multiple existing integrations.

Reviewed changes

Copilot reviewed 28 out of 29 changed files in this pull request and generated 4 comments.

Show a summary per file
File Description
pnpm-lock.yaml Updates lockfile dependency (caniuse-lite) snapshot.
frontend/src/Utils/StaticData/tutorialLinks.js Adds Ninja Tables documentation link entry.
frontend/src/components/Flow/New/SelectAction.jsx Adds “Ninja Tables” to action selection list.
frontend/src/components/AllIntegrations/NewInteg.jsx Wires Ninja Tables into the “new integration” router/switch.
frontend/src/components/AllIntegrations/EditInteg.jsx Wires Ninja Tables into the “edit integration” router/switch.
frontend/src/components/AllIntegrations/IntegInfo.jsx Wires Ninja Tables authorization into integration info view.
frontend/src/components/AllIntegrations/NinjaTables/staticData.js Defines Ninja Tables action modules metadata.
frontend/src/components/AllIntegrations/NinjaTables/NinjaTablesCommonFunc.js Adds Ninja Tables refresh/auth helpers + mapped-field validation.
frontend/src/components/AllIntegrations/NinjaTables/NinjaTablesAuthorization.jsx Adds step-1 “authorization” UI for Ninja Tables.
frontend/src/components/AllIntegrations/NinjaTables/NinjaTablesIntegLayout.jsx Adds step-2 UI (action/table/row/user selection + mapping).
frontend/src/components/AllIntegrations/NinjaTables/NinjaTablesFieldMap.jsx Adds field mapping row UI for Ninja Tables.
frontend/src/components/AllIntegrations/NinjaTables/NinjaTables.jsx Adds the new integration “create” flow container (steps 1–3).
frontend/src/components/AllIntegrations/NinjaTables/EditNinjaTables.jsx Adds the edit flow container for an existing Ninja Tables action.
frontend/src/components/AllIntegrations/WPCourseware/WPCourseware.jsx Updates step container minHeight.
frontend/src/components/AllIntegrations/WPCafe/WPCafe.jsx Updates step container minHeight.
frontend/src/components/AllIntegrations/TutorLms/TutorLms.jsx Updates step container minHeight.
frontend/src/components/AllIntegrations/Telegram/Telegram.jsx Updates step container minHeight.
frontend/src/components/AllIntegrations/TeamsForWooCommerceMemberships/TeamsForWooCommerceMemberships.jsx Updates step container minHeight.
frontend/src/components/AllIntegrations/SeoPress/SeoPress.jsx Updates step container minHeight.
frontend/src/components/AllIntegrations/MailPoet/MailPoet.jsx Updates step container minHeight.
frontend/src/components/AllIntegrations/MailerPress/MailerPress.jsx Updates step container minHeight.
frontend/src/components/AllIntegrations/FluentCRM/FluentCrm.jsx Updates step container minHeight.
frontend/src/components/AllIntegrations/FluentCart/FluentCart.jsx Updates step container minHeight.
frontend/src/components/AllIntegrations/Encharge/Encharge.jsx Updates step container minHeight (and fixes missing px).
frontend/src/components/AllIntegrations/Autonami/Autonami.jsx Updates step container minHeight.
frontend/src/components/AllIntegrations/AcademyLms/AcademyLms.jsx Updates step container minHeight.
backend/Actions/NinjaTables/Routes.php Registers AJAX endpoints for authorize + refresh tables/rows/users/columns.
backend/Actions/NinjaTables/NinjaTablesController.php Implements refresh endpoints and execution entrypoint.
backend/Actions/NinjaTables/RecordApiHelper.php Implements execution logic + filter dispatch + logging for add/update.
Files not reviewed (1)
  • pnpm-lock.yaml: Language not supported

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines +78 to +87
<button
onClick={handleAuthorize}
className="btn btcd-btn-lg purple sh-sm flx"
type="button"
disabled={isAuthorized}>
{isAuthorized
? __('Connected ✔', 'bit-integrations')
: __('Connect to Ninja Tables', 'bit-integrations')}
{isLoading === 'auth' && <LoaderSm size={20} clr="#022217" className="ml-2" />}
</button>
Copy link

Copilot AI Apr 4, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

When isInfo is true, the "Connect" button is still clickable and triggers handleAuthorize(), which uses formID, setIsLoading, and setSnackbar. In the integration info view these props are not provided, so clicking the button will throw. Hide/disable the connect UI (and skip authorization logic) when isInfo is true.

Copilot uses AI. Check for mistakes.
setNinjaTablesConf(prevConf => ({
...prevConf,
default: {
...prevConf.default,
Copy link

Copilot AI Apr 4, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

handleFetch spreads prevConf.default without guarding for undefined. If an existing config ever lacks the default object (e.g., older saved configs), this will throw a TypeError during refresh. Use a fallback like ...(prevConf.default || {}) when constructing the new default object.

Suggested change
...prevConf.default,
...(prevConf.default || {}),

Copilot uses AI. Check for mistakes.
return [
'success' => false,
'message' => wp_sprintf(
__('%s plugin is not installed or activate', 'bit-integrations'),
Copy link

Copilot AI Apr 4, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Spelling/grammar in the default error message: "not installed or activate" should be "not installed or activated". This message is user-visible in logs/errors, so it should be corrected.

Suggested change
__('%s plugin is not installed or activate', 'bit-integrations'),
__('%s plugin is not installed or activated', 'bit-integrations'),

Copilot uses AI. Check for mistakes.
abdul-kaioum
abdul-kaioum previously approved these changes Apr 13, 2026
Copilot AI review requested due to automatic review settings April 13, 2026 11:49
Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 28 out of 29 changed files in this pull request and generated 6 comments.

Files not reviewed (1)
  • pnpm-lock.yaml: Language not supported

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines +622 to +623
case 'Ninja Tables':
return <NinjaTablesAuthorization ninjaTablesConf={integrationConf} step={1} isInfo />
Copy link

Copilot AI Apr 13, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In the Integration Info view this component is instantiated without the state setters/handlers (e.g., setNinjaTablesConf, setIsLoading, setSnackbar). NinjaTablesAuthorization currently uses those unconditionally (input onChange / Connect button), which will throw at runtime. Either pass the required props here, or update NinjaTablesAuthorization to fully support an isInfo mode (disable inputs/buttons and avoid calling missing callbacks).

Copilot uses AI. Check for mistakes.
Comment on lines +25 to +46
bitsFetch(requestParams, 'ninja_tables_authorize').then(result => {
if (result?.success) {
setIsAuthorized(true)
setSnackbar({
show: true,
msg: __('Connected with Ninja Tables successfully', 'bit-integrations')
})
setIsLoading(false)
} else {
setShowAuthMsg(true)
setSnackbar({
show: true,
msg: __(
result?.data
? result.data
: 'Connection failed. Please make sure Ninja Tables is installed and activated',
'bit-integrations'
)
})
setIsLoading(false)
}
})
Copy link

Copilot AI Apr 13, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

handleAuthorize() does not handle rejected promises. If bitsFetch throws/rejects, setIsLoading(false) is never called and the UI can get stuck in loading state. Add a catch/finally path that resets loading and shows a useful error message; also consider clearing showAuthMsg on successful authorization so the reminder doesn’t persist after a retry succeeds.

Suggested change
bitsFetch(requestParams, 'ninja_tables_authorize').then(result => {
if (result?.success) {
setIsAuthorized(true)
setSnackbar({
show: true,
msg: __('Connected with Ninja Tables successfully', 'bit-integrations')
})
setIsLoading(false)
} else {
setShowAuthMsg(true)
setSnackbar({
show: true,
msg: __(
result?.data
? result.data
: 'Connection failed. Please make sure Ninja Tables is installed and activated',
'bit-integrations'
)
})
setIsLoading(false)
}
})
bitsFetch(requestParams, 'ninja_tables_authorize')
.then(result => {
if (result?.success) {
setIsAuthorized(true)
setShowAuthMsg(false)
setSnackbar({
show: true,
msg: __('Connected with Ninja Tables successfully', 'bit-integrations')
})
} else {
setShowAuthMsg(true)
setSnackbar({
show: true,
msg: __(
result?.data
? result.data
: 'Connection failed. Please make sure Ninja Tables is installed and activated',
'bit-integrations'
)
})
}
})
.catch(error => {
setShowAuthMsg(true)
setSnackbar({
show: true,
msg: __(
error?.message ||
'Connection failed. Please make sure Ninja Tables is installed and activated',
'bit-integrations'
)
})
})
.finally(() => {
setIsLoading(false)
})

Copilot uses AI. Check for mistakes.
Comment on lines +62 to +73
setSnackbar({
show: true,
msg: successMsg
})
} else {
throw new Error(result?.data || errorMsg)
}
} catch (error) {
setSnackbar({
show: true,
msg: error.message || errorMsg
})
Copy link

Copilot AI Apr 13, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

throw new Error(result?.data || errorMsg) can produce an unhelpful message like "[object Object]" when result.data is not a string. Consider normalizing to a string (e.g., prefer result?.data?.message, JSON.stringify for objects, or fallback to errorMsg) before constructing the Error / snackbar message.

Copilot uses AI. Check for mistakes.
className="icn-btn sh-sm ml-2"
type="button"
title={__('Remove', 'bit-integrations')}
aria-label="btn">
Copy link

Copilot AI Apr 13, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The remove button has aria-label="btn", which isn’t descriptive for screen readers. Use an accessible label that describes the action (e.g., “Remove field mapping row”).

Suggested change
aria-label="btn">
aria-label={__('Remove field mapping row', 'bit-integrations')}>

Copilot uses AI. Check for mistakes.
return [
'success' => false,
'message' => wp_sprintf(
__('%s plugin is not installed or activate', 'bit-integrations'),
Copy link

Copilot AI Apr 13, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Typo/grammar in the translatable string: "is not installed or activate" should be "is not installed or activated".

Suggested change
__('%s plugin is not installed or activate', 'bit-integrations'),
__('%s plugin is not installed or activated', 'bit-integrations'),

Copilot uses AI. Check for mistakes.
Comment on lines +392 to +400
foreach ($fieldMap as $value) {
$triggerValue = $value->formField;
$actionValue = $value->columnName;

if ($triggerValue === 'custom' && isset($value->customValue)) {
$dataFinal[$actionValue] = Common::replaceFieldWithValue($value->customValue, $fieldValues);
} elseif (isset($fieldValues[$triggerValue]) && !\is_null($fieldValues[$triggerValue])) {
$dataFinal[$actionValue] = $fieldValues[$triggerValue];
}
Copy link

Copilot AI Apr 13, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

generateReqDataFromFieldMap() writes to $dataFinal[$actionValue] without checking that $actionValue (columnName) is non-empty. With the initial/partially-configured field_map, this can create entries with an empty-string key and overwrite previous values. Skip items where columnName is empty before adding to $dataFinal.

Copilot uses AI. Check for mistakes.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants