Skip to content

Commit 1f2763d

Browse files
authored
Merge branch 'development' into feat/pro/3077
2 parents e64cb40 + edb78a7 commit 1f2763d

File tree

10 files changed

+464
-44
lines changed

10 files changed

+464
-44
lines changed

.github/workflows/diff-translations.yml

Lines changed: 20 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -5,71 +5,48 @@ on:
55
pull_request:
66
types: [opened, edited, synchronize, ready_for_review]
77
branches:
8-
- "development"
9-
- "new/**"
8+
- development
9+
- master
1010

1111
jobs:
1212
translation:
1313
runs-on: ubuntu-latest
1414
steps:
15-
- name: Checkout Ref Base
15+
- name: Checkout Base Branch
1616
uses: actions/checkout@v4
1717
with:
18-
path: neve-head
18+
ref: ${{ github.base_ref }}
19+
path: neve-base
1920
- name: Setup node 16
2021
uses: actions/setup-node@v4
2122
with:
2223
node-version: 16.x
23-
- name: FRESH Makepot BASE
24+
- name: Build POT for Base Branch
2425
run: |
25-
cd neve-head
26+
cd neve-base
2627
ls languages/
2728
composer install --no-dev --prefer-dist --no-progress --no-suggest
2829
yarn install --frozen-lockfile
2930
yarn run build
3031
ls languages/
31-
- name: Checkout Ref Head
32-
uses: actions/checkout@v2
32+
- name: Checkout PR Branch (Head)
33+
uses: actions/checkout@v4
3334
with:
34-
ref: development
35-
path: neve-base
36-
- name: FRESH Makepot HEAD
35+
path: neve-head
36+
- name: Build POT for PR Branch
3737
run: |
38-
cd neve-base
38+
cd neve-head
3939
ls languages/
4040
composer install --no-dev --prefer-dist --no-progress --no-suggest
4141
yarn install --frozen-lockfile
4242
yarn run build
4343
ls languages/
44-
- name: Find Comment
45-
uses: peter-evans/find-comment@v1
46-
id: find_coomment
47-
with:
48-
issue-number: ${{ github.event.pull_request.number }}
49-
comment-author: "pirate-bot"
50-
body-includes: PR has POT difference
51-
- name: Install PODiff
52-
run: |
53-
curl -o podiff.gz ftp://download.gnu.org.ua/pub/releases/podiff/podiff-1.3.tar.gz
54-
tar -xf podiff.gz
55-
cd podiff-1.3
56-
make
57-
mkdir -p $GITHUB_WORKSPACE/bin
58-
mv ./podiff $GITHUB_WORKSPACE/bin
59-
echo "$GITHUB_WORKSPACE/bin" >> $GITHUB_PATH
60-
cd ..
61-
- name: Run Podiff
62-
id: translation_status
63-
run: |
64-
${GITHUB_WORKSPACE}/neve-head/bin/pot-diff.sh ./neve-base/languages/neve.pot ./neve-head/languages/neve.pot $PERCENT_TRESHOLD
65-
- name: Step require review
66-
if: steps.translation_status.outputs.has_pot_diff != 'success'
67-
uses: Automattic/action-required-review@v2
44+
- name: Compare POT files
45+
uses: Codeinwp/action-i18n-string-reviewer@main
6846
with:
69-
requirements: |
70-
- name: Everything else
71-
paths: unmatched
72-
teams:
73-
- "admin-neve"
74-
status: Has translation changes, a review admin-neve team is required
75-
token: ${{ secrets.BOT_TOKEN }}
47+
fail-on-changes: 'true'
48+
openrouter-key: ${{ secrets.OPEN_ROUTER_API_KEY }}
49+
openrouter-model: 'google/gemini-2.5-flash'
50+
base-pot-file: 'neve-base/languages/neve.pot'
51+
target-pot-file: 'neve-head/languages/neve.pot'
52+
github-token: ${{ secrets.BOT_TOKEN }}
Lines changed: 213 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,213 @@
1+
/* global neveDash */
2+
import { __ } from '@wordpress/i18n';
3+
import {
4+
NEVE_AVAILABLE_MODULES_ICON_MAP,
5+
NEVE_STORE,
6+
} from '../../utils/constants';
7+
import { ArrowRight, LoaderCircle, LucideSettings } from 'lucide-react';
8+
import Card from '../../Layout/Card';
9+
import { useState } from '@wordpress/element';
10+
import { useDispatch, useSelect } from '@wordpress/data';
11+
import Toggle from '../Common/Toggle';
12+
import { send } from '../../utils/rest';
13+
14+
const Toast = ({ message }) => {
15+
return (
16+
<div className="fixed flex items-center gap-2 z-[99999] top-10 right-5 bg-white text-black text-base font-medium px-4 py-2 rounded shadow border border-solid border-blue-600">
17+
{message}
18+
</div>
19+
);
20+
};
21+
22+
const ModuleToggle = ({
23+
slug,
24+
moduleData,
25+
setMessage,
26+
isActive,
27+
setIsActive,
28+
isInstalled,
29+
setIsInstalled,
30+
}) => {
31+
const [loading, setLoading] = useState(false);
32+
const { changeModuleStatus, setObfxModuleStatus, setToast } =
33+
useDispatch(NEVE_STORE);
34+
const { moduleStatus } = useSelect((select) => {
35+
const { getObfxModuleStatus } = select(NEVE_STORE);
36+
37+
return {
38+
moduleStatus: getObfxModuleStatus(slug) || false,
39+
};
40+
});
41+
42+
const { api } = neveDash;
43+
const { title } = moduleData;
44+
const toastMessage = {
45+
installing: __('Installing', 'neve'),
46+
activating: __('Activating', 'neve'),
47+
};
48+
49+
const handleToggle = async (value) => {
50+
try {
51+
setLoading(true);
52+
changeModuleStatus(slug, value);
53+
54+
let isPluginActive = true;
55+
// Handle plugin installation or activation
56+
if (!isInstalled) {
57+
setMessage(toastMessage.installing);
58+
isPluginActive = false;
59+
} else if (!isActive) {
60+
setMessage(toastMessage.activating);
61+
isPluginActive = false;
62+
}
63+
64+
if (!isPluginActive) {
65+
await send(api + 'activate-plugin', {
66+
slug: 'themeisle-companion',
67+
}).then((res) => {
68+
if (res.success) {
69+
setIsInstalled(true);
70+
setIsActive(true);
71+
}
72+
});
73+
}
74+
75+
// Fire the send method after install/activate or immediately if both are done
76+
const response = await send(api + 'activate-module', {
77+
slug,
78+
value,
79+
});
80+
81+
setObfxModuleStatus(slug, response.success ? value : !value);
82+
setToast(
83+
response.success
84+
? (value
85+
? __('Module Activated', 'neve')
86+
: __('Module Deactivated.', 'neve')) + ` (${title})`
87+
: response.data
88+
);
89+
} catch (error) {
90+
setToast(
91+
__(
92+
'Something went wrong. Please reload the page and try again.',
93+
'neve'
94+
)
95+
);
96+
} finally {
97+
setLoading(false);
98+
setMessage('');
99+
}
100+
};
101+
102+
return (
103+
<div className="flex gap-2 items-center">
104+
<Toggle
105+
checked={moduleStatus}
106+
onToggle={handleToggle}
107+
disabled={loading}
108+
/>
109+
</div>
110+
);
111+
};
112+
113+
const AvailableModuleCard = ({
114+
moduleData,
115+
slug,
116+
setMessage,
117+
isActive,
118+
setIsActive,
119+
isInstalled,
120+
setIsInstalled,
121+
}) => {
122+
const { title, description } = moduleData;
123+
const CardIcon = NEVE_AVAILABLE_MODULES_ICON_MAP[slug] || LucideSettings;
124+
125+
return (
126+
<Card
127+
icon={<CardIcon size={18} />}
128+
title={title}
129+
className="bg-white p-6 rounded-lg shadow-sm"
130+
afterTitle={
131+
<ModuleToggle
132+
slug={slug}
133+
moduleData={moduleData}
134+
setMessage={setMessage}
135+
isActive={isActive}
136+
setIsActive={setIsActive}
137+
isInstalled={isInstalled}
138+
setIsInstalled={setIsInstalled}
139+
/>
140+
}
141+
id={`module-${slug}`}
142+
>
143+
<p className="text-gray-600 text-sm leading-relaxed">
144+
{description}
145+
</p>
146+
{!isActive ? (
147+
<p className="mt-2 italic text-sm text-gray-500">
148+
{__(
149+
'This feature is part of OrbitFox plugin, built by the Neve team. Enabling the toggle will automatically install and activate the plugin.',
150+
'neve'
151+
)}
152+
</p>
153+
) : (
154+
<a
155+
className="flex mt-2 text-blue-600 gap-2 align-middle"
156+
href="admin.php?page=obfx_companion"
157+
>
158+
{__('Settings', 'neve')}
159+
<ArrowRight size={18} />
160+
</a>
161+
)}
162+
</Card>
163+
);
164+
};
165+
166+
export default () => {
167+
const [message, setMessage] = useState('');
168+
const [isInstalled, setIsInstalled] = useState(
169+
neveDash.orbitFox.isInstalled
170+
);
171+
const [isActive, setIsActive] = useState(neveDash.orbitFox.isActive);
172+
173+
return (
174+
<>
175+
<div className="mb-6">
176+
<div className="flex items-center justify-between">
177+
<h2 className="text-lg font-semibold">
178+
{__('Available Modules', 'neve')}
179+
</h2>
180+
</div>
181+
<div className="grid xl:grid-cols-2 gap-6">
182+
{Object.entries(neveDash.availableModules).map(
183+
([slug, moduleData]) => (
184+
<AvailableModuleCard
185+
key={slug}
186+
slug={slug}
187+
moduleData={moduleData}
188+
setMessage={setMessage}
189+
isActive={isActive}
190+
setIsActive={setIsActive}
191+
isInstalled={isInstalled}
192+
setIsInstalled={setIsInstalled}
193+
/>
194+
)
195+
)}
196+
</div>
197+
</div>
198+
{message && (
199+
<Toast
200+
message={
201+
<>
202+
<LoaderCircle
203+
size={18}
204+
className="animate-spin text-blue-800"
205+
/>
206+
{message}
207+
</>
208+
}
209+
/>
210+
)}
211+
</>
212+
);
213+
};
Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,11 @@
1+
import AvailableModule from '../AvailableModule';
12
import ModuleGrid from '../ModuleGrid';
23

