bfg-common 1.3.202 → 1.3.203
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/components/common/diagramMain/DiagramMain.vue +9 -0
- package/components/common/wizards/network/add/Add.vue +37 -0
- package/components/common/wizards/network/add/lib/config/initialData.ts +1 -1
- package/components/common/wizards/network/add/lib/models/interfaces.ts +27 -1
- package/components/common/wizards/network/add/lib/models/types.ts +1 -1
- package/components/common/wizards/network/add/steps/IpFourSettings.vue +61 -11
- package/components/common/wizards/network/add/steps/PortProperties.vue +30 -7
- package/lib/models/enums.ts +7 -0
- package/lib/models/interfaces.ts +17 -0
- package/package.json +1 -1
|
@@ -203,8 +203,10 @@
|
|
|
203
203
|
:is-dark-mode="props.isDarkMode"
|
|
204
204
|
:selected-standard-switch-id="selectedStandardSwitchId"
|
|
205
205
|
:selected-switch-id="selectedSwitchId"
|
|
206
|
+
:tcp-stacks="props.tcpStacks"
|
|
206
207
|
@check-network-label="onCheckNetworkLabel"
|
|
207
208
|
@get-existing-standard-switches="onGetExistingStandardSwitches"
|
|
209
|
+
@get-tcp-stacks="onGetTcpStacks"
|
|
208
210
|
@get-free-adapters="onGetFreeAdapters"
|
|
209
211
|
@send-add-networking-data="onSendNetworkData"
|
|
210
212
|
@add-networking-data-validate="onValidateBeforeSending"
|
|
@@ -252,6 +254,7 @@ import {
|
|
|
252
254
|
UI_I_AddNetworkingSecondOrThirdSchemeDataSend,
|
|
253
255
|
UI_I_AddNetworkingZeroOrFirstSchemeDataSend,
|
|
254
256
|
UI_I_Switch,
|
|
257
|
+
UI_I_TCPStack,
|
|
255
258
|
} from '~/components/common/wizards/network/add/lib/models/interfaces'
|
|
256
259
|
import {
|
|
257
260
|
adapterViewSettingsFunc,
|
|
@@ -294,6 +297,7 @@ const props = withDefaults(
|
|
|
294
297
|
freeAdapters?: UI_I_Adapter[]
|
|
295
298
|
networksList?: UI_I_Network[]
|
|
296
299
|
isDarkMode: boolean
|
|
300
|
+
tcpStacks?: UI_I_TCPStack[]
|
|
297
301
|
}>(),
|
|
298
302
|
{
|
|
299
303
|
diagramData: null,
|
|
@@ -307,6 +311,7 @@ const props = withDefaults(
|
|
|
307
311
|
}),
|
|
308
312
|
freeAdapters: () => [],
|
|
309
313
|
networksList: () => [],
|
|
314
|
+
tcpStacks: () => [],
|
|
310
315
|
}
|
|
311
316
|
)
|
|
312
317
|
|
|
@@ -568,6 +573,9 @@ const onCheckNetworkLabel = (
|
|
|
568
573
|
const onGetExistingStandardSwitches = (cb: () => void) => {
|
|
569
574
|
emits('get-existing-standard-switches', cb)
|
|
570
575
|
}
|
|
576
|
+
const onGetTcpStacks = (cb: () => void) => {
|
|
577
|
+
emits('get-tcp-stacks', cb)
|
|
578
|
+
}
|
|
571
579
|
const onGetFreeAdapters = (cb: () => void) => {
|
|
572
580
|
emits('get-free-adapters', cb)
|
|
573
581
|
}
|
|
@@ -895,6 +903,7 @@ const emits = defineEmits<{
|
|
|
895
903
|
hideModalCB: () => void,
|
|
896
904
|
hideLoaderCB: () => void
|
|
897
905
|
): void
|
|
906
|
+
(event: 'get-tcp-stacks', cb: () => void): void
|
|
898
907
|
}>()
|
|
899
908
|
|
|
900
909
|
const onTogglePorts = (
|
|
@@ -66,6 +66,8 @@
|
|
|
66
66
|
:project="props.project"
|
|
67
67
|
:messages-fields="selectedStep.fields"
|
|
68
68
|
:alert-messages="alertMessages[3]"
|
|
69
|
+
:tcp-stacks="props.tcpStacks"
|
|
70
|
+
@change-gateway-flag="onChangeGatewayFlag"
|
|
69
71
|
@change-port-properties="onChangePortProperties"
|
|
70
72
|
@hide-alert="onHideAlert"
|
|
71
73
|
/>
|
|
@@ -75,6 +77,10 @@
|
|
|
75
77
|
:ip-four-settings="ipFourSettings"
|
|
76
78
|
:messages-fields="selectedStep.fields"
|
|
77
79
|
:alert-messages="alertMessages[4]"
|
|
80
|
+
:tcp-stacks="props.tcpStacks"
|
|
81
|
+
:tcp="portProperties.tcp"
|
|
82
|
+
:gateway-flag="gatewayFlag"
|
|
83
|
+
@change-gateway-flag="onChangeGatewayFlag"
|
|
78
84
|
@change-ip-four-settings="onChangeIpFourSettings"
|
|
79
85
|
@hide-alert="onHideAlert"
|
|
80
86
|
/>
|
|
@@ -114,6 +120,7 @@ import {
|
|
|
114
120
|
UI_I_AddNetworkingSecondOrThirdSchemeDataSend,
|
|
115
121
|
UI_I_AddNetworkingZeroOrFirstSchemeDataSend,
|
|
116
122
|
UI_I_AddNetworkingEmits,
|
|
123
|
+
UI_I_TCPStack,
|
|
117
124
|
} from '~/components/common/wizards/network/add/lib/models/interfaces'
|
|
118
125
|
import {
|
|
119
126
|
UI_I_Adapter,
|
|
@@ -162,6 +169,7 @@ const props = withDefaults(
|
|
|
162
169
|
isDarkMode?: boolean
|
|
163
170
|
selectedStandardSwitchId?: string
|
|
164
171
|
selectedSwitchId?: string
|
|
172
|
+
tcpStacks?: UI_I_TCPStack[]
|
|
165
173
|
}>(),
|
|
166
174
|
{
|
|
167
175
|
standardSwitchesInitial: () => [],
|
|
@@ -170,6 +178,7 @@ const props = withDefaults(
|
|
|
170
178
|
isDarkMode: false,
|
|
171
179
|
selectedStandardSwitchId: '',
|
|
172
180
|
selectedSwitchId: '',
|
|
181
|
+
tcpStacks: () => [],
|
|
173
182
|
}
|
|
174
183
|
)
|
|
175
184
|
|
|
@@ -255,6 +264,11 @@ const portProperties = ref<UI_I_PortProperties>(
|
|
|
255
264
|
useDeepCopy(portPropertiesInitial)
|
|
256
265
|
)
|
|
257
266
|
const onChangePortProperties = (newFields: UI_I_PortProperties): void => {
|
|
267
|
+
if (portProperties.value.tcp !== newFields.tcp) {
|
|
268
|
+
ipFourSettings.value.static.defaultGateway.value =
|
|
269
|
+
props.tcpStacks?.find((tcp: UI_I_TCPStack) => tcp.id === newFields.tcp)
|
|
270
|
+
.gateway || ''
|
|
271
|
+
}
|
|
258
272
|
portProperties.value = newFields
|
|
259
273
|
}
|
|
260
274
|
|
|
@@ -264,6 +278,11 @@ const onChangeIpFourSettings = (newFields: UI_I_IpFourSettings): void => {
|
|
|
264
278
|
ipFourSettings.value = newFields
|
|
265
279
|
}
|
|
266
280
|
|
|
281
|
+
const gatewayFlag = ref<boolean>(false)
|
|
282
|
+
const onChangeGatewayFlag = (newValue: boolean) => {
|
|
283
|
+
gatewayFlag.value = newValue
|
|
284
|
+
}
|
|
285
|
+
|
|
267
286
|
// Step's content data and changers (connectionSettings)
|
|
268
287
|
const connectionSettings = ref<UI_I_ConnectionSettings>(
|
|
269
288
|
connectionSettingsInitial
|
|
@@ -326,12 +345,20 @@ const onGetExistingStandardSwitches = (): void => {
|
|
|
326
345
|
emits('get-existing-standard-switches', () => wizard.setLoader(false))
|
|
327
346
|
}
|
|
328
347
|
|
|
348
|
+
const onGetTcpStacks = (): void => {
|
|
349
|
+
wizard.setLoader(true)
|
|
350
|
+
emits('get-tcp-stacks', () => wizard.setLoader(false))
|
|
351
|
+
}
|
|
352
|
+
|
|
329
353
|
watch(
|
|
330
354
|
() => wizard.selectedStepId,
|
|
331
355
|
(newSelectedStep: number) => {
|
|
332
356
|
if (newSelectedStep === 1) {
|
|
333
357
|
onGetExistingStandardSwitches()
|
|
334
358
|
}
|
|
359
|
+
if (newSelectedStep === 3) {
|
|
360
|
+
onGetTcpStacks()
|
|
361
|
+
}
|
|
335
362
|
if (newSelectedStep === 6 && flagSwitch !== targetDevice.value.switch) {
|
|
336
363
|
const nics = props.standardSwitchesInitial.find(
|
|
337
364
|
(sw) => sw.id === targetDevice.value.switch
|
|
@@ -701,6 +728,16 @@ const onSubmit = async (): Promise<void> => {
|
|
|
701
728
|
onMounted(() => {
|
|
702
729
|
hostname.value = location.hostname
|
|
703
730
|
})
|
|
731
|
+
|
|
732
|
+
watch(
|
|
733
|
+
props.tcpStacks,
|
|
734
|
+
(newValue: UI_I_TCPStack[]) => {
|
|
735
|
+
portProperties.value.tcp = newValue?.[0]?.id || ''
|
|
736
|
+
ipFourSettings.value.static.defaultGateway.value =
|
|
737
|
+
newValue?.[0]?.gateway || ''
|
|
738
|
+
},
|
|
739
|
+
{ deep: true }
|
|
740
|
+
)
|
|
704
741
|
</script>
|
|
705
742
|
|
|
706
743
|
<style scoped lang="scss">
|
|
@@ -1,4 +1,8 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import {
|
|
2
|
+
UI_I_ArbitraryObject,
|
|
3
|
+
UI_I_ListIndex,
|
|
4
|
+
UI_I_State,
|
|
5
|
+
} from '~/lib/models/interfaces'
|
|
2
6
|
import { UI_T_TCP } from '~/components/common/wizards/network/add/lib/models/types'
|
|
3
7
|
|
|
4
8
|
export interface UI_I_Services {
|
|
@@ -198,4 +202,26 @@ export interface UI_I_AddNetworkingEmits {
|
|
|
198
202
|
networkLabel: string,
|
|
199
203
|
cb: (error_message: string) => void
|
|
200
204
|
): void
|
|
205
|
+
(event: 'get-tcp-stacks', cb: () => void): void
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
export interface UI_I_TCPStack {
|
|
209
|
+
id: string
|
|
210
|
+
state: UI_I_State
|
|
211
|
+
index: UI_I_ListIndex
|
|
212
|
+
dns: {
|
|
213
|
+
auto_from?: string
|
|
214
|
+
hostname: string
|
|
215
|
+
domain: string
|
|
216
|
+
preferred_dns: string
|
|
217
|
+
alternative_dns: string
|
|
218
|
+
search_domains: string[]
|
|
219
|
+
}
|
|
220
|
+
gateway: string // TODO ??? type
|
|
221
|
+
advanced: {
|
|
222
|
+
congestion_control: string
|
|
223
|
+
max_connections: number
|
|
224
|
+
}
|
|
225
|
+
routing_table: number
|
|
226
|
+
routes: string[]
|
|
201
227
|
}
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
export type UI_T_TCP = 'default' | '
|
|
1
|
+
export type UI_T_TCP = 'default' | 'provisioning' | ''
|
|
2
2
|
export type UI_T_Project = 'procurator' | 'sphere'
|
|
@@ -163,8 +163,14 @@
|
|
|
163
163
|
</template>
|
|
164
164
|
|
|
165
165
|
<script setup lang="ts">
|
|
166
|
-
import {
|
|
167
|
-
|
|
166
|
+
import {
|
|
167
|
+
UI_I_ArbitraryObject,
|
|
168
|
+
UI_I_Localization,
|
|
169
|
+
} from '~/lib/models/interfaces'
|
|
170
|
+
import {
|
|
171
|
+
UI_I_IpFourSettings,
|
|
172
|
+
UI_I_TCPStack,
|
|
173
|
+
} from '~/components/common/wizards/network/add/lib/models/interfaces'
|
|
168
174
|
import { UI_I_ErrorFields } from '~/components/atoms/wizard/lib/models/interfaces'
|
|
169
175
|
import type Wizard from '~/components/atoms/wizard/lib/utils/utils'
|
|
170
176
|
import {
|
|
@@ -174,17 +180,26 @@ import {
|
|
|
174
180
|
validateMaskIpFourSettingsLocal,
|
|
175
181
|
} from '~/components/common/wizards/network/add/validations/validations'
|
|
176
182
|
|
|
177
|
-
const props =
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
+
const props = withDefaults(
|
|
184
|
+
defineProps<{
|
|
185
|
+
ipFourSettings: UI_I_IpFourSettings
|
|
186
|
+
alertMessages: string[]
|
|
187
|
+
messagesFields: UI_I_ArbitraryObject<UI_I_ErrorFields>
|
|
188
|
+
wizard: Wizard
|
|
189
|
+
tcpStacks?: UI_I_TCPStack[]
|
|
190
|
+
tcp: string
|
|
191
|
+
gatewayFlag: boolean
|
|
192
|
+
}>(),
|
|
193
|
+
{
|
|
194
|
+
tcpStacks: () => [],
|
|
195
|
+
}
|
|
196
|
+
)
|
|
183
197
|
|
|
184
198
|
const localization = computed<UI_I_Localization>(() => useLocal())
|
|
185
199
|
|
|
186
200
|
const emits = defineEmits<{
|
|
187
201
|
(event: 'change-ip-four-settings', ipFourSettings: UI_I_IpFourSettings): void
|
|
202
|
+
(event: 'change-gateway-flag', value: boolean): void
|
|
188
203
|
(event: 'hide-alert', stepId: 4): void
|
|
189
204
|
}>()
|
|
190
205
|
|
|
@@ -195,7 +210,6 @@ let oldFields = useDeepCopy(fields.value)
|
|
|
195
210
|
watch(
|
|
196
211
|
fields,
|
|
197
212
|
(newFields: UI_I_IpFourSettings) => {
|
|
198
|
-
|
|
199
213
|
if (newFields.ipSettings === '1') {
|
|
200
214
|
oldFields.static.ipFourAddress !== newFields.static.ipFourAddress &&
|
|
201
215
|
validateAddressIpFourSettingsLocal(
|
|
@@ -211,9 +225,23 @@ watch(
|
|
|
211
225
|
props.wizard
|
|
212
226
|
)
|
|
213
227
|
|
|
214
|
-
|
|
228
|
+
const isGatewayChanged =
|
|
229
|
+
newFields.static.defaultGateway &&
|
|
215
230
|
oldFields.static.defaultGateway.value !==
|
|
216
|
-
newFields.static.defaultGateway.value
|
|
231
|
+
newFields.static.defaultGateway.value
|
|
232
|
+
|
|
233
|
+
emits('change-gateway-flag', true)
|
|
234
|
+
|
|
235
|
+
if (
|
|
236
|
+
oldFields.static.defaultGateway.override &&
|
|
237
|
+
!newFields.static.defaultGateway.override
|
|
238
|
+
) {
|
|
239
|
+
fields.value.static.defaultGateway.value = props.tcpStacks.find(
|
|
240
|
+
(tcp: UI_I_TCPStack) => tcp.id === props.tcp
|
|
241
|
+
).gateway
|
|
242
|
+
}
|
|
243
|
+
|
|
244
|
+
isGatewayChanged &&
|
|
217
245
|
validateGatewayIpFourSettingsLocal(
|
|
218
246
|
localization.value,
|
|
219
247
|
newFields,
|
|
@@ -230,6 +258,28 @@ watch(
|
|
|
230
258
|
{ deep: true }
|
|
231
259
|
)
|
|
232
260
|
|
|
261
|
+
watch(
|
|
262
|
+
() => props.tcpStacks,
|
|
263
|
+
(newValue: UI_I_TCPStack[]) => {
|
|
264
|
+
if (fields.value.static.defaultGateway.value === '') {
|
|
265
|
+
fields.value.static.defaultGateway.value = newValue?.[0]?.gateway || ''
|
|
266
|
+
}
|
|
267
|
+
},
|
|
268
|
+
{ deep: true, immediate: true }
|
|
269
|
+
)
|
|
270
|
+
|
|
271
|
+
watch(
|
|
272
|
+
() => props.tcp,
|
|
273
|
+
(newValue: string) => {
|
|
274
|
+
if (newValue && !props.gatewayFlag) {
|
|
275
|
+
fields.value.static.defaultGateway.value = props.tcpStacks.find(
|
|
276
|
+
(tcp: UI_I_TCPStack) => tcp.id === newValue
|
|
277
|
+
).gateway
|
|
278
|
+
}
|
|
279
|
+
},
|
|
280
|
+
{ immediate: true }
|
|
281
|
+
)
|
|
282
|
+
|
|
233
283
|
const onHideAlert = (): void => {
|
|
234
284
|
emits('hide-alert', 4)
|
|
235
285
|
}
|
|
@@ -133,8 +133,10 @@
|
|
|
133
133
|
<div class="property-value-group">
|
|
134
134
|
<div class="select">
|
|
135
135
|
<select id="tsp" v-model="fields.tcp">
|
|
136
|
-
<
|
|
137
|
-
|
|
136
|
+
<template v-for="tcp in props.tcpStacks" :key="tcp.id">
|
|
137
|
+
<option :value="tcp.id">{{ localization[tcp.id] }}</option>
|
|
138
|
+
</template>
|
|
139
|
+
<!-- <option value="1">{{ localization.provisioning }}</option>-->
|
|
138
140
|
<!-- <option value="2">{{ localization.vMotion }}</option>-->
|
|
139
141
|
</select>
|
|
140
142
|
</div>
|
|
@@ -200,14 +202,20 @@
|
|
|
200
202
|
</template>
|
|
201
203
|
|
|
202
204
|
<script setup lang="ts">
|
|
203
|
-
import {
|
|
205
|
+
import {
|
|
206
|
+
UI_I_ArbitraryObject,
|
|
207
|
+
UI_I_Localization,
|
|
208
|
+
} from '~/lib/models/interfaces'
|
|
204
209
|
import { UI_T_Project } from '~/lib/models/types'
|
|
205
210
|
import {
|
|
206
211
|
servicesInitial,
|
|
207
212
|
vlanIdSelectData,
|
|
208
213
|
portPropertiesEnabledServicesFunc,
|
|
209
214
|
} from '~/components/common/wizards/network/add/lib/config'
|
|
210
|
-
import {
|
|
215
|
+
import {
|
|
216
|
+
UI_I_PortProperties,
|
|
217
|
+
UI_I_TCPStack,
|
|
218
|
+
} from '~/components/common/wizards/network/add/lib/models/interfaces'
|
|
211
219
|
import { UI_T_TCP } from '~/components/common/wizards/network/add/lib/models/types'
|
|
212
220
|
import { UI_I_ErrorFields } from '~/components/atoms/wizard/lib/models/interfaces'
|
|
213
221
|
import type Wizard from '~/components/atoms/wizard/lib/utils/utils'
|
|
@@ -225,9 +233,11 @@ const props = withDefaults(
|
|
|
225
233
|
alertMessages: string[]
|
|
226
234
|
messagesFields: UI_I_ArbitraryObject<UI_I_ErrorFields>
|
|
227
235
|
wizard: Wizard
|
|
236
|
+
tcpStacks?: UI_I_TCPStack[]
|
|
228
237
|
}>(),
|
|
229
238
|
{
|
|
230
239
|
mtuFromSwitch: 1500,
|
|
240
|
+
tcpStacks: () => [],
|
|
231
241
|
}
|
|
232
242
|
)
|
|
233
243
|
|
|
@@ -241,6 +251,7 @@ const portPropertiesEnabledServices = computed(() =>
|
|
|
241
251
|
|
|
242
252
|
const emits = defineEmits<{
|
|
243
253
|
(event: 'change-port-properties', portProperties: UI_I_PortProperties): void
|
|
254
|
+
(event: 'change-gateway-flag', value: boolean): void
|
|
244
255
|
(event: 'hide-alert', stepId: 3): void
|
|
245
256
|
}>()
|
|
246
257
|
|
|
@@ -273,7 +284,7 @@ const setEnabledServiceProvisioning = (
|
|
|
273
284
|
currentFields: UI_I_PortProperties,
|
|
274
285
|
newFields?: UI_I_PortProperties
|
|
275
286
|
): void => {
|
|
276
|
-
tcp === '
|
|
287
|
+
tcp === 'provisioning' &&
|
|
277
288
|
(fields.value = {
|
|
278
289
|
...(newFields || currentFields),
|
|
279
290
|
services: {
|
|
@@ -288,7 +299,7 @@ const setEnabledServiceVMotion = (
|
|
|
288
299
|
currentFields: UI_I_PortProperties,
|
|
289
300
|
newFields?: UI_I_PortProperties
|
|
290
301
|
): void => {
|
|
291
|
-
tcp === '
|
|
302
|
+
tcp === '' &&
|
|
292
303
|
(fields.value = {
|
|
293
304
|
...(newFields || currentFields),
|
|
294
305
|
services: {
|
|
@@ -304,7 +315,9 @@ let oldFields = useDeepCopy(fields.value)
|
|
|
304
315
|
watch(
|
|
305
316
|
fields,
|
|
306
317
|
(newFields: UI_I_PortProperties) => {
|
|
307
|
-
if (newFields.tcp && newFields.tcp !==
|
|
318
|
+
if (newFields.tcp && newFields.tcp !== oldFields.tcp) {
|
|
319
|
+
emits('change-gateway-flag', false)
|
|
320
|
+
setEnabledServiceDefault(newFields.tcp, fields.value)
|
|
308
321
|
setEnabledServiceProvisioning(newFields.tcp, fields.value, newFields)
|
|
309
322
|
setEnabledServiceVMotion(newFields.tcp, fields.value, newFields)
|
|
310
323
|
}
|
|
@@ -363,6 +376,16 @@ watch(
|
|
|
363
376
|
}
|
|
364
377
|
)
|
|
365
378
|
|
|
379
|
+
watch(
|
|
380
|
+
() => props.tcpStacks,
|
|
381
|
+
(newValue: UI_I_TCPStack[]) => {
|
|
382
|
+
if (fields.value.tcp === '') {
|
|
383
|
+
fields.value.tcp = newValue?.[0]?.id || ''
|
|
384
|
+
}
|
|
385
|
+
},
|
|
386
|
+
{ deep: true, immediate: true }
|
|
387
|
+
)
|
|
388
|
+
|
|
366
389
|
const onHideAlert = (): void => {
|
|
367
390
|
emits('hide-alert', 3)
|
|
368
391
|
}
|
package/lib/models/enums.ts
CHANGED
package/lib/models/interfaces.ts
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import type { UI_T_Status } from '~/components/atoms/alert/lib/models/types'
|
|
2
|
+
import { UI_E_State } from '~/lib/models/enums'
|
|
2
3
|
|
|
3
4
|
export interface UI_I_ItemView {
|
|
4
5
|
value: number | string
|
|
@@ -24,3 +25,19 @@ export interface UI_I_NotifyBodyMessage {
|
|
|
24
25
|
title: string
|
|
25
26
|
desc: string
|
|
26
27
|
}
|
|
28
|
+
|
|
29
|
+
export interface UI_I_ListIndex {
|
|
30
|
+
idx: number
|
|
31
|
+
count: number
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
export interface UI_I_State {
|
|
35
|
+
state: UI_E_State
|
|
36
|
+
errors: string[]
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
export interface UI_I_ItemsWithTotalCounts<T> {
|
|
40
|
+
total_items: number
|
|
41
|
+
total_pages: number
|
|
42
|
+
items: T[]
|
|
43
|
+
}
|