Skip to content
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

Domains: Add Glue Records management UI #84261

Merged
merged 27 commits into from
Dec 7, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
27 commits
Select commit Hold shift + click to select a range
3f934b7
Add initial structure
rafaelgallani Nov 16, 2023
5d7c72e
Fix styles
rafaelgallani Nov 16, 2023
9168139
Improve styles
rafaelgallani Nov 16, 2023
61d5f8a
Add feature flags
rafaelgallani Nov 16, 2023
c38f8ff
Replace `Remove` link with button
rafaelgallani Nov 16, 2023
5fbda46
Improve loading state
rafaelgallani Nov 16, 2023
2cd08e6
Improve placeholder labels
rafaelgallani Nov 16, 2023
f8ef6ee
Update field labels
rafaelgallani Nov 16, 2023
3fabb12
Add limit of glue records
rafaelgallani Nov 16, 2023
731d11b
Improve react-query cached data
rafaelgallani Nov 17, 2023
8a947ed
Include placeholder style
rafaelgallani Nov 17, 2023
69de37c
Force lowercase nameservers
rafaelgallani Nov 17, 2023
4e80a2f
Render `Add Glue Records` action only when necessary
rafaelgallani Nov 17, 2023
34a92bb
Fix cancel button behavior
rafaelgallani Nov 17, 2023
6e7ad11
Lazy query
rafaelgallani Nov 17, 2023
0e4996c
Improve data caching
rafaelgallani Nov 18, 2023
6ef3d3b
Only show glue records card for domains registered with us
leonardost Dec 6, 2023
63bdcdb
Fix comments
leonardost Dec 6, 2023
39b4faa
Validate record and IP address fields before saving glue record
leonardost Dec 6, 2023
e13a064
Rename method `handleAddGlueRecord` to `showGlueRecordForm`
leonardost Dec 6, 2023
3e9706f
Fix comment
leonardost Dec 6, 2023
c4ce459
Add missing dependency for `useEffect`
leonardost Dec 6, 2023
169d6aa
Simplify condition
leonardost Dec 6, 2023
4fd3340
Only show glue records card for domains registered through Key-Systems
leonardost Dec 6, 2023
37512d5
Add error validation message to glue record fields
leonardost Dec 7, 2023
8c436ab
Remove references to domain forwarding and simplify CSS
leonardost Dec 7, 2023
4b49961
Fetch data when expanding card to prevent stale data from being shown
leonardost Dec 7, 2023
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
2 changes: 2 additions & 0 deletions client/components/domains/accordion/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ const Accordion = ( {
isDisabled,
expanded = false,
onClose,
onOpen,
className,
}: AccordionProps ) => {
const classes = classNames( {
Expand Down Expand Up @@ -49,6 +50,7 @@ const Accordion = ( {
</button>
}
onClose={ onClose }
onOpen={ onOpen }
>
{ children }
</FoldableCard>
Expand Down
1 change: 1 addition & 0 deletions client/components/domains/accordion/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ export type AccordionProps = {
subtitle?: string | React.ReactNode;
expanded?: boolean;
onClose?: () => void;
onOpen?: () => void;

isPlaceholder?: boolean;
isDisabled?: boolean;
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
import { QueryKey } from '@tanstack/react-query';

export function domainGlueRecordQueryKey( domainName: string ): QueryKey {
return [ 'glue-record', domainName ];
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
import { useMutation, useQueryClient } from '@tanstack/react-query';
import { useCallback } from 'react';
import { domainGlueRecordQueryKey } from 'calypso/data/domains/glue-records/domain-glue-record-query-key';
import {
GlueRecordObject,
GlueRecordQueryData,
} from 'calypso/data/domains/glue-records/use-domain-glue-records-query';
import { DomainsApiError } from 'calypso/lib/domains/types';
import wp from 'calypso/lib/wp';

export default function useDeleteGlueRecordMutation(
domainName: string,
queryOptions: {
onSuccess?: () => void;
onError?: ( error: DomainsApiError ) => void;
}
) {
const queryClient = useQueryClient();
const mutation = useMutation( {
mutationFn: ( glueRecord: GlueRecordObject ) =>
wp.req
.post(
{
path: `/domains/glue-records/${ domainName }`,
apiNamespace: 'wpcom/v2',
method: 'DELETE',
},
{
name_server: glueRecord.record,
}
)
.then( () => glueRecord ),
...queryOptions,
onSuccess( glueRecord: GlueRecordObject ) {
const key = domainGlueRecordQueryKey( domainName );
queryClient.setQueryData( key, ( old: GlueRecordQueryData ) => {
if ( ! old ) {
return [];
}
return old.filter( ( item ) => item.nameserver !== glueRecord.record );
} );
queryOptions.onSuccess?.();
},
} );

const { mutate } = mutation;

const deleteGlueRecord = useCallback(
( glueRecord: GlueRecordObject ) => mutate( glueRecord ),
[ mutate ]
);

return { deleteGlueRecord, ...mutation };
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
import { UseQueryResult, useQuery } from '@tanstack/react-query';
import wp from 'calypso/lib/wp';
import { domainGlueRecordQueryKey } from './domain-glue-record-query-key';

export type Maybe< T > = T | null | undefined;
export type GlueRecordResponse = GlueRecordObject[] | null | undefined;

export type GlueRecordObject = {
record: string;
address: string;
};

export type GlueRecordQueryData = Maybe< GlueRecordApiObject[] >;

export type GlueRecordApiObject = {
nameserver: string;
ip_addresses: string[];
};

export const mapGlueRecordObjectToApiObject = ( record: GlueRecordObject ): GlueRecordApiObject => {
return {
nameserver: record.record.toLowerCase(),
ip_addresses: [ record.address ],
};
};

const selectGlueRecords = ( response: GlueRecordApiObject[] | null ): GlueRecordResponse => {
if ( ! response ) {
return null;
}

return response?.map( ( record: GlueRecordApiObject ) => {
return {
record: record.nameserver.toLowerCase(),
address: record.ip_addresses[ 0 ],
};
} );
};

export default function useDomainGlueRecordsQuery(
domainName: string
): UseQueryResult< GlueRecordResponse > {
return useQuery( {
queryKey: domainGlueRecordQueryKey( domainName ),
queryFn: () =>
wp.req.get( {
path: `/domains/glue-records/${ domainName }`,
apiNamespace: 'wpcom/v2',
} ),
refetchOnWindowFocus: false,
select: selectGlueRecords,
enabled: false,
staleTime: 5 * 60 * 1000,
cacheTime: 5 * 60 * 1000,
} );
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
import { useMutation, useQueryClient } from '@tanstack/react-query';
import { useCallback } from 'react';
import { domainGlueRecordQueryKey } from 'calypso/data/domains/glue-records/domain-glue-record-query-key';
import { DomainsApiError } from 'calypso/lib/domains/types';
import wp from 'calypso/lib/wp';
import {
GlueRecordObject,
GlueRecordQueryData,
mapGlueRecordObjectToApiObject,
} from './use-domain-glue-records-query';

export default function useUpdateGlueRecordMutation(
domainName: string,
queryOptions: {
onSuccess?: () => void;
onError?: ( error: DomainsApiError ) => void;
}
) {
const queryClient = useQueryClient();
const mutation = useMutation( {
mutationFn: ( glueRecord: GlueRecordObject ) =>
wp.req
.post(
{
path: `/domains/glue-records`,
apiNamespace: 'wpcom/v2',
},
{
name_server: glueRecord.record.toLowerCase(),
ip_addresses: [ glueRecord.address ],
}
)
.then( () => glueRecord ),
...queryOptions,
onSuccess( glueRecord: GlueRecordObject ) {
const key = domainGlueRecordQueryKey( domainName );
queryClient.setQueryData( key, ( old: GlueRecordQueryData ) => {
if ( ! old ) {
return [ mapGlueRecordObjectToApiObject( glueRecord ) ];
}
return [ ...old, mapGlueRecordObjectToApiObject( glueRecord ) ];
} );
queryOptions.onSuccess?.();
},
onError( error: DomainsApiError ) {
queryOptions.onError?.( error );
},
} );

const { mutate } = mutation;

const updateGlueRecord = useCallback(
( glueRecord: GlueRecordObject ) => mutate( glueRecord ),
[ mutate ]
);

return { updateGlueRecord, ...mutation };
}
Loading
Loading