@elementor/editor-audits 4.4.0-1118 → 4.4.0-1120

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@elementor/editor-audits",
3
- "version": "4.4.0-1118",
3
+ "version": "4.4.0-1120",
4
4
  "private": false,
5
5
  "author": "Elementor Team",
6
6
  "homepage": "https://elementor.com/",
@@ -39,21 +39,21 @@
39
39
  "dev": "tsup --config=../../tsup.dev.ts"
40
40
  },
41
41
  "dependencies": {
42
- "@elementor/editor": "4.4.0-1118",
43
- "@elementor/editor-mcp": "4.4.0-1118",
44
- "@elementor/editor-app-bar": "4.4.0-1118",
45
- "@elementor/editor-elements": "4.4.0-1118",
46
- "@elementor/editor-floating-panels": "4.4.0-1118",
47
- "@elementor/editor-notifications": "4.4.0-1118",
48
- "@elementor/editor-props": "4.4.0-1118",
49
- "@elementor/editor-styles": "4.4.0-1118",
50
- "@elementor/editor-v1-adapters": "4.4.0-1118",
51
- "@elementor/events": "4.4.0-1118",
52
- "@elementor/http-client": "4.4.0-1118",
42
+ "@elementor/editor": "4.4.0-1120",
43
+ "@elementor/editor-mcp": "4.4.0-1120",
44
+ "@elementor/editor-app-bar": "4.4.0-1120",
45
+ "@elementor/editor-elements": "4.4.0-1120",
46
+ "@elementor/editor-floating-panels": "4.4.0-1120",
47
+ "@elementor/editor-notifications": "4.4.0-1120",
48
+ "@elementor/editor-props": "4.4.0-1120",
49
+ "@elementor/editor-styles": "4.4.0-1120",
50
+ "@elementor/editor-v1-adapters": "4.4.0-1120",
51
+ "@elementor/events": "4.4.0-1120",
52
+ "@elementor/http-client": "4.4.0-1120",
53
53
  "@elementor/icons": "~1.77.0",
54
- "@elementor/locations": "4.4.0-1118",
55
- "@elementor/session": "4.4.0-1118",
56
- "@elementor/store": "4.4.0-1118",
54
+ "@elementor/locations": "4.4.0-1120",
55
+ "@elementor/session": "4.4.0-1120",
56
+ "@elementor/store": "4.4.0-1120",
57
57
  "@elementor/ui": "1.37.5"
58
58
  },
59
59
  "peerDependencies": {
@@ -1,8 +1,7 @@
1
1
  import * as React from 'react';
2
2
  import { getHostDocumentId } from '@elementor/editor-elements';
3
3
  import { FloatingPanelBody, FloatingPanelFooter, FloatingPanelHeader } from '@elementor/editor-floating-panels';
4
- import { ReloadIcon } from '@elementor/icons';
5
- import { Box, Button, Typography } from '@elementor/ui';
4
+ import { Box, Typography } from '@elementor/ui';
6
5
  import { __ } from '@wordpress/i18n';
7
6
 
8
7
  import { AUDIT_PANEL_ID } from '../constants';
@@ -12,9 +11,10 @@ import ErrorPage from './pages/error-page';
12
11
  import LoadingPage from './pages/loading-page';
13
12
  import WelcomePage from './pages/welcome-page';
14
13
  import ReportShell from './report-shell';
14
+ import RescanButton from './rescan-button';
15
15
 
16
16
  export default function AuditPanel() {
17
- const { status, report, error, run } = useAuditReport();
17
+ const { status, report, error, isStale, run } = useAuditReport();
18
18
 
19
19
  const hostDocumentId = getHostDocumentId() ?? 0;
20
20
  const onRun = () => run( hostDocumentId );
@@ -49,15 +49,12 @@ export default function AuditPanel() {
49
49
  <Box sx={ { flex: 1 } } />
50
50
  ) }
51
51
  { lastScanLabel && <AuditFeedback /> }
52
- <Button
53
- variant="contained"
54
- size="small"
55
- startIcon={ lastScanLabel ? <ReloadIcon fontSize="small" /> : undefined }
56
- onClick={ onRun }
52
+ <RescanButton
53
+ hasScanned={ Boolean( lastScanLabel ) }
54
+ isStale={ isStale }
57
55
  disabled={ status === 'loading' || hostDocumentId === 0 }
58
- >
59
- { lastScanLabel ? __( 'Rescan', 'elementor' ) : __( 'Run page audit', 'elementor' ) }
60
- </Button>
56
+ onClick={ onRun }
57
+ />
61
58
  </FloatingPanelFooter>
62
59
  </>
63
60
  );