34
export default () => {
4-
return <ModuleGrid />;
5+
return (
6+
<>
7+
<AvailableModule />
8+
<ModuleGrid />
9+
</>
10+
);
511
};

assets/apps/dashboard/src/store/actions.js

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -50,4 +50,10 @@ export default {
5050
payload: loggerStatus,
5151
};
5252
},
53+
setObfxModuleStatus(slug, value) {
54+
return {
55+
type: 'SET_OBFX_MODULE_STATUS',
56+
payload: { slug, value },
57+
};
58+
},
5359
};

assets/apps/dashboard/src/store/reducer.js

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ const initialState = {
88
currentTab: 'start',
99
license: neveDash.pro ? neveDash.license : {},
1010
notifications: neveDash.notifications || {},
11+
obfxModuleStatus: neveDash.orbitFox?.data?.module_status || {},
1112
};
1213

1314
const hash = getTabHash();
@@ -73,6 +74,16 @@ const reducer = (state = initialState, action) => {
7374
neve_logger_flag: action.payload,
7475
},
7576
};
77+
case 'SET_OBFX_MODULE_STATUS':
78+
return {
79+
...state,
80+
obfxModuleStatus: {
81+
...state.obfxModuleStatus,
82+
[action.payload.slug]: {
83+
active: action.payload.value,
84+
},
85+
},
86+
};
7687
}
7788
return state;
7889
};

assets/apps/dashboard/src/store/selectors.js

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,4 +25,15 @@ export default {
2525

2626
return shownNotifications;
2727
},
28+
getObfxModuleStatus: (state, slug) => {
29+
if (!state.obfxModuleStatus) {
30+
return false;
31+
}
32+
33+
if (state.obfxModuleStatus[slug]) {
34+
return state.obfxModuleStatus[slug]?.active || false;
35+
}
36+
37+
return false;
38+
},
2839
};

0 commit comments

Comments
 (0)