Skip to content

Add feature fake data provider #777

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 5 commits into
base: main
Choose a base branch
from
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 5 additions & 3 deletions lib/screens/common_widgets/envvar_span.dart
Original file line number Diff line number Diff line change
@@ -27,9 +27,11 @@ class EnvVarSpan extends HookConsumerWidget {
final showPopover = useState(false);

final isMissingVariable = suggestion.isUnknown;
final String scope = isMissingVariable
? 'unknown'
: getEnvironmentTitle(environments?[suggestion.environmentId]?.name);
final String scope = suggestion.environmentId == "Random"
? "Random"
: isMissingVariable
? 'unknown'
: getEnvironmentTitle(environments?[suggestion.environmentId]?.name);
final colorScheme = Theme.of(context).colorScheme;

var text = Text(
214 changes: 214 additions & 0 deletions lib/screens/envvar/editor_pane/fake_data_pane.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,214 @@
import 'package:apidash_design_system/apidash_design_system.dart';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:hooks_riverpod/hooks_riverpod.dart';
import 'package:apidash/utils/fake_data_provider.dart';

class FakeDataProvidersPane extends ConsumerWidget {
const FakeDataProvidersPane({super.key});

@override
Widget build(BuildContext context, WidgetRef ref) {
return Container(
decoration: BoxDecoration(
color: Theme.of(context).colorScheme.surface,
borderRadius: kBorderRadius12,
),
margin: kP10,
child: Column(
crossAxisAlignment: CrossAxisAlignment.stretch,
children: [
Expanded(
child: SingleChildScrollView(
child: Padding(
padding: const EdgeInsets.all(16),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
'Fake Data Providers',
style: Theme.of(context).textTheme.titleMedium,
),
const SizedBox(height: 10),
Text(
'Use these placeholders in your API requests to generate random test data automatically.',
style: Theme.of(context).textTheme.bodyMedium,
),
const SizedBox(height: 20),
Text(
'How to use:',
style: Theme.of(context).textTheme.titleSmall,
),
const SizedBox(height: 5),
Text(
'Type {{\$tagName}} in any field where you want to use random data.',
style: Theme.of(context).textTheme.bodyMedium,
),
const SizedBox(height: 10),
Text(
'For example: {{\$randomEmail}} will be replaced with a randomly generated email address.',
style: Theme.of(context).textTheme.bodyMedium,
),
const SizedBox(height: 30),
Text(
'Available Placeholders:',
style: Theme.of(context).textTheme.titleSmall,
),
const SizedBox(height: 20),
_buildFakeDataTable(context),
],
),
),
),
),
],
),
);
}

Widget _buildFakeDataTable(BuildContext context) {
final fakeDataTags = [
_FakeDataItem(
name: 'randomUsername',
description: 'Random username (e.g., user123, test_dev)',
example: FakeDataProvider.randomUsername(),
),
_FakeDataItem(
name: 'randomEmail',
description: 'Random email address',
example: FakeDataProvider.randomEmail(),
),
_FakeDataItem(
name: 'randomId',
description: 'Random numeric ID',
example: FakeDataProvider.randomId(),
),
_FakeDataItem(
name: 'randomUuid',
description: 'Random UUID',
example: FakeDataProvider.randomUuid(),
),
_FakeDataItem(
name: 'randomName',
description: 'Random full name',
example: FakeDataProvider.randomName(),
),
_FakeDataItem(
name: 'randomPhone',
description: 'Random phone number',
example: FakeDataProvider.randomPhone(),
),
_FakeDataItem(
name: 'randomAddress',
description: 'Random address',
example: FakeDataProvider.randomAddress(),
),
_FakeDataItem(
name: 'randomDate',
description: 'Random date (YYYY-MM-DD)',
example: FakeDataProvider.randomDate(),
),
_FakeDataItem(
name: 'randomDateTime',
description: 'Random date and time (ISO format)',
example: FakeDataProvider.randomDateTime(),
),
_FakeDataItem(
name: 'randomBoolean',
description: 'Random boolean value (true/false)',
example: FakeDataProvider.randomBoolean(),
),
_FakeDataItem(
name: 'randomNumber',
description: 'Random number between 0-1000',
example: FakeDataProvider.randomNumber(),
),
_FakeDataItem(
name: 'randomJson',
description: 'Random JSON object with basic fields',
example: FakeDataProvider.randomJson(),
),
];

return Table(
columnWidths: const {
0: FlexColumnWidth(1.2),
1: FlexColumnWidth(2),
2: FlexColumnWidth(1.5),
3: FlexColumnWidth(0.5),
},
defaultVerticalAlignment: TableCellVerticalAlignment.middle,
border: TableBorder.all(
color: Theme.of(context).colorScheme.outline,
width: 1,
),
children: [

TableRow(
decoration: BoxDecoration(
color: Theme.of(context).colorScheme.surfaceContainerHigh,
),
children: [
_buildTableCell(context, 'Placeholder', isHeader: true),
_buildTableCell(context, 'Description', isHeader: true),
_buildTableCell(context, 'Example Output', isHeader: true),
_buildTableCell(context, 'Copy', isHeader: true),
],
),

for (var item in fakeDataTags)
TableRow(
children: [
_buildTableCell(context, '{{\$${item.name}}}'),
_buildTableCell(context, item.description),
_buildTableCell(context, item.example),
_buildCopyButton(context, '{{\$${item.name}}}'),
],
),
],
);
}