@@ -0,0 +1,22 @@
1
+ import * as React from 'react';
2
+ import { ShieldCheckIcon } from '@elementor/icons';
3
+ import { __useSelector as useSelector } from '@elementor/store';
4
+ import { Badge } from '@elementor/ui';
5
+
6
+ import { type GlobalState, selectIsStale } from '../store';
7
+
8
+ export default function AuditToggleIcon() {
9
+ const isStale = useSelector( ( state: GlobalState ) => selectIsStale( state ) );
10
+
11
+ return (
12
+ <Badge
13
+ variant="dot"
14
+ color="warning"
15
+ invisible={ ! isStale }
16
+ overlap="circular"
17
+ slotProps={ { badge: { 'data-testid': 'audit-stale-indicator' } } }
18
+ >
19
+ <ShieldCheckIcon />
20
+ </Badge>
21
+ );
22
+ }
@@ -0,0 +1,38 @@
1
+ import * as React from 'react';
2
+ import { useFloatingPanelZIndex } from '@elementor/editor-floating-panels';
3
+ import { ReloadIcon } from '@elementor/icons';
4
+ import { Badge, Button, Tooltip } from '@elementor/ui';
5
+ import { __ } from '@wordpress/i18n';
6
+
7
+ import { AUDIT_PANEL_ID } from '../constants';
8
+
9
+ type Props = {
10
+ hasScanned: boolean;
11
+ isStale: boolean;
12
+ disabled: boolean;
13
+ onClick: () => void;
14
+ };
15
+
16
+ export default function RescanButton( { hasScanned, isStale, disabled, onClick }: Props ) {
17
+ const panelZIndex = useFloatingPanelZIndex( AUDIT_PANEL_ID );
18
+
19
+ return (
20
+ <Tooltip
21
+ title={ __( 'Page content changed - rescan advised', 'elementor' ) }
22
+ disableHoverListener={ ! isStale }
23
+ PopperProps={ { sx: { zIndex: panelZIndex } } }
24
+ >
25
+ <Badge variant="dot" color="warning" invisible={ ! isStale } overlap="rectangular">
26
+ <Button
27
+ variant="contained"
28
+ size="small"
29
+ startIcon={ hasScanned ? <ReloadIcon fontSize="small" /> : undefined }
30
+ onClick={ onClick }
31
+ disabled={ disabled }
32
+ >
33
+ { hasScanned ? __( 'Rescan', 'elementor' ) : __( 'Run page audit', 'elementor' ) }
34
+ </Button>
35
+ </Badge>
36
+ </Tooltip>
37
+ );
38
+ }
@@ -3,7 +3,7 @@ import { getHostDocumentId } from '@elementor/editor-elements';
3
3
  import { __useDispatch as useDispatch, __useSelector as useSelector } from '@elementor/store';
4
4
 
5
5
  import { runPageAudit } from '../runner';
6
- import { type GlobalState, selectError, selectReport, selectStatus, slice } from '../store';
6
+ import { type GlobalState, selectError, selectIsStale, selectReport, selectStatus, slice } from '../store';
7
7
  import { getPersistedReport, persistReport } from '../utils/report-storage';
8
8
  import { SessionExpiredError } from '../utils/session-expiration';
9
9
 
@@ -11,6 +11,7 @@ export function useAuditReport() {
11
11
  const status = useSelector( ( state: GlobalState ) => selectStatus( state ) );
12
12
  const report = useSelector( ( state: GlobalState ) => selectReport( state ) );
13
13
  const error = useSelector( ( state: GlobalState ) => selectError( state ) );
14
+ const isStale = useSelector( ( state: GlobalState ) => selectIsStale( state ) );
14
15
  const dispatch = useDispatch();
15
16
  const documentId = getHostDocumentId() ?? 0;
16
17
 
@@ -45,5 +46,5 @@ export function useAuditReport() {
45
46
  }
46
47
  };
