Fixed Edit Port Dialog on Network Map
This commit is contained in:
@@ -655,8 +655,8 @@ class _PortsList extends ConsumerWidget {
|
|||||||
PortListTile(
|
PortListTile(
|
||||||
port: p,
|
port: p,
|
||||||
canEdit: true,
|
canEdit: true,
|
||||||
onTap: () => showPortEditDialog(
|
onTap: (ctx) => showPortEditDialog(
|
||||||
context: context,
|
context: ctx,
|
||||||
ref: ref,
|
ref: ref,
|
||||||
deviceId: deviceId,
|
deviceId: deviceId,
|
||||||
existing: p,
|
existing: p,
|
||||||
|
|||||||
@@ -132,8 +132,8 @@ class NetworkMapDeviceScreen extends ConsumerWidget {
|
|||||||
linkedPortLabel: otherPortLabel(port.id),
|
linkedPortLabel: otherPortLabel(port.id),
|
||||||
canEdit: canEdit,
|
canEdit: canEdit,
|
||||||
onTap: canEdit
|
onTap: canEdit
|
||||||
? () => showPortEditDialog(
|
? (ctx) => showPortEditDialog(
|
||||||
context: context,
|
context: ctx,
|
||||||
ref: ref,
|
ref: ref,
|
||||||
deviceId: device.id,
|
deviceId: device.id,
|
||||||
existing: port,
|
existing: port,
|
||||||
|
|||||||
@@ -131,18 +131,19 @@ class _PortEditDialogState extends ConsumerState<_PortEditDialog> {
|
|||||||
return AlertDialog(
|
return AlertDialog(
|
||||||
title: Text(widget.existing == null ? 'Add port' : 'Edit port'),
|
title: Text(widget.existing == null ? 'Add port' : 'Edit port'),
|
||||||
content: ConstrainedBox(
|
content: ConstrainedBox(
|
||||||
constraints: const BoxConstraints(maxWidth: 420),
|
constraints: const BoxConstraints(minWidth: 320, maxWidth: 480),
|
||||||
child: SingleChildScrollView(
|
child: SingleChildScrollView(
|
||||||
child: Column(
|
child: Column(
|
||||||
mainAxisSize: MainAxisSize.min,
|
mainAxisSize: MainAxisSize.min,
|
||||||
crossAxisAlignment: CrossAxisAlignment.stretch,
|
crossAxisAlignment: CrossAxisAlignment.stretch,
|
||||||
children: [
|
children: [
|
||||||
|
// ── Identity ─────────────────────────────────────────
|
||||||
TextField(
|
TextField(
|
||||||
controller: _numberCtrl,
|
controller: _numberCtrl,
|
||||||
autofocus: widget.existing == null,
|
autofocus: widget.existing == null,
|
||||||
decoration: const InputDecoration(
|
decoration: const InputDecoration(
|
||||||
labelText: 'Port number *',
|
labelText: 'Port number *',
|
||||||
helperText: 'Exactly as labeled on the device (e.g. Gi0/1, eth0, 24)',
|
helperText: 'e.g. Gi0/1, eth0, port24',
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
const SizedBox(height: 12),
|
const SizedBox(height: 12),
|
||||||
@@ -161,6 +162,7 @@ class _PortEditDialogState extends ConsumerState<_PortEditDialog> {
|
|||||||
),
|
),
|
||||||
const SizedBox(height: 12),
|
const SizedBox(height: 12),
|
||||||
Row(
|
Row(
|
||||||
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
children: [
|
children: [
|
||||||
Expanded(
|
Expanded(
|
||||||
child: TextField(
|
child: TextField(
|
||||||
@@ -182,39 +184,43 @@ class _PortEditDialogState extends ConsumerState<_PortEditDialog> {
|
|||||||
inputFormatters: [FilteringTextInputFormatter.digitsOnly],
|
inputFormatters: [FilteringTextInputFormatter.digitsOnly],
|
||||||
decoration: InputDecoration(
|
decoration: InputDecoration(
|
||||||
labelText: 'Access VLAN',
|
labelText: 'Access VLAN',
|
||||||
helperText: _isTrunk
|
helperText: _isTrunk ? 'Disabled for trunk' : '1–4094',
|
||||||
? 'Disabled — trunk port'
|
|
||||||
: 'Single VLAN ID (1–4094)',
|
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
const SizedBox(height: 12),
|
// ── Switching config ──────────────────────────────────
|
||||||
|
const Divider(height: 28),
|
||||||
SwitchListTile.adaptive(
|
SwitchListTile.adaptive(
|
||||||
value: _isTrunk,
|
value: _isTrunk,
|
||||||
onChanged: (v) => setState(() => _isTrunk = v),
|
onChanged: (v) => setState(() => _isTrunk = v),
|
||||||
contentPadding: EdgeInsets.zero,
|
contentPadding: EdgeInsets.zero,
|
||||||
title: const Text('Trunk port'),
|
title: const Text('Trunk port'),
|
||||||
subtitle: Text(
|
subtitle: Text('Carries multiple VLANs', style: tt.bodySmall),
|
||||||
'Carries multiple VLANs',
|
|
||||||
style: tt.bodySmall,
|
|
||||||
),
|
|
||||||
),
|
),
|
||||||
if (_isTrunk) ...[
|
AnimatedSize(
|
||||||
const SizedBox(height: 4),
|
duration: const Duration(milliseconds: 200),
|
||||||
TextField(
|
curve: Curves.easeInOut,
|
||||||
controller: _trunkVlansCtrl,
|
child: _isTrunk
|
||||||
decoration: const InputDecoration(
|
? Padding(
|
||||||
labelText: 'Allowed VLANs (comma-separated)',
|
padding: const EdgeInsets.only(top: 8),
|
||||||
helperText: 'e.g. 10, 20, 100-105',
|
child: TextField(
|
||||||
),
|
controller: _trunkVlansCtrl,
|
||||||
),
|
decoration: const InputDecoration(
|
||||||
],
|
labelText: 'Allowed VLANs',
|
||||||
|
helperText: 'Comma-separated, e.g. 10, 20, 100',
|
||||||
|
),
|
||||||
|
),
|
||||||
|
)
|
||||||
|
: const SizedBox.shrink(),
|
||||||
|
),
|
||||||
|
// ── Notes ─────────────────────────────────────────────
|
||||||
const SizedBox(height: 12),
|
const SizedBox(height: 12),
|
||||||
TextField(
|
TextField(
|
||||||
controller: _notesCtrl,
|
controller: _notesCtrl,
|
||||||
maxLines: 2,
|
minLines: 2,
|
||||||
|
maxLines: 4,
|
||||||
decoration: const InputDecoration(labelText: 'Notes'),
|
decoration: const InputDecoration(labelText: 'Notes'),
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
@@ -228,7 +234,13 @@ class _PortEditDialogState extends ConsumerState<_PortEditDialog> {
|
|||||||
),
|
),
|
||||||
FilledButton(
|
FilledButton(
|
||||||
onPressed: _saving ? null : _save,
|
onPressed: _saving ? null : _save,
|
||||||
child: Text(_saving ? 'Saving…' : 'Save'),
|
child: _saving
|
||||||
|
? const SizedBox(
|
||||||
|
width: 16,
|
||||||
|
height: 16,
|
||||||
|
child: CircularProgressIndicator(strokeWidth: 2),
|
||||||
|
)
|
||||||
|
: Text(widget.existing == null ? 'Add' : 'Save'),
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -21,7 +21,7 @@ class PortListTile extends StatelessWidget {
|
|||||||
final String? linkedDeviceName;
|
final String? linkedDeviceName;
|
||||||
final String? linkedPortLabel;
|
final String? linkedPortLabel;
|
||||||
final bool canEdit;
|
final bool canEdit;
|
||||||
final VoidCallback? onTap;
|
final void Function(BuildContext)? onTap;
|
||||||
final void Function(BuildContext)? onConnect;
|
final void Function(BuildContext)? onConnect;
|
||||||
final void Function(BuildContext)? onDisconnect;
|
final void Function(BuildContext)? onDisconnect;
|
||||||
final VoidCallback? onDelete;
|
final VoidCallback? onDelete;
|
||||||
@@ -40,7 +40,7 @@ class PortListTile extends StatelessWidget {
|
|||||||
];
|
];
|
||||||
|
|
||||||
return ListTile(
|
return ListTile(
|
||||||
onTap: onTap,
|
onTap: onTap == null ? null : () => onTap!(context),
|
||||||
leading: CircleAvatar(
|
leading: CircleAvatar(
|
||||||
backgroundColor: isLinked
|
backgroundColor: isLinked
|
||||||
? cs.primaryContainer
|
? cs.primaryContainer
|
||||||
@@ -75,7 +75,7 @@ class PortListTile extends StatelessWidget {
|
|||||||
onSelected: (action) {
|
onSelected: (action) {
|
||||||
switch (action) {
|
switch (action) {
|
||||||
case _PortAction.editPort:
|
case _PortAction.editPort:
|
||||||
onTap?.call();
|
onTap?.call(context);
|
||||||
case _PortAction.connect:
|
case _PortAction.connect:
|
||||||
onConnect?.call(context);
|
onConnect?.call(context);
|
||||||
case _PortAction.disconnect:
|
case _PortAction.disconnect:
|
||||||
|
|||||||
Reference in New Issue
Block a user