mirror of
https://github.com/foss42/apidash.git
synced 2025-06-04 17:37:05 +08:00
Merge branch 'main' into add-feature-22
This commit is contained in:
1
devtools_options.yaml
Normal file
1
devtools_options.yaml
Normal file
@ -0,0 +1 @@
|
|||||||
|
extensions:
|
@ -48,6 +48,7 @@ const kHintOpacity = 0.6;
|
|||||||
const kForegroundOpacity = 0.05;
|
const kForegroundOpacity = 0.05;
|
||||||
|
|
||||||
const kTextStyleButton = TextStyle(fontWeight: FontWeight.bold);
|
const kTextStyleButton = TextStyle(fontWeight: FontWeight.bold);
|
||||||
|
const kTextStyleButtonSmall = TextStyle(fontSize: 12);
|
||||||
const kFormDataButtonLabelTextStyle = TextStyle(
|
const kFormDataButtonLabelTextStyle = TextStyle(
|
||||||
fontSize: 12,
|
fontSize: 12,
|
||||||
fontWeight: FontWeight.w600,
|
fontWeight: FontWeight.w600,
|
||||||
|
@ -54,7 +54,7 @@ class EditRequestHeadersState extends ConsumerState<EditRequestHeaders> {
|
|||||||
columns: [
|
columns: [
|
||||||
DaviColumn(
|
DaviColumn(
|
||||||
name: 'Checkbox',
|
name: 'Checkbox',
|
||||||
width: 36,
|
width: 30,
|
||||||
cellBuilder: (_, row) {
|
cellBuilder: (_, row) {
|
||||||
int idx = row.index;
|
int idx = row.index;
|
||||||
return CheckBox(
|
return CheckBox(
|
||||||
@ -72,6 +72,7 @@ class EditRequestHeadersState extends ConsumerState<EditRequestHeaders> {
|
|||||||
),
|
),
|
||||||
DaviColumn(
|
DaviColumn(
|
||||||
name: 'Header Name',
|
name: 'Header Name',
|
||||||
|
width: 70,
|
||||||
grow: 1,
|
grow: 1,
|
||||||
cellBuilder: (_, row) {
|
cellBuilder: (_, row) {
|
||||||
int idx = row.index;
|
int idx = row.index;
|
||||||
|
@ -55,7 +55,7 @@ class EditRequestURLParamsState extends ConsumerState<EditRequestURLParams> {
|
|||||||
columns: [
|
columns: [
|
||||||
DaviColumn(
|
DaviColumn(
|
||||||
name: 'Checkbox',
|
name: 'Checkbox',
|
||||||
width: 36,
|
width: 30,
|
||||||
cellBuilder: (_, row) {
|
cellBuilder: (_, row) {
|
||||||
int idx = row.index;
|
int idx = row.index;
|
||||||
|
|
||||||
@ -74,6 +74,7 @@ class EditRequestURLParamsState extends ConsumerState<EditRequestURLParams> {
|
|||||||
),
|
),
|
||||||
DaviColumn(
|
DaviColumn(
|
||||||
name: 'URL Parameter',
|
name: 'URL Parameter',
|
||||||
|
width: 70,
|
||||||
grow: 1,
|
grow: 1,
|
||||||
cellBuilder: (_, row) {
|
cellBuilder: (_, row) {
|
||||||
int idx = row.index;
|
int idx = row.index;
|
||||||
|
@ -59,3 +59,13 @@ Color getDarkModeColor(Color col) {
|
|||||||
kColorWhite,
|
kColorWhite,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
double? getJsonPreviewerMaxRootNodeWidth(double w) {
|
||||||
|
if (w < 300) {
|
||||||
|
return 150;
|
||||||
|
}
|
||||||
|
if (w < 400) {
|
||||||
|
return 200;
|
||||||
|
}
|
||||||
|
return w - 150;
|
||||||
|
}
|
||||||
|
@ -5,6 +5,7 @@ import 'package:provider/provider.dart';
|
|||||||
import 'package:scrollable_positioned_list/scrollable_positioned_list.dart';
|
import 'package:scrollable_positioned_list/scrollable_positioned_list.dart';
|
||||||
import 'package:url_launcher/url_launcher_string.dart';
|
import 'package:url_launcher/url_launcher_string.dart';
|
||||||
import '../consts.dart';
|
import '../consts.dart';
|
||||||
|
import '../utils/ui_utils.dart';
|
||||||
import "snackbars.dart";
|
import "snackbars.dart";
|
||||||
import 'textfields.dart';
|
import 'textfields.dart';
|
||||||
|
|
||||||
@ -151,120 +152,151 @@ class _JsonPreviewerState extends State<JsonPreviewer> {
|
|||||||
store.expandAll();
|
store.expandAll();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
void didUpdateWidget(JsonPreviewer oldWidget) {
|
||||||
|
if (oldWidget.code != widget.code) {
|
||||||
|
store.buildNodes(widget.code, areAllCollapsed: true);
|
||||||
|
store.expandAll();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
var sm = ScaffoldMessenger.of(context);
|
var sm = ScaffoldMessenger.of(context);
|
||||||
return ChangeNotifierProvider.value(
|
return ChangeNotifierProvider.value(
|
||||||
value: store,
|
value: store,
|
||||||
child: Consumer<DataExplorerStore>(
|
child: Consumer<DataExplorerStore>(
|
||||||
builder: (context, state, child) => Column(
|
builder: (context, state, child) {
|
||||||
crossAxisAlignment: CrossAxisAlignment.start,
|
return LayoutBuilder(
|
||||||
children: [
|
builder: (BuildContext context, BoxConstraints constraints) {
|
||||||
Row(
|
var maxRootNodeWidth =
|
||||||
mainAxisAlignment: MainAxisAlignment.end,
|
getJsonPreviewerMaxRootNodeWidth(constraints.maxWidth);
|
||||||
children: [
|
return Column(
|
||||||
TextButton(
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
onPressed: () async {
|
|
||||||
await _copy(kEncoder.convert(widget.code), sm);
|
|
||||||
},
|
|
||||||
child: const Text('Copy'),
|
|
||||||
),
|
|
||||||
TextButton(
|
|
||||||
onPressed: state.areAllExpanded() ? null : state.expandAll,
|
|
||||||
child: const Text('Expand All'),
|
|
||||||
),
|
|
||||||
TextButton(
|
|
||||||
onPressed: state.areAllCollapsed() ? null : state.collapseAll,
|
|
||||||
child: const Text('Collapse All'),
|
|
||||||
),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
Expanded(
|
|
||||||
child: JsonDataExplorer(
|
|
||||||
nodes: state.displayNodes,
|
|
||||||
itemScrollController: itemScrollController,
|
|
||||||
itemSpacing: 4,
|
|
||||||
rootInformationBuilder: (context, node) =>
|
|
||||||
rootInfoBox(context, node),
|
|
||||||
collapsableToggleBuilder: (context, node) => AnimatedRotation(
|
|
||||||
turns: node.isCollapsed ? -0.25 : 0,
|
|
||||||
duration: const Duration(milliseconds: 300),
|
|
||||||
child: const Icon(Icons.arrow_drop_down),
|
|
||||||
),
|
|
||||||
trailingBuilder: (context, node) => node.isFocused
|
|
||||||
? Padding(
|
|
||||||
padding: const EdgeInsets.only(right: 12),
|
|
||||||
child: IconButton(
|
|
||||||
padding: EdgeInsets.zero,
|
|
||||||
constraints: const BoxConstraints(maxHeight: 18),
|
|
||||||
icon: const Icon(
|
|
||||||
Icons.copy,
|
|
||||||
size: 18,
|
|
||||||
),
|
|
||||||
onPressed: () async {
|
|
||||||
await _copy(kEncoder.convert(toJson(node)), sm);
|
|
||||||
},
|
|
||||||
),
|
|
||||||
)
|
|
||||||
: const SizedBox(),
|
|
||||||
valueStyleBuilder: (value, style) =>
|
|
||||||
valueStyleOverride(context, value, style),
|
|
||||||
theme: (Theme.of(context).brightness == Brightness.light)
|
|
||||||
? dataExplorerThemeLight
|
|
||||||
: dataExplorerThemeDark,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
Container(
|
|
||||||
decoration: BoxDecoration(
|
|
||||||
color: Theme.of(context).colorScheme.background,
|
|
||||||
border: Border.all(
|
|
||||||
color: Theme.of(context).colorScheme.surfaceVariant),
|
|
||||||
borderRadius: kBorderRadius8,
|
|
||||||
),
|
|
||||||
child: Row(
|
|
||||||
children: [
|
children: [
|
||||||
const Padding(
|
Row(
|
||||||
padding: EdgeInsets.symmetric(horizontal: 8.0),
|
mainAxisAlignment: MainAxisAlignment.end,
|
||||||
child: Icon(
|
children: [
|
||||||
Icons.search,
|
TextButton(
|
||||||
size: 18,
|
onPressed: () async {
|
||||||
),
|
await _copy(kEncoder.convert(widget.code), sm);
|
||||||
|
},
|
||||||
|
child: const Text(
|
||||||
|
'Copy',
|
||||||
|
style: kTextStyleButtonSmall,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
TextButton(
|
||||||
|
onPressed:
|
||||||
|
state.areAllExpanded() ? null : state.expandAll,
|
||||||
|
child: const Text(
|
||||||
|
'Expand All',
|
||||||
|
style: kTextStyleButtonSmall,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
TextButton(
|
||||||
|
onPressed:
|
||||||
|
state.areAllCollapsed() ? null : state.collapseAll,
|
||||||
|
child: const Text(
|
||||||
|
'Collapse All',
|
||||||
|
style: kTextStyleButtonSmall,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
),
|
),
|
||||||
Expanded(
|
Expanded(
|
||||||
child: JsonSearchField(
|
child: JsonDataExplorer(
|
||||||
controller: searchController,
|
nodes: state.displayNodes,
|
||||||
onChanged: (term) => state.search(term),
|
itemScrollController: itemScrollController,
|
||||||
|
itemSpacing: 4,
|
||||||
|
rootInformationBuilder: (context, node) =>
|
||||||
|
rootInfoBox(context, node),
|
||||||
|
collapsableToggleBuilder: (context, node) =>
|
||||||
|
AnimatedRotation(
|
||||||
|
turns: node.isCollapsed ? -0.25 : 0,
|
||||||
|
duration: const Duration(milliseconds: 300),
|
||||||
|
child: const Icon(Icons.arrow_drop_down),
|
||||||
|
),
|
||||||
|
trailingBuilder: (context, node) => node.isFocused
|
||||||
|
? Padding(
|
||||||
|
padding: const EdgeInsets.only(right: 12),
|
||||||
|
child: IconButton(
|
||||||
|
padding: EdgeInsets.zero,
|
||||||
|
constraints:
|
||||||
|
const BoxConstraints(maxHeight: 18),
|
||||||
|
icon: const Icon(
|
||||||
|
Icons.copy,
|
||||||
|
size: 18,
|
||||||
|
),
|
||||||
|
onPressed: () async {
|
||||||
|
await _copy(
|
||||||
|
kEncoder.convert(toJson(node)), sm);
|
||||||
|
},
|
||||||
|
),
|
||||||
|
)
|
||||||
|
: const SizedBox(),
|
||||||
|
valueStyleBuilder: (value, style) =>
|
||||||
|
valueStyleOverride(context, value, style),
|
||||||
|
theme: (Theme.of(context).brightness == Brightness.light)
|
||||||
|
? dataExplorerThemeLight
|
||||||
|
: dataExplorerThemeDark,
|
||||||
|
maxRootNodeWidth: maxRootNodeWidth,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
const SizedBox(
|
Container(
|
||||||
width: 8,
|
decoration: BoxDecoration(
|
||||||
|
color: Theme.of(context).colorScheme.background,
|
||||||
|
border: Border.all(
|
||||||
|
color: Theme.of(context).colorScheme.surfaceVariant),
|
||||||
|
borderRadius: kBorderRadius8,
|
||||||
|
),
|
||||||
|
child: Row(
|
||||||
|
children: [
|
||||||
|
const Padding(
|
||||||
|
padding: EdgeInsets.symmetric(horizontal: 8.0),
|
||||||
|
child: Icon(
|
||||||
|
Icons.search,
|
||||||
|
size: 18,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
Expanded(
|
||||||
|
child: JsonSearchField(
|
||||||
|
controller: searchController,
|
||||||
|
onChanged: (term) => state.search(term),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
const SizedBox(
|
||||||
|
width: 8,
|
||||||
|
),
|
||||||
|
if (state.searchResults.isNotEmpty)
|
||||||
|
Text(_searchFocusText(),
|
||||||
|
style: Theme.of(context).textTheme.bodySmall),
|
||||||
|
if (state.searchResults.isNotEmpty)
|
||||||
|
IconButton(
|
||||||
|
visualDensity: VisualDensity.compact,
|
||||||
|
onPressed: () {
|
||||||
|
store.focusPreviousSearchResult();
|
||||||
|
_scrollToSearchMatch();
|
||||||
|
},
|
||||||
|
icon: const Icon(Icons.arrow_drop_up),
|
||||||
|
),
|
||||||
|
if (state.searchResults.isNotEmpty)
|
||||||
|
IconButton(
|
||||||
|
visualDensity: VisualDensity.compact,
|
||||||
|
onPressed: () {
|
||||||
|
store.focusNextSearchResult();
|
||||||
|
_scrollToSearchMatch();
|
||||||
|
},
|
||||||
|
icon: const Icon(Icons.arrow_drop_down),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
),
|
),
|
||||||
if (state.searchResults.isNotEmpty)
|
|
||||||
Text(_searchFocusText(),
|
|
||||||
style: Theme.of(context).textTheme.bodySmall),
|
|
||||||
if (state.searchResults.isNotEmpty)
|
|
||||||
IconButton(
|
|
||||||
visualDensity: VisualDensity.compact,
|
|
||||||
onPressed: () {
|
|
||||||
store.focusPreviousSearchResult();
|
|
||||||
_scrollToSearchMatch();
|
|
||||||
},
|
|
||||||
icon: const Icon(Icons.arrow_drop_up),
|
|
||||||
),
|
|
||||||
if (state.searchResults.isNotEmpty)
|
|
||||||
IconButton(
|
|
||||||
visualDensity: VisualDensity.compact,
|
|
||||||
onPressed: () {
|
|
||||||
store.focusNextSearchResult();
|
|
||||||
_scrollToSearchMatch();
|
|
||||||
},
|
|
||||||
icon: const Icon(Icons.arrow_drop_down),
|
|
||||||
),
|
|
||||||
],
|
],
|
||||||
),
|
);
|
||||||
),
|
},
|
||||||
],
|
);
|
||||||
),
|
},
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -397,6 +397,13 @@ class _BodySuccessState extends State<BodySuccess> {
|
|||||||
(widget.options == kRawBodyViewOptions)
|
(widget.options == kRawBodyViewOptions)
|
||||||
? const SizedBox()
|
? const SizedBox()
|
||||||
: SegmentedButton<ResponseBodyView>(
|
: SegmentedButton<ResponseBodyView>(
|
||||||
|
style: const ButtonStyle(
|
||||||
|
padding: MaterialStatePropertyAll(
|
||||||
|
EdgeInsets.symmetric(
|
||||||
|
horizontal: 8,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
selectedIcon: Icon(currentSeg.icon),
|
selectedIcon: Icon(currentSeg.icon),
|
||||||
segments: widget.options
|
segments: widget.options
|
||||||
.map<ButtonSegment<ResponseBodyView>>(
|
.map<ButtonSegment<ResponseBodyView>>(
|
||||||
@ -418,7 +425,7 @@ class _BodySuccessState extends State<BodySuccess> {
|
|||||||
const Spacer(),
|
const Spacer(),
|
||||||
kCodeRawBodyViewOptions.contains(currentSeg)
|
kCodeRawBodyViewOptions.contains(currentSeg)
|
||||||
? CopyButton(
|
? CopyButton(
|
||||||
toCopy: widget.body,
|
toCopy: widget.formattedBody ?? widget.body,
|
||||||
showLabel: showLabel,
|
showLabel: showLabel,
|
||||||
)
|
)
|
||||||
: const SizedBox(),
|
: const SizedBox(),
|
||||||
@ -474,7 +481,7 @@ class _BodySuccessState extends State<BodySuccess> {
|
|||||||
decoration: textContainerdecoration,
|
decoration: textContainerdecoration,
|
||||||
child: SingleChildScrollView(
|
child: SingleChildScrollView(
|
||||||
child: SelectableText(
|
child: SelectableText(
|
||||||
widget.body,
|
widget.formattedBody ?? widget.body,
|
||||||
style: kCodeStyle,
|
style: kCodeStyle,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
24
pubspec.lock
24
pubspec.lock
@ -281,6 +281,14 @@ packages:
|
|||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "7.0.0"
|
version: "7.0.0"
|
||||||
|
file_picker:
|
||||||
|
dependency: "direct main"
|
||||||
|
description:
|
||||||
|
name: file_picker
|
||||||
|
sha256: "4e42aacde3b993c5947467ab640882c56947d9d27342a5b6f2895b23956954a6"
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "6.1.1"
|
||||||
fixnum:
|
fixnum:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
@ -366,6 +374,14 @@ packages:
|
|||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "0.6.18+2"
|
version: "0.6.18+2"
|
||||||
|
flutter_plugin_android_lifecycle:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: flutter_plugin_android_lifecycle
|
||||||
|
sha256: b068ffc46f82a55844acfa4fdbb61fad72fa2aef0905548419d97f0f95c456da
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "2.0.17"
|
||||||
flutter_riverpod:
|
flutter_riverpod:
|
||||||
dependency: "direct main"
|
dependency: "direct main"
|
||||||
description:
|
description:
|
||||||
@ -548,11 +564,11 @@ packages:
|
|||||||
dependency: "direct main"
|
dependency: "direct main"
|
||||||
description:
|
description:
|
||||||
path: "."
|
path: "."
|
||||||
ref: HEAD
|
ref: "9fa58d7b51e65174ab11cbcae17bba88a4194dde"
|
||||||
resolved-ref: "9e279ee9862c4fc4050dbcb5074529b22e67a7c3"
|
resolved-ref: "9fa58d7b51e65174ab11cbcae17bba88a4194dde"
|
||||||
url: "https://github.com/foss42/json_data_explorer.git"
|
url: "https://github.com/foss42/json_data_explorer.git"
|
||||||
source: git
|
source: git
|
||||||
version: "0.1.1"
|
version: "0.1.2"
|
||||||
json_serializable:
|
json_serializable:
|
||||||
dependency: "direct dev"
|
dependency: "direct dev"
|
||||||
description:
|
description:
|
||||||
@ -1304,5 +1320,5 @@ packages:
|
|||||||
source: hosted
|
source: hosted
|
||||||
version: "3.1.2"
|
version: "3.1.2"
|
||||||
sdks:
|
sdks:
|
||||||
dart: ">=3.2.0 <4.0.0"
|
dart: ">=3.2.3 <4.0.0"
|
||||||
flutter: ">=3.16.0"
|
flutter: ">=3.16.0"
|
||||||
|
@ -47,7 +47,7 @@ dependencies:
|
|||||||
json_data_explorer:
|
json_data_explorer:
|
||||||
git:
|
git:
|
||||||
url: https://github.com/foss42/json_data_explorer.git
|
url: https://github.com/foss42/json_data_explorer.git
|
||||||
version: ^0.1.1
|
ref: 9fa58d7b51e65174ab11cbcae17bba88a4194dde
|
||||||
scrollable_positioned_list: ^0.2.3
|
scrollable_positioned_list: ^0.2.3
|
||||||
file_picker: ^6.1.1
|
file_picker: ^6.1.1
|
||||||
flutter_svg: ^2.0.9
|
flutter_svg: ^2.0.9
|
||||||
|
Reference in New Issue
Block a user