mirror of
https://github.com/foss42/apidash.git
synced 2025-06-01 23:45:19 +08:00
fix: history body view
This commit is contained in:
@ -53,7 +53,69 @@ class HistoryRequestPane extends ConsumerWidget {
|
|||||||
rows: headersMap,
|
rows: headersMap,
|
||||||
keyName: kNameHeader,
|
keyName: kNameHeader,
|
||||||
),
|
),
|
||||||
const SizedBox(),
|
const HisRequestBody(),
|
||||||
|
],
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class HisRequestBody extends ConsumerWidget {
|
||||||
|
const HisRequestBody({super.key});
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context, WidgetRef ref) {
|
||||||
|
final selectedHistoryModel = ref.watch(selectedHistoryRequestModelProvider);
|
||||||
|
final requestModel = selectedHistoryModel?.httpRequestModel;
|
||||||
|
final contentType = requestModel?.bodyContentType;
|
||||||
|
|
||||||
|
return Column(
|
||||||
|
children: [
|
||||||
|
kVSpacer5,
|
||||||
|
RichText(
|
||||||
|
text: TextSpan(
|
||||||
|
style: Theme.of(context).textTheme.labelLarge,
|
||||||
|
children: [
|
||||||
|
const TextSpan(
|
||||||
|
text: "Content Type: ",
|
||||||
|
),
|
||||||
|
TextSpan(
|
||||||
|
text: contentType?.name ?? "text",
|
||||||
|
style: Theme.of(context).textTheme.titleSmall?.copyWith(
|
||||||
|
color: Theme.of(context).colorScheme.primary,
|
||||||
|
fontWeight: FontWeight.bold,
|
||||||
|
)),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
kVSpacer5,
|
||||||
|
Expanded(
|
||||||
|
child: switch (contentType) {
|
||||||
|
ContentType.formdata => Padding(
|
||||||
|
padding: kPh4,
|
||||||
|
child:
|
||||||
|
RequestFormDataTable(rows: requestModel?.formData ?? [])),
|
||||||
|
// TODO: Fix JsonTextFieldEditor & plug it here
|
||||||
|
ContentType.json => Padding(
|
||||||
|
padding: kPt5o10,
|
||||||
|
child: TextFieldEditor(
|
||||||
|
key: Key("${selectedHistoryModel?.historyId}-json-body"),
|
||||||
|
fieldKey:
|
||||||
|
"${selectedHistoryModel?.historyId}-json-body-viewer",
|
||||||
|
initialValue: requestModel?.body,
|
||||||
|
readOnly: true,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
_ => Padding(
|
||||||
|
padding: kPt5o10,
|
||||||
|
child: TextFieldEditor(
|
||||||
|
key: Key("${selectedHistoryModel?.historyId}-body"),
|
||||||
|
fieldKey: "${selectedHistoryModel?.historyId}-body-viewer",
|
||||||
|
initialValue: requestModel?.body,
|
||||||
|
readOnly: true,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
},
|
||||||
|
)
|
||||||
],
|
],
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -124,17 +124,7 @@ class _FormDataBodyState extends ConsumerState<FormDataWidget> {
|
|||||||
),
|
),
|
||||||
DataCell(
|
DataCell(
|
||||||
formRows[index].type == FormDataType.file
|
formRows[index].type == FormDataType.file
|
||||||
? ElevatedButton.icon(
|
? FormDataFileButton(
|
||||||
icon: const Icon(
|
|
||||||
Icons.snippet_folder_rounded,
|
|
||||||
size: 20,
|
|
||||||
),
|
|
||||||
style: ElevatedButton.styleFrom(
|
|
||||||
minimumSize: const Size.fromHeight(kDataTableRowHeight),
|
|
||||||
shape: RoundedRectangleBorder(
|
|
||||||
borderRadius: BorderRadius.circular(6),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
onPressed: () async {
|
onPressed: () async {
|
||||||
var pickedResult = await pickFile();
|
var pickedResult = await pickFile();
|
||||||
if (pickedResult != null &&
|
if (pickedResult != null &&
|
||||||
@ -146,14 +136,7 @@ class _FormDataBodyState extends ConsumerState<FormDataWidget> {
|
|||||||
_onFieldChange(selectedId!);
|
_onFieldChange(selectedId!);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
label: Text(
|
initialValue: formRows[index].value,
|
||||||
(formRows[index].type == FormDataType.file &&
|
|
||||||
formRows[index].value.isNotEmpty)
|
|
||||||
? formRows[index].value.toString()
|
|
||||||
: kLabelSelectFile,
|
|
||||||
overflow: TextOverflow.ellipsis,
|
|
||||||
style: kFormDataButtonLabelTextStyle,
|
|
||||||
),
|
|
||||||
)
|
)
|
||||||
: CellField(
|
: CellField(
|
||||||
keyId: "$selectedId-$index-form-v-$seed",
|
keyId: "$selectedId-$index-form-v-$seed",
|
||||||
|
31
lib/widgets/button_form_data_file.dart
Normal file
31
lib/widgets/button_form_data_file.dart
Normal file
@ -0,0 +1,31 @@
|
|||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:apidash/consts.dart';
|
||||||
|
|
||||||
|
class FormDataFileButton extends StatelessWidget {
|
||||||
|
const FormDataFileButton({super.key, this.onPressed, this.initialValue});
|
||||||
|
|
||||||
|
final VoidCallback? onPressed;
|
||||||
|
final String? initialValue;
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
return ElevatedButton.icon(
|
||||||
|
icon: const Icon(
|
||||||
|
Icons.snippet_folder_rounded,
|
||||||
|
size: 20,
|
||||||
|
),
|
||||||
|
style: ElevatedButton.styleFrom(
|
||||||
|
minimumSize: const Size.fromHeight(kDataTableRowHeight),
|
||||||
|
shape: RoundedRectangleBorder(
|
||||||
|
borderRadius: BorderRadius.circular(6),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
onPressed: onPressed,
|
||||||
|
label: Text(
|
||||||
|
initialValue ?? kLabelSelectFile,
|
||||||
|
overflow: TextOverflow.ellipsis,
|
||||||
|
style: kFormDataButtonLabelTextStyle,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
@ -9,11 +9,13 @@ class TextFieldEditor extends StatefulWidget {
|
|||||||
required this.fieldKey,
|
required this.fieldKey,
|
||||||
this.onChanged,
|
this.onChanged,
|
||||||
this.initialValue,
|
this.initialValue,
|
||||||
|
this.readOnly = false,
|
||||||
});
|
});
|
||||||
|
|
||||||
final String fieldKey;
|
final String fieldKey;
|
||||||
final Function(String)? onChanged;
|
final Function(String)? onChanged;
|
||||||
final String? initialValue;
|
final String? initialValue;
|
||||||
|
final bool readOnly;
|
||||||
@override
|
@override
|
||||||
State<TextFieldEditor> createState() => _TextFieldEditorState();
|
State<TextFieldEditor> createState() => _TextFieldEditorState();
|
||||||
}
|
}
|
||||||
@ -69,6 +71,7 @@ class _TextFieldEditorState extends State<TextFieldEditor> {
|
|||||||
keyboardType: TextInputType.multiline,
|
keyboardType: TextInputType.multiline,
|
||||||
expands: true,
|
expands: true,
|
||||||
maxLines: null,
|
maxLines: null,
|
||||||
|
readOnly: widget.readOnly,
|
||||||
style: kCodeStyle,
|
style: kCodeStyle,
|
||||||
textAlignVertical: TextAlignVertical.top,
|
textAlignVertical: TextAlignVertical.top,
|
||||||
onChanged: widget.onChanged,
|
onChanged: widget.onChanged,
|
||||||
|
@ -103,7 +103,6 @@ class RequestDataTable extends StatelessWidget {
|
|||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
kVSpacer40,
|
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
|
119
lib/widgets/table_request_form.dart
Normal file
119
lib/widgets/table_request_form.dart
Normal file
@ -0,0 +1,119 @@
|
|||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:data_table_2/data_table_2.dart';
|
||||||
|
import 'package:apidash/widgets/widgets.dart';
|
||||||
|
import 'package:apidash/models/models.dart';
|
||||||
|
import 'package:apidash/consts.dart';
|
||||||
|
|
||||||
|
class RequestFormDataTable extends StatelessWidget {
|
||||||
|
const RequestFormDataTable({
|
||||||
|
super.key,
|
||||||
|
required this.rows,
|
||||||
|
this.keyName,
|
||||||
|
this.valueName,
|
||||||
|
});
|
||||||
|
|
||||||
|
final List<FormDataModel> rows;
|
||||||
|
final String? keyName;
|
||||||
|
final String? valueName;
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
final clrScheme = Theme.of(context).colorScheme;
|
||||||
|
|
||||||
|
final List<DataColumn> columns = [
|
||||||
|
const DataColumn2(
|
||||||
|
label: Text(''),
|
||||||
|
fixedWidth: 8,
|
||||||
|
),
|
||||||
|
DataColumn2(
|
||||||
|
label: Text(keyName ?? kNameField),
|
||||||
|
),
|
||||||
|
const DataColumn2(
|
||||||
|
label: Text('='),
|
||||||
|
fixedWidth: 30,
|
||||||
|
),
|
||||||
|
DataColumn2(
|
||||||
|
label: Text(valueName ?? kNameValue),
|
||||||
|
),
|
||||||
|
const DataColumn2(
|
||||||
|
label: Text(''),
|
||||||
|
fixedWidth: 8,
|
||||||
|
),
|
||||||
|
];
|
||||||
|
|
||||||
|
final fieldDecoration = InputDecoration(
|
||||||
|
contentPadding: const EdgeInsets.only(bottom: 12),
|
||||||
|
focusedBorder: UnderlineInputBorder(
|
||||||
|
borderSide: BorderSide(
|
||||||
|
color: clrScheme.primary.withOpacity(
|
||||||
|
kHintOpacity,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
enabledBorder: UnderlineInputBorder(
|
||||||
|
borderSide: BorderSide(
|
||||||
|
color: clrScheme.surfaceContainerHighest,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
|
||||||
|
final List<DataRow> dataRows = rows
|
||||||
|
.map<DataRow>(
|
||||||
|
(FormDataModel entry) => DataRow(
|
||||||
|
cells: <DataCell>[
|
||||||
|
const DataCell(kHSpacer5),
|
||||||
|
DataCell(
|
||||||
|
ReadOnlyTextField(
|
||||||
|
initialValue: entry.name,
|
||||||
|
decoration: fieldDecoration,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
const DataCell(
|
||||||
|
Text('='),
|
||||||
|
),
|
||||||
|
DataCell(
|
||||||
|
entry.type == FormDataType.file
|
||||||
|
? Tooltip(
|
||||||
|
message: entry.value,
|
||||||
|
child: FormDataFileButton(
|
||||||
|
onPressed: () {},
|
||||||
|
initialValue: entry.value,
|
||||||
|
),
|
||||||
|
)
|
||||||
|
: ReadOnlyTextField(
|
||||||
|
initialValue: entry.value,
|
||||||
|
decoration: fieldDecoration,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
const DataCell(kHSpacer5),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
)
|
||||||
|
.toList();
|
||||||
|
|
||||||
|
return Container(
|
||||||
|
margin: kP10,
|
||||||
|
child: Column(
|
||||||
|
children: [
|
||||||
|
Expanded(
|
||||||
|
child: Theme(
|
||||||
|
data: Theme.of(context)
|
||||||
|
.copyWith(scrollbarTheme: kDataTableScrollbarTheme),
|
||||||
|
child: DataTable2(
|
||||||
|
columnSpacing: 12,
|
||||||
|
dividerThickness: 0,
|
||||||
|
horizontalMargin: 0,
|
||||||
|
headingRowHeight: 0,
|
||||||
|
dataRowHeight: kDataTableRowHeight,
|
||||||
|
bottomMargin: kDataTableBottomPadding,
|
||||||
|
isVerticalScrollBarVisible: true,
|
||||||
|
columns: columns,
|
||||||
|
rows: dataRows,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
@ -1,6 +1,7 @@
|
|||||||
export 'button_clear_response.dart';
|
export 'button_clear_response.dart';
|
||||||
export 'button_copy.dart';
|
export 'button_copy.dart';
|
||||||
export 'button_discord.dart';
|
export 'button_discord.dart';
|
||||||
|
export 'button_form_data_file.dart';
|
||||||
export 'button_group_filled.dart';
|
export 'button_group_filled.dart';
|
||||||
export 'button_repo.dart';
|
export 'button_repo.dart';
|
||||||
export 'button_save_download.dart';
|
export 'button_save_download.dart';
|
||||||
@ -51,6 +52,7 @@ export 'splitview_equal.dart';
|
|||||||
export 'splitview_history.dart';
|
export 'splitview_history.dart';
|
||||||
export 'tabbar_segmented.dart';
|
export 'tabbar_segmented.dart';
|
||||||
export 'table_map.dart';
|
export 'table_map.dart';
|
||||||
|
export 'table_request_form.dart';
|
||||||
export 'table_request.dart';
|
export 'table_request.dart';
|
||||||
export 'tabs.dart';
|
export 'tabs.dart';
|
||||||
export 'texts.dart';
|
export 'texts.dart';
|
||||||
|
Reference in New Issue
Block a user