mirror of
https://github.com/portainer/portainer.git
synced 2025-08-02 20:35:25 +02:00
feat(app): limit the docker API version supported by the frontend (#11855)
Some checks are pending
ci / build_images (map[arch:amd64 platform:linux version:]) (push) Waiting to run
ci / build_images (map[arch:amd64 platform:windows version:1809]) (push) Waiting to run
ci / build_images (map[arch:amd64 platform:windows version:ltsc2022]) (push) Waiting to run
ci / build_images (map[arch:arm platform:linux version:]) (push) Waiting to run
ci / build_images (map[arch:arm64 platform:linux version:]) (push) Waiting to run
ci / build_images (map[arch:ppc64le platform:linux version:]) (push) Waiting to run
ci / build_images (map[arch:s390x platform:linux version:]) (push) Waiting to run
ci / build_manifests (push) Blocked by required conditions
/ triage (push) Waiting to run
Lint / Run linters (push) Waiting to run
Test / test-client (push) Waiting to run
Test / test-server (map[arch:amd64 platform:linux]) (push) Waiting to run
Test / test-server (map[arch:amd64 platform:windows version:1809]) (push) Waiting to run
Test / test-server (map[arch:amd64 platform:windows version:ltsc2022]) (push) Waiting to run
Test / test-server (map[arch:arm64 platform:linux]) (push) Waiting to run
Some checks are pending
ci / build_images (map[arch:amd64 platform:linux version:]) (push) Waiting to run
ci / build_images (map[arch:amd64 platform:windows version:1809]) (push) Waiting to run
ci / build_images (map[arch:amd64 platform:windows version:ltsc2022]) (push) Waiting to run
ci / build_images (map[arch:arm platform:linux version:]) (push) Waiting to run
ci / build_images (map[arch:arm64 platform:linux version:]) (push) Waiting to run
ci / build_images (map[arch:ppc64le platform:linux version:]) (push) Waiting to run
ci / build_images (map[arch:s390x platform:linux version:]) (push) Waiting to run
ci / build_manifests (push) Blocked by required conditions
/ triage (push) Waiting to run
Lint / Run linters (push) Waiting to run
Test / test-client (push) Waiting to run
Test / test-server (map[arch:amd64 platform:linux]) (push) Waiting to run
Test / test-server (map[arch:amd64 platform:windows version:1809]) (push) Waiting to run
Test / test-server (map[arch:amd64 platform:windows version:ltsc2022]) (push) Waiting to run
Test / test-server (map[arch:arm64 platform:linux]) (push) Waiting to run
This commit is contained in:
parent
4ba16f1b04
commit
6a8e6734f3
212 changed files with 4439 additions and 3281 deletions
82
app/types/deepPick.ts
Normal file
82
app/types/deepPick.ts
Normal file
|
@ -0,0 +1,82 @@
|
|||
import { DeepRequired } from './deepRequired';
|
||||
import { Shift } from './shift';
|
||||
import { ToTuple } from './toTuple';
|
||||
import { PathToStringArray, Prettify } from './utils';
|
||||
|
||||
/**
|
||||
* Pick and union the types of the paths (or path-arrays).
|
||||
*
|
||||
* To be able to properly pick, it marks all segments of the paths required, even the last.
|
||||
*
|
||||
* The resulting type will never be optional
|
||||
*
|
||||
* @example
|
||||
* type SubExample = {
|
||||
* something: number;
|
||||
* };
|
||||
*
|
||||
* type Example = {
|
||||
* always: string;
|
||||
* a?: {
|
||||
* two?: boolean;
|
||||
* b?: {
|
||||
* c?: number;
|
||||
* };
|
||||
* };
|
||||
*
|
||||
* one?: {
|
||||
* two?: {
|
||||
* three?: SubExample;
|
||||
* four?: number;
|
||||
* };
|
||||
* };
|
||||
* };
|
||||
*
|
||||
* type DeepPickExampleArray = DeepPick<Example, ['a', 'b', 'c'] | ['one', 'two', 'three'] | ['a', 'two']>;
|
||||
* type DeepPickExampleString = DeepPick<Example, 'a.b.c' | 'one.two.three' | 'a.two'>;
|
||||
* type DeepPickExampleMix = DeepPick<Example, 'a.b.c' | ['one', 'two', 'three'] | 'a.two'>;
|
||||
*
|
||||
* // they all equal to
|
||||
* type ResultingType =
|
||||
* | number // picked from 'a.b.c'
|
||||
* | boolean // picked from 'a.two'
|
||||
* | { something: number }; // picked from 'one.two.three'
|
||||
*
|
||||
*/
|
||||
export type DeepPick<T extends object, P extends string | string[]> = Prettify<
|
||||
P extends string
|
||||
? DeepPickFromString<DeepRequired<T, P>, P>
|
||||
: P extends string[]
|
||||
? DeepPickFromArray<DeepRequired<T, P>, P>
|
||||
: never
|
||||
>;
|
||||
|
||||
/**
|
||||
* DeepPick and transform union of paths to union of path-arrays
|
||||
* from `'a.b.c' | 'c.d.e'` to `['a', 'b', 'c'] | ['c' | 'd' | 'e']`
|
||||
*/
|
||||
type DeepPickFromString<T extends object, P extends string> = DeepPickFromArray<
|
||||
T,
|
||||
PathToStringArray<P>
|
||||
>;
|
||||
|
||||
/**
|
||||
* Transform union of path-arrays to tuple of path-arrays
|
||||
* from `['a', 'b', 'c'] | ['c' | 'd' | 'e']` to `[['a', 'b', 'c'], ['c' | 'd' | 'e']]`
|
||||
*/
|
||||
type DeepPickFromArray<
|
||||
T extends object,
|
||||
P extends string[],
|
||||
> = ToTuple<P> extends string[][] ? DeepPickRec<T, ToTuple<P>> : never;
|
||||
|
||||
// Recursively pick each path-array of tuple and union the resulting types
|
||||
type DeepPickRec<T extends object, P extends string[][]> = P[0] extends string[]
|
||||
? PickOne<T, P[0]> | DeepPickRec<T, Shift<P>>
|
||||
: never;
|
||||
|
||||
// Recursively pick each element of path-array
|
||||
type PickOne<T extends object, P extends string[]> = P[0] extends keyof T
|
||||
? T[P[0]] extends object
|
||||
? PickOne<T[P[0]], Shift<P>>
|
||||
: T[P[0]]
|
||||
: T;
|
68
app/types/deepRequired.ts
Normal file
68
app/types/deepRequired.ts
Normal file
|
@ -0,0 +1,68 @@
|
|||
import { ShiftUnion } from './shift';
|
||||
import { PathToStringArray, Prettify } from './utils';
|
||||
|
||||
/**
|
||||
* Recursively make all paths (or path-arrays) required
|
||||
*
|
||||
* @example
|
||||
* type SubExample = {
|
||||
* something: number;
|
||||
* };
|
||||
*
|
||||
* type Example = {
|
||||
* always: string;
|
||||
* a?: {
|
||||
* two?: boolean;
|
||||
* b?: {
|
||||
* c?: number;
|
||||
* };
|
||||
* };
|
||||
*
|
||||
* one?: {
|
||||
* two?: {
|
||||
* three?: SubExample;
|
||||
* four?: number;
|
||||
* };
|
||||
* };
|
||||
* };
|
||||
*
|
||||
* type DeepRequiredExampleArray = DeepRequired<Example, 'a.b.c' | 'one.two.three'>;
|
||||
* type DeepRequiredExampleString = DeepRequired<Example, ['a', 'b', 'c'] | ['one', 'two', 'three']>;
|
||||
* type DeepRequiredExampleMix = DeepRequired<Example, 'a.b.c' | ['one', 'two', 'three']>;
|
||||
*
|
||||
* // they all equal to
|
||||
* type ResultingType = {
|
||||
* always: string;
|
||||
* a: { // became required
|
||||
* two?: boolean | undefined;
|
||||
* b: { // became required
|
||||
* c: number; // deep required
|
||||
* };
|
||||
* };
|
||||
* one: { // became required
|
||||
* two: { // became required
|
||||
* four?: number | undefined;
|
||||
* three: { // deep required
|
||||
* something: number;
|
||||
* };
|
||||
* };
|
||||
* };
|
||||
* };
|
||||
*
|
||||
*/
|
||||
export type DeepRequired<T, P extends string[] | string> = Prettify<
|
||||
DeepRequiredRec<T, P extends string ? PathToStringArray<P> : P>
|
||||
>;
|
||||
|
||||
/**
|
||||
* Recursively require all elements of path-array
|
||||
* The Omit part is there to make the key a hard require
|
||||
*/
|
||||
type DeepRequiredRec<T, P extends string[]> = T extends object
|
||||
? Omit<T, Extract<keyof T, P[0]>> &
|
||||
Required<{
|
||||
[K in Extract<keyof T, P[0]>]: NonNullable<
|
||||
DeepRequiredRec<T[K], ShiftUnion<K, P>>
|
||||
>;
|
||||
}>
|
||||
: T;
|
27
app/types/shift.ts
Normal file
27
app/types/shift.ts
Normal file
|
@ -0,0 +1,27 @@
|
|||
/* eslint-disable @typescript-eslint/no-explicit-any */
|
||||
// required `any` for Distributive Conditional
|
||||
// https://www.typescriptlang.org/docs/handbook/2/conditional-types.html#distributive-conditional-types
|
||||
|
||||
/**
|
||||
* Remove the first element (allows to move forward path-arrays)
|
||||
*/
|
||||
export type Shift<T extends any[]> = ((...t: T) => any) extends (
|
||||
first: any,
|
||||
...rest: infer Rest
|
||||
) => any
|
||||
? Rest
|
||||
: never;
|
||||
|
||||
/**
|
||||
* Using Distributive Conditional, allows to move forward on union of path-arrays
|
||||
*
|
||||
* @example
|
||||
* type Result = ShiftUnion<['a', 'b'] | ['c', 'd']> // ['b'] | ['d']
|
||||
*/
|
||||
export type ShiftUnion<P extends PropertyKey, T extends any[]> = T extends any[]
|
||||
? T[0] extends P
|
||||
? Shift<T>
|
||||
: never
|
||||
: never;
|
||||
|
||||
/* eslint-enable @typescript-eslint/no-explicit-any */
|
89
app/types/toTuple.ts
Normal file
89
app/types/toTuple.ts
Normal file
|
@ -0,0 +1,89 @@
|
|||
/* eslint-disable @typescript-eslint/no-explicit-any */
|
||||
// required `any` for Distributive Conditional
|
||||
// https://www.typescriptlang.org/docs/handbook/2/conditional-types.html#distributive-conditional-types
|
||||
|
||||
/**
|
||||
* Transform a union to a tuple
|
||||
* from 'a' | 'b' | ['c', 'd'] to `['a', 'b', ['c', 'd']]`
|
||||
*/
|
||||
export type ToTuple<Union> = ToTupleRec<Union, []>;
|
||||
|
||||
// Recursively build a tuple from a union
|
||||
type ToTupleRec<Union, Result extends any[]> = SpliceOne<Union> extends never
|
||||
? [ExtractOne<Union>, ...Result]
|
||||
: ToTupleRec<SpliceOne<Union>, [ExtractOne<Union>, ...Result]>;
|
||||
|
||||
// Remove the first element of union
|
||||
type SpliceOne<Union> = Exclude<Union, ExtractOne<Union>>;
|
||||
|
||||
// Extract the first element of union
|
||||
type ExtractOne<Union> = ExtractParam<UnionToIntersection<UnionToParam<Union>>>;
|
||||
|
||||
/**
|
||||
* Extract param of function
|
||||
*
|
||||
* Here, used with an intersection of functions generated by UnionToIntersection to pick the first type of intersection
|
||||
*
|
||||
* @example
|
||||
* type EP = ExtractParam<((k: 'a') => void) & ((k: 'b') => void)> // 'a'
|
||||
*/
|
||||
type ExtractParam<F> = F extends { (a: infer A): void } ? A : never;
|
||||
|
||||
/**
|
||||
* When called with a union of functions, allows to generate an intersection of the functions params types
|
||||
*
|
||||
* ---
|
||||
*
|
||||
* In our usage
|
||||
* ```
|
||||
* type Inter = UnionToIntersection<UnionToParam<'a' | 'b'>>;
|
||||
* // equals
|
||||
* type Inter = UnionToIntersection<((k: 'a') => void) | ((k: 'b') => void)>;
|
||||
* // which expands to
|
||||
* type Inter =
|
||||
* | ((k: (k: 'a') => void) => void)
|
||||
* | ((k: (k: 'b') => void) => void) extends (k: infer I) => void
|
||||
* ? I
|
||||
* : never;
|
||||
* // using the contra-variant positions, an intersection is inferred. The result is then
|
||||
* type Inter = ((k: 'a') => void) & ((k: 'b') => void);
|
||||
* // (infer I) of 1st Union elem & (infer I) of 2nd Union element
|
||||
* ```
|
||||
*
|
||||
* ---
|
||||
*
|
||||
* For more details see https://www.typescriptlang.org/docs/handbook/release-notes/typescript-2-8.html#type-inference-in-conditional-types
|
||||
*
|
||||
* ```
|
||||
* // The following example demonstrates how multiple candidates for the same type variable in co-variant positions causes a union type to be inferred:
|
||||
* type Foo<T> = T extends { a: infer U; b: infer U } ? U : never;
|
||||
* type T10 = Foo<{ a: string; b: string }>; // string
|
||||
* type T11 = Foo<{ a: string; b: number }>; // string | number
|
||||
*
|
||||
* // Likewise, multiple candidates for the same type variable in contra-variant positions causes an intersection type to be inferred:
|
||||
* type Bar<T> = T extends { a: (x: infer U) => void; b: (x: infer U) => void } ? U : never;
|
||||
* type T20 = Bar<{ a: (x: string) => void; b: (x: string) => void }>; // string
|
||||
* type T21 = Bar<{ a: (x: string) => void; b: (x: number) => void }>; // string & number
|
||||
* ```
|
||||
*
|
||||
*/
|
||||
type UnionToIntersection<U> = UnionToParam<U> extends (k: infer I) => void
|
||||
? I
|
||||
: never;
|
||||
|
||||
/**
|
||||
* Transform T to `(k: T) => void` (excluding never)
|
||||
*
|
||||
* When called with a union of functions, generates a union of functions taking a function as param
|
||||
*
|
||||
* @example
|
||||
* type U = UnionToParam<'a' | 'b'>;
|
||||
* // = ((k: "a") => void) | ((k: "b") => void)
|
||||
*
|
||||
* @example
|
||||
* type U2 = UnionToParam<UnionToParam<'a' | 'b'>>;
|
||||
* // = ((k: (k: "a") => void) => void) | ((k: (k: "b") => void) => void)
|
||||
*/
|
||||
type UnionToParam<U> = U extends any ? (k: U) => void : never;
|
||||
|
||||
/* eslint-enable @typescript-eslint/no-explicit-any */
|
21
app/types/utils.ts
Normal file
21
app/types/utils.ts
Normal file
|
@ -0,0 +1,21 @@
|
|||
/**
|
||||
* Transform `'a.b.c'` or `['a', 'b', 'c']` to `['a', 'b', 'c']`
|
||||
*/
|
||||
export type PathToStringArray<T extends string | string[]> = T extends string[]
|
||||
? T
|
||||
: T extends `${infer Head}.${infer Tail}`
|
||||
? [...PathToStringArray<Head>, ...PathToStringArray<Tail>]
|
||||
: [T];
|
||||
|
||||
/* eslint-disable @typescript-eslint/ban-types */
|
||||
/**
|
||||
* VSCode helper to recursively pretty print the constructed types instead of
|
||||
* displaying the sub types.
|
||||
*
|
||||
* Particularly useful to see the resulting type when using `DeepRequired` and `DeepPick`.
|
||||
* Both already use them at root.
|
||||
*/
|
||||
export type Prettify<T> = {
|
||||
[K in keyof T]: Prettify<T[K]>;
|
||||
} & {};
|
||||
/* eslint-enable @typescript-eslint/ban-types */
|
Loading…
Add table
Add a link
Reference in a new issue