Widget _buildTableCell(BuildContext context, String text, {bool isHeader = false}) {
return Padding(
padding: const EdgeInsets.all(8),
child: Text(
text,
style: isHeader
? Theme.of(context).textTheme.titleSmall
: Theme.of(context).textTheme.bodyMedium,
),
);
}

Widget _buildCopyButton(BuildContext context, String textToCopy) {
return Padding(
padding: const EdgeInsets.all(4),
child: IconButton(
icon: const Icon(Icons.copy, size: 18),
onPressed: () {
Clipboard.setData(ClipboardData(text: textToCopy));
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(
content: Text('Copied $textToCopy to clipboard'),
duration: const Duration(seconds: 1),
),
);
},
tooltip: 'Copy to clipboard',
),
);
}
}

class _FakeDataItem {
final String name;
final String description;
final String example;

_FakeDataItem({
required this.name,
required this.description,
required this.example,
});
}
90 changes: 75 additions & 15 deletions lib/screens/envvar/environment_editor.dart
Original file line number Diff line number Diff line change
@@ -6,10 +6,81 @@ import 'package:apidash/widgets/widgets.dart';
import 'package:apidash/consts.dart';
import '../common_widgets/common_widgets.dart';
import './editor_pane/variables_pane.dart';
import './editor_pane/fake_data_pane.dart';

final environmentEditorTabProvider = StateProvider<int>((ref) => 0);

class EnvironmentEditor extends ConsumerWidget {
const EnvironmentEditor({super.key});

Widget _buildTabBar(BuildContext context, WidgetRef ref) {
final selectedTab = ref.watch(environmentEditorTabProvider);

return Row(
mainAxisAlignment: MainAxisAlignment.center,
children: [
_buildTabButton(
context,
'Environment Variables',
0,
selectedTab == 0,
() => ref.read(environmentEditorTabProvider.notifier).state = 0,
),
const SizedBox(width: 16),
_buildTabButton(
context,
'Fake Data Providers',
1,
selectedTab == 1,
() => ref.read(environmentEditorTabProvider.notifier).state = 1,
),
],
);
}

Widget _buildTabButton(BuildContext context, String title, int index, bool isSelected, VoidCallback onPressed) {
return ElevatedButton(
onPressed: onPressed,
style: ElevatedButton.styleFrom(
backgroundColor: isSelected
? Theme.of(context).colorScheme.primaryContainer
: Theme.of(context).colorScheme.surfaceContainerLow,
foregroundColor: isSelected
? Theme.of(context).colorScheme.primary
: Theme.of(context).colorScheme.onSurface,
elevation: 0,
padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 12),
),
child: Text(title),
);
}

Widget _buildTabContent(WidgetRef ref) {
final selectedTab = ref.watch(environmentEditorTabProvider);

if (selectedTab == 0) {
return Column(
children: [
const Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
SizedBox(width: 30),
Text("Variable"),
SizedBox(width: 30),
Text("Value"),
SizedBox(width: 40),
],
),
kHSpacer40,
const Divider(),
const Expanded(child: EditEnvironmentVariables()),
],
);
} else {
return const FakeDataProvidersPane();
}
}

@override
Widget build(BuildContext context, WidgetRef ref) {
final id = ref.watch(selectedEnvironmentIdStateProvider);
@@ -84,24 +155,13 @@ class EnvironmentEditor extends ConsumerWidget {
borderRadius: kBorderRadius12,
),
elevation: 0,
child: const Padding(
child: Padding(
padding: kPv6,
child: Column(
children: [
kHSpacer40,
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
SizedBox(width: 30),
Text("Variable"),
SizedBox(width: 30),
Text("Value"),
SizedBox(width: 40),
],
),
kHSpacer40,
Divider(),
Expanded(child: EditEnvironmentVariables())
_buildTabBar(context, ref),
kHSpacer20,
Expanded(child: _buildTabContent(ref))
],
),
),
33 changes: 29 additions & 4 deletions lib/utils/envvar_utils.dart
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import 'package:apidash_core/apidash_core.dart';
import 'package:apidash/consts.dart';
import 'fake_data_provider.dart';

String getEnvironmentTitle(String? name) {
if (name == null || name.trim() == "") {
@@ -41,6 +42,7 @@ String? substituteVariables(
Map<String, String> envVarMap,
) {
if (input == null) return null;

if (envVarMap.keys.isEmpty) {
return input;
}
@@ -151,9 +153,32 @@ EnvironmentVariableSuggestion getVariableStatus(
);
}

// If not found in environments check if it's a random data generator
if (key.startsWith('\$')) {
final generatorType = key.substring(1);
final generator = FakeDataProvider.processFakeDataTag(generatorType);
if (generator != '{{generatorType}}') {
return EnvironmentVariableSuggestion(
environmentId: "Random",
variable: EnvironmentVariableModel(
key: key,
type: EnvironmentVariableType.variable,
value: generator,
enabled: true,
),
isUnknown: false,
);
}
}

return EnvironmentVariableSuggestion(
isUnknown: true,
environmentId: "unknown",
variable: EnvironmentVariableModel(
key: key, type: EnvironmentVariableType.variable, value: "unknown"));
isUnknown: true,
environmentId: "unknown",
variable: EnvironmentVariableModel(
key: key,
type: EnvironmentVariableType.variable,
value: "unknown",
// enabled: false,
),
);
}
Loading