47
48
 
48
- return { status, report, error, run };
49
+ return { status, report, error, isStale, run };
49
50
  }
@@ -1,7 +1,7 @@
1
1
  import { type ToggleActionProps } from '@elementor/editor-app-bar';
2
- import { ShieldCheckIcon } from '@elementor/icons';
3
2
  import { __ } from '@wordpress/i18n';
4
3
 
4
+ import AuditToggleIcon from '../components/audit-toggle-icon';
5
5
  import { auditPanel } from '../editor-panel';
6
6
 
7
7
  export function useAuditToggleProps(): ToggleActionProps {
@@ -10,7 +10,7 @@ export function useAuditToggleProps(): ToggleActionProps {
10
10
 
11
11
  return {
12
12
  title: __( 'Audit Page', 'elementor' ),
13
- icon: ShieldCheckIcon,
13
+ icon: AuditToggleIcon,
14
14
  selected: isOpen,
15
15
  onClick: () => toggle(),
16
16
  };
package/src/init.ts CHANGED
@@ -5,10 +5,12 @@ import { registerAppBarAuditsToggle } from './editor-app-bar';
5
5
  import { auditPanel } from './editor-panel';
6
6
  import { registerAllAudits } from './register-audits';
7
7
  import { slice } from './store/slice';
8
+ import { syncReportStaleness } from './sync-report-staleness';
8
9
 
9
10
  export function init(): void {
10
11
  registerSlice( slice );
11
12
  registerAllAudits();
12
13
  registerFloatingPanel( auditPanel.panel );
13
14
  registerAppBarAuditsToggle();
15
+ syncReportStaleness();
14
16
  }
@@ -13,3 +13,7 @@ export function selectReport( state: GlobalState ) {
13
13
  export function selectError( state: GlobalState ) {
14
14
  return state.audits.error;
15
15
  }
16
+
17
+ export function selectIsStale( state: GlobalState ) {
18
+ return state.audits.isStale;
19
+ }
@@ -6,9 +6,10 @@ type SliceState = {
6
6
  status: 'idle' | 'loading' | 'error' | 'ready';
7
7
  report: PageAuditReport | null;
8
8
  error: string | null;
9
+ isStale: boolean;
9
10
  };
10
11
 
11
- const initialState: SliceState = { status: 'idle', report: null, error: null };
12
+ const initialState: SliceState = { status: 'idle', report: null, error: null, isStale: false };
12
13
 
13
14
  export const slice = __createSlice( {
14
15
  name: 'audits',
@@ -21,6 +22,7 @@ export const slice = __createSlice( {
21
22
  runSucceeded( state, action: PayloadAction< PageAuditReport > ) {
22
23
  state.status = 'ready';
23
24
  state.report = action.payload;
25
+ state.isStale = false;
24
26
  },
25
27
  runFailed( state, action: PayloadAction< string > ) {
26
28
  state.status = 'error';
@@ -33,11 +35,18 @@ export const slice = __createSlice( {
33
35
  state.status = 'ready';
34
36
  state.report = action.payload;
35
37
  state.error = null;
38
+ state.isStale = false;
36
39
  },
37
40
  reportCleared( state ) {
38
41
  state.status = 'idle';
39
42
  state.report = null;
40
43
  state.error = null;
44
+ state.isStale = false;
45
+ },
46
+ reportStale( state ) {
47
+ if ( state.report ) {
48
+ state.isStale = true;
49
+ }
41
50
  },
42
51
  },
43
52
  } );
@@ -0,0 +1,14 @@
1
+ import { __privateListenTo as listenTo, commandEndEvent, type CommandEvent } from '@elementor/editor-v1-adapters';
2
+ import { __dispatch as dispatch } from '@elementor/store';
3
+
4
+ import { slice } from './store/slice';
5
+
6
+ export function syncReportStaleness() {
7
+ listenTo( commandEndEvent( 'document/save/set-is-modified' ), ( e ) => {
8
+ const event = e as CommandEvent< { status: boolean } >;
9
+
10
+ if ( event.args?.status ) {
11
+ dispatch( slice.actions.reportStale() );
12
+ }
13
+ } );
14
+ }