Skip to content

Commit f8584b3

Browse files
upcoming: [UIE-9780] - Add new API endpoints, types and queries for R… (#13187)
* upcoming: [UIE-9780] - Add new API endpoints, types and queries for Resource Locking feature(RESPROT2) * Added changeset: Add new API endpoints and types for Resource Locking feature(RESPROT2) * Added changeset: Add new API queries for CRUD of locks for Resource Locking feature(RESPROT2) * Address review comments.
1 parent 3e1af13 commit f8584b3

File tree

9 files changed

+231
-0
lines changed

9 files changed

+231
-0
lines changed
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
"@linode/api-v4": Upcoming Features
3+
---
4+
5+
Add new API endpoints and types for Resource Locking feature(RESPROT2) ([#13187](https://github.com/linode/manager/pull/13187))

packages/api-v4/src/index.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,8 @@ export * from './kubernetes';
2424

2525
export * from './linodes';
2626

27+
export * from './locks';
28+
2729
export * from './longview';
2830

2931
export * from './managed';

packages/api-v4/src/locks/index.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
export * from './locks';
2+
3+
export * from './types';

packages/api-v4/src/locks/locks.ts

Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
1+
import { BETA_API_ROOT } from '../constants';
2+
import Request, { setData, setMethod, setURL, setXFilter } from '../request';
3+
4+
import type { Filter, ResourcePage as Page, Params } from '../types';
5+
import type { CreateLockPayload, ResourceLock } from './types';
6+
7+
/**
8+
* getLocks
9+
*
10+
* Returns a paginated list of resource locks on your Account.
11+
*
12+
* @param params { Params } Pagination parameters
13+
* @param filters { Filter } X-Filter for API
14+
*/
15+
export const getLocks = (params?: Params, filters?: Filter) =>
16+
Request<Page<ResourceLock>>(
17+
setURL(`${BETA_API_ROOT}/locks`),
18+
setMethod('GET'),
19+
setXFilter(filters),
20+
);
21+
22+
/**
23+
* getLock
24+
*
25+
* Returns information about a single resource lock.
26+
*
27+
* @param lockId { number } The ID of the lock to retrieve.
28+
*/
29+
export const getLock = (lockId: number) =>
30+
Request<ResourceLock>(
31+
setURL(`${BETA_API_ROOT}/locks/${encodeURIComponent(lockId)}`),
32+
setMethod('GET'),
33+
);
34+
35+
/**
36+
* createLock
37+
*
38+
* Creates a new resource lock to prevent accidental deletion or modification.
39+
*
40+
* @param payload { CreateLockPayload } The lock creation payload
41+
* @param payload.entity_type { string } The type of entity to lock (e.g., 'linode')
42+
* @param payload.entity_id { number | string } The ID of the entity to lock
43+
* @param payload.lock_type { string } The type of lock ('cannot_delete', 'cannot_delete_with_subresources')
44+
*/
45+
export const createLock = (payload: CreateLockPayload) =>
46+
Request<ResourceLock>(
47+
setURL(`${BETA_API_ROOT}/locks`),
48+
setData(payload),
49+
setMethod('POST'),
50+
);
51+
52+
/**
53+
* deleteLock
54+
*
55+
* Deletes a resource lock, allowing the resource to be deleted or modified.
56+
*
57+
* @param lockId { number } The ID of the lock to delete.
58+
*/
59+
export const deleteLock = (lockId: number) =>
60+
Request<{}>(
61+
setURL(`${BETA_API_ROOT}/locks/${encodeURIComponent(lockId)}`),
62+
setMethod('DELETE'),
63+
);

packages/api-v4/src/locks/types.ts

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
import type { EntityType } from '../entities';
2+
3+
/**
4+
* Types of locks that can be applied to a resource
5+
*/
6+
export type LockType = 'cannot_delete' | 'cannot_delete_with_subresources';
7+
8+
/**
9+
* Entity information attached to a lock
10+
*/
11+
export interface LockEntity {
12+
id: number | string;
13+
label?: string;
14+
type: EntityType;
15+
url?: string;
16+
}
17+
18+
/**
19+
* Request payload for creating a lock
20+
* POST /v4beta/locks
21+
*/
22+
export interface CreateLockPayload {
23+
/** Required: ID of the entity being locked */
24+
entity_id: number | string;
25+
/** Required: Type of the entity being locked */
26+
entity_type: EntityType;
27+
/** Required: Type of lock to apply */
28+
lock_type: LockType;
29+
}
30+
31+
/**
32+
* Resource Lock object returned from API
33+
* Response from POST /v4beta/locks
34+
*/
35+
export interface ResourceLock {
36+
/** Information about the locked entity */
37+
entity: LockEntity;
38+
/** Unique identifier for the lock */
39+
id: number;
40+
/** Type of lock applied */
41+
lock_type: LockType;
42+
}
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
"@linode/queries": Upcoming Features
3+
---
4+
5+
Add new API queries for CRUD of locks for Resource Locking feature(RESPROT2) ([#13187](https://github.com/linode/manager/pull/13187))

packages/queries/src/index.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ export * from './firewalls';
1010
export * from './iam';
1111
export * from './images';
1212
export * from './linodes';
13+
export * from './locks';
1314
export * from './netloadbalancers';
1415
export * from './networking';
1516
export * from './networktransfer';
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
export * from './locks';
Lines changed: 109 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,109 @@
1+
import {
2+
createLock,
3+
deleteLock,
4+
getLock,
5+
getLocks,
6+
} from '@linode/api-v4/lib/locks';
7+
import { createQueryKeys } from '@lukemorales/query-key-factory';
8+
import { useMutation, useQuery, useQueryClient } from '@tanstack/react-query';
9+
10+
import type { APIError, Filter, Params, ResourcePage } from '@linode/api-v4';
11+
import type {
12+
CreateLockPayload,
13+
ResourceLock,
14+
} from '@linode/api-v4/lib/locks/types';
15+
16+
export const lockQueries = createQueryKeys('locks', {
17+
lock: (id: number) => ({
18+
queryFn: () => getLock(id),
19+
queryKey: [id],
20+
}),
21+
locks: {
22+
contextQueries: {
23+
paginated: (params: Params = {}, filter: Filter = {}) => ({
24+
queryFn: () => getLocks(params, filter),
25+
queryKey: [params, filter],
26+
}),
27+
},
28+
queryKey: null,
29+
},
30+
});
31+
32+
/**
33+
* useLocksQuery
34+
*
35+
* Returns a paginated list of resource locks
36+
*
37+
* @example
38+
* const { data, isLoading } = useLocksQuery();
39+
*/
40+
export const useLocksQuery = (params: Params = {}, filter: Filter = {}) => {
41+
return useQuery<ResourcePage<ResourceLock>, APIError[]>({
42+
...lockQueries.locks._ctx.paginated(params, filter),
43+
});
44+
};
45+
46+
/**
47+
* useLockQuery
48+
*
49+
* Returns a single resource lock by ID
50+
*
51+
* @example
52+
* const { data: lock } = useLockQuery(123);
53+
*/
54+
export const useLockQuery = (id: number, enabled: boolean = true) => {
55+
return useQuery<ResourceLock, APIError[]>({
56+
...lockQueries.lock(id),
57+
enabled,
58+
});
59+
};
60+
61+
/**
62+
*
63+
* Creates a new resource lock
64+
* POST /v4beta/locks
65+
*
66+
* @example
67+
* const { mutate: createLock } = useCreateLockMutation();
68+
* createLock({
69+
* entity_type: 'linode',
70+
* entity_id: 12345,
71+
* lock_type: 'cannot_delete',
72+
* });
73+
*/
74+
export const useCreateLockMutation = () => {
75+
const queryClient = useQueryClient();
76+
77+
return useMutation<ResourceLock, APIError[], CreateLockPayload>({
78+
mutationFn: (payload) => createLock(payload),
79+
onSuccess: () => {
80+
// Invalidate all lock queries
81+
queryClient.invalidateQueries({
82+
queryKey: lockQueries.locks.queryKey,
83+
});
84+
},
85+
});
86+
};
87+
88+
/**
89+
*
90+
* Deletes a resource lock
91+
* DELETE /v4beta/locks/{lock_id}
92+
*
93+
* @example
94+
* const { mutate: deleteLock } = useDeleteLockMutation();
95+
* deleteLock(123);
96+
*/
97+
export const useDeleteLockMutation = () => {
98+
const queryClient = useQueryClient();
99+
100+
return useMutation<{}, APIError[], number>({
101+
mutationFn: (lockId) => deleteLock(lockId),
102+
onSuccess: () => {
103+
// Invalidate all lock queries
104+
queryClient.invalidateQueries({
105+
queryKey: lockQueries.locks.queryKey,
106+
});
107+
},
108+
});
109+
};

0 commit comments

Comments
 (0)