Skip to content

Commit

Permalink
Plugin Scheduler: Check for file mod capabilities (#88124)
Browse files Browse the repository at this point in the history
This prevents the plugin scheduler UI from loading if we don't have file mod capabilities.
  • Loading branch information
vishnugopal authored Mar 7, 2024
1 parent 9a0e205 commit 52a957f
Show file tree
Hide file tree
Showing 7 changed files with 146 additions and 37 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
import { useUpdateScheduleCapabilitiesQuery } from 'calypso/data/plugins/use-update-schedules-capabilities-query';

const DEFAULT_FILE_MOD_PERMISSIONS = {
modify_files: false,
autoupdate_files: false,
errors: undefined,
};

interface UseCanCreateSchedulesReturn {
canCreateSchedules: boolean;
errors?: { code: string; message: string }[];
isLoading: boolean;
}

export function useCanCreateSchedules( siteSlug: string ): UseCanCreateSchedulesReturn {
const { data, isLoading } = useUpdateScheduleCapabilitiesQuery( siteSlug );
const {
modify_files: modifyFiles,
autoupdate_files: autoUpdateFiles,
errors,
} = data || DEFAULT_FILE_MOD_PERMISSIONS;

// we assume we can create schedules until the API reports back.
const canCreateSchedules = isLoading ? true : modifyFiles && autoUpdateFiles;

return { canCreateSchedules, errors, isLoading };
}
12 changes: 7 additions & 5 deletions client/blocks/plugins-update-manager/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import NavigationHeader from 'calypso/components/navigation-header';
import { useUpdateScheduleQuery } from 'calypso/data/plugins/use-update-schedules-query';
import { MAX_SCHEDULES } from './config';
import { PluginUpdateManagerContextProvider } from './context';
import { useCanCreateSchedules } from './hooks/use-can-create-schedules';
import { ScheduleCreate } from './schedule-create';
import { ScheduleEdit } from './schedule-edit';
import { ScheduleList } from './schedule-list';
Expand All @@ -20,11 +21,14 @@ interface Props {
onCreateNewSchedule?: () => void;
onEditSchedule: ( id: string ) => void;
}

export const PluginsUpdateManager = ( props: Props ) => {
const { siteSlug, context, scheduleId, onNavBack, onCreateNewSchedule, onEditSchedule } = props;
const { data: schedules = [] } = useUpdateScheduleQuery( siteSlug );
const hideCreateButton = schedules.length === MAX_SCHEDULES || schedules.length === 0;

const { canCreateSchedules } = useCanCreateSchedules( siteSlug );

const { component, title } = {
list: {
component: (
Expand All @@ -41,9 +45,7 @@ export const PluginsUpdateManager = ( props: Props ) => {
title: 'Create a new schedule',
},
edit: {
component: (
<ScheduleEdit scheduleId={ scheduleId } onNavBack={ onNavBack } />
),
component: <ScheduleEdit scheduleId={ scheduleId } onNavBack={ onNavBack } />,
title: 'Edit schedule',
},
}[ context ];
Expand All @@ -62,15 +64,15 @@ export const PluginsUpdateManager = ( props: Props ) => {
<Button
__next40pxDefaultSize
icon={ plus }
variant="primary"
variant={ canCreateSchedules ? 'primary' : 'secondary' }
onClick={ onCreateNewSchedule }
disabled={ ! canCreateSchedules }
>
Create a new schedule
</Button>
) }
</NavigationHeader>
{ component }

</MainComponent>
</PluginUpdateManagerContextProvider>
);
Expand Down
20 changes: 18 additions & 2 deletions client/blocks/plugins-update-manager/schedule-create.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,11 +6,13 @@ import {
CardHeader,
CardBody,
CardFooter,
Icon,
} from '@wordpress/components';
import { arrowLeft } from '@wordpress/icons';
import { arrowLeft, warning } from '@wordpress/icons';
import { useEffect } from 'react';
import { useUpdateScheduleQuery } from 'calypso/data/plugins/use-update-schedules-query';
import { MAX_SCHEDULES } from './config';
import { useCanCreateSchedules } from './hooks/use-can-create-schedules';
import { useSiteSlug } from './hooks/use-site-slug';
import { ScheduleForm } from './schedule-form';

Expand All @@ -20,7 +22,9 @@ interface Props {
export const ScheduleCreate = ( props: Props ) => {
const siteSlug = useSiteSlug();
const { onNavBack } = props;

const { data: schedules = [], isFetched } = useUpdateScheduleQuery( siteSlug );
const { canCreateSchedules } = useCanCreateSchedules( siteSlug );

const mutationState = useMutationState( {
filters: { mutationKey: [ 'create-update-schedule', siteSlug ] },
Expand Down Expand Up @@ -50,9 +54,21 @@ export const ScheduleCreate = ( props: Props ) => {
<ScheduleForm onSyncSuccess={ () => onNavBack && onNavBack() } />
</CardBody>
<CardFooter>
<Button form="schedule" type="submit" variant="primary" isBusy={ isBusy }>
<Button
form="schedule"
type="submit"
variant={ canCreateSchedules ? 'primary' : 'secondary' }
disabled={ ! canCreateSchedules }
isBusy={ isBusy }
>
Create
</Button>
{ ! canCreateSchedules && (
<Text as="p">
<Icon className="icon-info" icon={ warning } size={ 16 } />
This site is unable to schedule auto-updates for plugins.
</Text>
) }
</CardFooter>
</Card>
);
Expand Down
20 changes: 18 additions & 2 deletions client/blocks/plugins-update-manager/schedule-edit.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,11 @@ import {
CardHeader,
CardBody,
CardFooter,
Icon,
} from '@wordpress/components';
import { arrowLeft } from '@wordpress/icons';
import { arrowLeft, warning } from '@wordpress/icons';
import { useUpdateScheduleQuery } from 'calypso/data/plugins/use-update-schedules-query';
import { useCanCreateSchedules } from './hooks/use-can-create-schedules';
import { useSiteSlug } from './hooks/use-site-slug';
import { ScheduleForm } from './schedule-form';

Expand All @@ -28,6 +30,8 @@ export const ScheduleEdit = ( props: Props ) => {
} );
const isBusy = mutationState.filter( ( { status } ) => status === 'pending' ).length > 0;

const { canCreateSchedules } = useCanCreateSchedules( siteSlug );

// If the schedule is not found, navigate back to the list
if ( isFetched && ! schedule ) {
onNavBack && onNavBack();
Expand Down Expand Up @@ -56,9 +60,21 @@ export const ScheduleEdit = ( props: Props ) => {
) }
</CardBody>
<CardFooter>
<Button form="schedule" type="submit" variant="primary" isBusy={ isBusy }>
<Button
form="schedule"
type="submit"
variant={ canCreateSchedules ? 'primary' : 'secondary' }
isBusy={ isBusy }
disabled={ ! canCreateSchedules }
>
Save
</Button>
{ ! canCreateSchedules && (
<Text as="p">
<Icon className="icon-info" icon={ warning } size={ 16 } />
This site is unable to schedule auto-updates for plugins.
</Text>
) }
</CardFooter>
</Card>
);
Expand Down
11 changes: 8 additions & 3 deletions client/blocks/plugins-update-manager/schedule-list-empty.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,21 +2,26 @@ import { __experimentalText as Text, Button } from '@wordpress/components';
import { plus } from '@wordpress/icons';

interface Props {
canCreateSchedules: boolean;
onCreateNewSchedule?: () => void;
}
export const ScheduleListEmpty = ( props: Props ) => {
const { onCreateNewSchedule } = props;
const { onCreateNewSchedule, canCreateSchedules } = props;

return (
<div className="empty-state">
<Text as="p" align="center">
Set up plugin update schedules to ensure your site runs smoothly.
{ ! canCreateSchedules
? 'This site is unable to schedule auto-updates for plugins.'
: 'Set up plugin update schedules to ensure your site runs smoothly.' }
</Text>
{ onCreateNewSchedule && (
<Button
__next40pxDefaultSize
icon={ plus }
variant="primary"
variant={ canCreateSchedules ? 'primary' : 'secondary' }
onClick={ onCreateNewSchedule }
disabled={ ! canCreateSchedules }
>
Create a new schedule
</Button>
Expand Down
64 changes: 39 additions & 25 deletions client/blocks/plugins-update-manager/schedule-list.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ import { useState } from 'react';
import { useDeleteUpdateScheduleMutation } from 'calypso/data/plugins/use-update-schedules-mutation';
import { useUpdateScheduleQuery } from 'calypso/data/plugins/use-update-schedules-query';
import { MAX_SCHEDULES } from './config';
import { useCanCreateSchedules } from './hooks/use-can-create-schedules';
import { useSiteSlug } from './hooks/use-site-slug';
import { ScheduleListCards } from './schedule-list-cards';
import { ScheduleListEmpty } from './schedule-list-empty';
Expand Down Expand Up @@ -40,6 +41,8 @@ export const ScheduleList = ( props: Props ) => {
const { deleteUpdateSchedule } = useDeleteUpdateScheduleMutation( siteSlug, {
onSuccess: () => refetch(),
} );
const { canCreateSchedules, isLoading: isLoadingCanCreateSchedules } =
useCanCreateSchedules( siteSlug );

const openRemoveDialog = ( id: string ) => {
setRemoveDialogOpen( true );
Expand Down Expand Up @@ -78,31 +81,42 @@ export const ScheduleList = ( props: Props ) => {
<div className="ch-placeholder"></div>
</CardHeader>
<CardBody>
{ isLoading && <Spinner /> }
{ isFetched && schedules.length === 0 && (
<ScheduleListEmpty onCreateNewSchedule={ onCreateNewSchedule } />
) }
{ isFetched && schedules.length > 0 && (
<>
{ isMobile ? (
<ScheduleListCards
onRemoveClick={ openRemoveDialog }
onEditClick={ onEditSchedule }
/>
) : (
<ScheduleListTable
onRemoveClick={ openRemoveDialog }
onEditClick={ onEditSchedule }
/>
) }
</>
) }
{ isFetched && schedules.length >= MAX_SCHEDULES && (
<Text as="p">
<Icon className="icon-info" icon={ info } size={ 16 } />
The current feature implementation only allows to set up two schedules.
</Text>
) }
{ ( isLoading || isLoadingCanCreateSchedules ) && <Spinner /> }
{ isFetched &&
! isLoadingCanCreateSchedules &&
( schedules.length === 0 || ! canCreateSchedules ) && (
<ScheduleListEmpty
onCreateNewSchedule={ onCreateNewSchedule }
canCreateSchedules={ canCreateSchedules }
/>
) }
{ isFetched &&
! isLoadingCanCreateSchedules &&
schedules.length > 0 &&
canCreateSchedules && (
<>
{ isMobile ? (
<ScheduleListCards
onRemoveClick={ openRemoveDialog }
onEditClick={ onEditSchedule }
/>
) : (
<ScheduleListTable
onRemoveClick={ openRemoveDialog }
onEditClick={ onEditSchedule }
/>
) }
</>
) }
{ isFetched &&
! isLoadingCanCreateSchedules &&
schedules.length >= MAX_SCHEDULES &&
canCreateSchedules && (
<Text as="p">
<Icon className="icon-info" icon={ info } size={ 16 } />
The current feature implementation only allows to set up two schedules.
</Text>
) }
</CardBody>
</Card>
</>
Expand Down
29 changes: 29 additions & 0 deletions client/data/plugins/use-update-schedules-capabilities-query.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
import { useQuery, UseQueryResult } from '@tanstack/react-query';
import wpcomRequest from 'wpcom-proxy-request';
import type { SiteSlug } from 'calypso/types';

export type ScheduleUpdatesCapabilities = {
modify_files: boolean;
autoupdate_files: boolean;
errors?: { code: string; message: string }[];
};

export const useUpdateScheduleCapabilitiesQuery = (
siteSlug: SiteSlug
): UseQueryResult< ScheduleUpdatesCapabilities > => {
return useQuery( {
queryKey: [ 'schedule-updates-capabilities', siteSlug ],
queryFn: () =>
wpcomRequest( {
path: `/sites/${ siteSlug }/update-schedules/capabilities`,
apiNamespace: 'wpcom/v2',
method: 'GET',
} ),
meta: {
persist: false,
},
enabled: !! siteSlug,
retry: false,
refetchOnWindowFocus: false,
} );
};

0 comments on commit 52a957f

Please sign in to comment.