added embedded objects
changed date presentation
MODIFY
packages/isar/lib/src/isar_connect.dart
packages/isar/lib/src/isar_connect.dart
@@ -87,7 +87,13 @@ abstract class _IsarConnect {
}
static Future<dynamic> _getSchema(Map<String, dynamic> _) async {
- return [..._schemas!.map((e) => e.toSchemaJson())];
+ return [
+ ..._schemas!.map(
+ (e) => e.toSchemaJson()
+ ..['objects'] =
+ e.embeddedSchemas.values.map((e) => e.toSchemaJson()).toList(),
+ )
+ ];
}
static Future<dynamic> _listInstances(Map<String, dynamic> _) async {

MODIFY
packages/isar_inspector/lib/desktop/app.dart
packages/isar_inspector/lib/desktop/app.dart
@@ -14,7 +14,7 @@ class App extends StatefulWidget {
class _AppState extends State<App> {
final _textController = TextEditingController();
- final urlRE = RegExp(r'^https:\/\/inspect\.isar\.dev\/#\/(\d+)\/([\w-]+)$');
+ final urlRE = RegExp(r'^https:\/\/inspect\.isar\.dev\/[\w.-]+\/#\/(\d+)\/([\w-]+)$');
String? _port;
String? _secret;
String? _error;

MODIFY
packages/isar_inspector/lib/edit_popup.dart
packages/isar_inspector/lib/edit_popup.dart
@@ -28,17 +28,24 @@ class _EditPopupState extends State<EditPopup> {
void initState() {
if (widget.type == IsarType.bool) {
_boolValue = widget.value == null || widget.value as bool;
+ } else {
+ if (widget.type == IsarType.dateTime) {
+ _controller.text = widget.value == null
+ ? ''
+ : DateTime.fromMicrosecondsSinceEpoch(widget.value as int)
+ .toIso8601String();
} else {
_controller.text = widget.value == null ? '' : widget.value.toString();
+ if (widget.type != IsarType.string) {
+ _inputFormatter = CustomTextInputFormatter(widget.type);
+ }
+ }
+
_controller.selection = TextSelection(
baseOffset: 0,
extentOffset: _controller.text.length,
);
- if (widget.type != IsarType.string) {
- _inputFormatter = CustomTextInputFormatter(widget.type);
- }
-
_focus.requestFocus();
}
@@ -101,6 +108,12 @@ class _EditPopupState extends State<EditPopup> {
if (val < 0 || val > 255) {
return 'Byte values must between 0-255';
}
+ } else if (widget.type == IsarType.dateTime) {
+ try {
+ DateTime.parse(value!);
+ } catch (_) {
+ return 'Wrong date time format';
+ }
}
return null;
},
@@ -137,6 +150,10 @@ class _EditPopupState extends State<EditPopup> {
value = double.tryParse(_controller.text) ?? 0.0;
break;
+ case IsarType.dateTime:
+ value = DateTime.parse(_controller.text).microsecondsSinceEpoch;
+ break;
+
case IsarType.byte:
case IsarType.int:
case IsarType.long:

MODIFY
packages/isar_inspector/lib/query_table.dart
packages/isar_inspector/lib/query_table.dart
@@ -17,6 +17,7 @@ import 'package:isar_inspector/state/query_state.dart';
const _stringColor = Color(0xFF6A8759);
const _numberColor = Color(0xFF6897BB);
const _boolColor = Color(0xFFCC7832);
+const _dateColor = Color(0xFFFFC66D);
const _disableColor = Colors.grey;
typedef Editor = void Function(
@@ -37,14 +38,16 @@ class QueryTable extends ConsumerWidget {
@override
Widget build(BuildContext context, WidgetRef ref) {
final collection = ref.watch(selectedCollectionPod).value!;
- final objects = ref.watch(queryResultsPod).value?.objects ?? [];
+ final queryResults = ref.watch(queryResultsPod).value;
- if (objects.isEmpty ||
- collection.allProperties.length + collection.links.length !=
- objects[0].data.length) {
+ if (queryResults == null ||
+ queryResults.objects.isEmpty ||
+ queryResults.collectionName != collection.name) {
return Container();
}
+ final objects = queryResults.objects;
+
return Column(
crossAxisAlignment: CrossAxisAlignment.stretch,
children: [
@@ -236,23 +239,75 @@ class _TableBlockState extends State<TableBlock> {
required Map<String, dynamic> data,
String prefixKey = '',
bool subLink = false,
+ List<IObject>? embeddedObjects,
}) {
+ embeddedObjects = embeddedObjects ?? widget.collection.objects;
return properties.map((property) {
+ final children = <Node<TreeViewHelper>>[];
+ final value = data[property.name];
- if ([IsarType.dateTime, IsarType.dateTimeList, IsarType.object, IsarType.objectList].contains(property.type)) {
+ if (property.type == IsarType.object) {
return Node<TreeViewHelper>(
key: '$prefixKey${property.name}',
label: '',
+ expanded: _isExpanded('$prefixKey${property.name}'),
+ children: _createProperties(
+ properties: embeddedObjects!
+ .firstWhere((e) => e.name == property.target)
+ .properties,
+ data: value as Map<String, dynamic>,
+ prefixKey: '${property.name}_',
+ subLink: subLink,
+ embeddedObjects: embeddedObjects,
+ ),
data: PropertyHelper(
- property: IProperty(name: property.name, type: IsarType.string),
- value: 'TODO',
- subLink: false,
+ property: property,
+ value: value,
+ subLink: subLink,
),
);
}
- final children = <Node<TreeViewHelper>>[];
- final value = data[property.name];
+ if (property.type == IsarType.objectList) {
+ final list = value as List<dynamic>;
+ return Node<TreeViewHelper>(
+ key: '$prefixKey${property.name}',
+ label: '',
+ expanded: _isExpanded('$prefixKey${property.name}'),
+ children: [
+ for (var index = 0; index < list.length; ++index)
+ Node<TreeViewHelper>(
+ key: '$prefixKey${property.name}_$index',
+ label: '',
+ expanded: _isExpanded('$prefixKey${property.name}_$index'),
+ children: _createProperties(
+ properties: embeddedObjects!
+ .firstWhere((e) => e.name == property.target)
+ .properties,
+ data: list[index] as Map<String, dynamic>,
+ prefixKey: '$prefixKey${property.name}_$index',
+ subLink: subLink,
+ embeddedObjects: embeddedObjects,
+ ),
+ data: PropertyHelper(
+ property: IProperty(
+ name: property.name,
+ type: property.type.scalarType,
+ target: property.target,
+ ),
+ value: list[index],
+ subLink: subLink,
+ index: index,
+ ),
+ )
+ ],
+ data: PropertyHelper(
+ property: property,
+ value: list,
+ subLink: subLink,
+ ),
+ );
+ }
if (property.type.isList && value != null) {
final list = value as List<dynamic>;
@@ -304,6 +359,7 @@ class _TableBlockState extends State<TableBlock> {
data: value as Map<String, dynamic>,
prefixKey: '${link.name}_',
subLink: true,
+ embeddedObjects: link.target.objects,
),
);
}
@@ -321,6 +377,7 @@ class _TableBlockState extends State<TableBlock> {
data: list[index] as Map<String, dynamic>,
prefixKey: '${link.name}_${index}_',
subLink: true,
+ embeddedObjects: link.target.objects,
),
data: LinkHelper(
link: link,
@@ -745,6 +802,18 @@ class _TableItemState extends State<TableItem> {
color = _boolColor;
break;
+ case IsarType.dateTime:
+ value =
+ DateTime.fromMicrosecondsSinceEpoch(widget.data.value as int)
+ .toIso8601String();
+ color = _dateColor;
+ break;
+
+ case IsarType.object:
+ value = prop.target!;
+ color = _disableColor;
+ break;
+
case IsarType.byte:
case IsarType.int:
case IsarType.float:
@@ -766,7 +835,17 @@ class _TableItemState extends State<TableItem> {
case IsarType.doubleList:
case IsarType.stringList:
case IsarType.boolList:
- value = '${prop.type.name} [';
+ case IsarType.dateTimeList:
+ value = 'List<${prop.type.scalarType.name[0].toUpperCase()}'
+ '${prop.type.scalarType.name.substring(1)}> [';
+ value += widget.data.value == null
+ ? 'null]'
+ : '${(widget.data.value as List).length.toString()}]';
+ color = _disableColor;
+ break;
+
+ case IsarType.objectList:
+ value = 'List<${prop.target}> [';
value += widget.data.value == null
? 'null]'
: '${(widget.data.value as List).length.toString()}]';

MODIFY
packages/isar_inspector/lib/schema.dart
packages/isar_inspector/lib/schema.dart
@@ -10,6 +10,7 @@ class ICollection {
required this.idName,
required this.properties,
required this.links,
+ required this.objects,
});
factory ICollection.fromJson(
@@ -40,6 +41,9 @@ class ICollection {
links: (json['links'] as List<dynamic>).map((e) {
return ILink.fromJson(e as Map<String, dynamic>, schema);
}).toList(),
+ objects: (json['objects'] as List<dynamic>).map((e) {
+ return IObject.fromJson(e as Map<String, dynamic>);
+ }).toList(),
);
}
@@ -47,6 +51,7 @@ class ICollection {
final String idName;
final List<IProperty> properties;
final List<ILink> links;
+ final List<IObject> objects;
QueryBuilderUIGroupHelper? uiFilter;
SortProperty? uiSort;
@@ -61,14 +66,19 @@ class IProperty {
const IProperty({
required this.name,
required this.type,
+ this.target,
this.isIndex = false,
this.isId = false,
});
- factory IProperty.fromJson(Map<String, dynamic> json, Set<String> indexes) {
+ factory IProperty.fromJson(
+ Map<String, dynamic> json, [
+ Set<String> indexes = const {}
+ ]) {
return IProperty(
name: json['name'] as String,
type: IsarType.values.firstWhere((e) => e.schemaName == json['type']),
+ target: json['target'] as String?,
isId: json['isId'] as bool? ?? false,
isIndex: indexes.contains(json['name']),
);
@@ -76,6 +86,9 @@ class IProperty {
final String name;
final IsarType type;
+
+ /// Embedded Target
+ final String? target;
final bool isId;
final bool isIndex;
@@ -119,11 +132,31 @@ class ILink {
final ILinkCollection target;
}
+class IObject {
+ const IObject({
+ required this.name,
+ required this.properties,
+ });
+
+ factory IObject.fromJson(Map<String, dynamic> json) {
+ return IObject(
+ name: json['name'] as String,
+ properties: (json['properties'] as List<dynamic>)
+ .map((e) => IProperty.fromJson(e as Map<String, dynamic>))
+ .toList(),
+ );
+ }
+
+ final String name;
+ final List<IProperty> properties;
+}
+
class ILinkCollection {
ILinkCollection({
required this.name,
required this.idName,
required this.properties,
+ required this.objects,
});
factory ILinkCollection.fromJson(Map<String, dynamic> json) {
@@ -148,12 +181,16 @@ class ILinkCollection {
properties: (json['properties'] as List<dynamic>)
.map((e) => IProperty.fromJson(e as Map<String, dynamic>, indexes))
.toList(),
+ objects: (json['objects'] as List<dynamic>).map((e) {
+ return IObject.fromJson(e as Map<String, dynamic>);
+ }).toList(),
);
}
final String name;
final String idName;
final List<IProperty> properties;
+ final List<IObject> objects;
late final List<IProperty> allProperties = [
IProperty(name: idName, type: IsarType.long, isId: true),
@@ -161,9 +198,7 @@ class ILinkCollection {
];
}
-// ignore_for_file: constant_identifier_names
extension IsarTypeNum on IsarType {
-
bool get isNum {
//ignore: missing_enum_constant_in_switch
switch (this) {

MODIFY
packages/isar_inspector/lib/state/isar_connect_state_notifier.dart
packages/isar_inspector/lib/state/isar_connect_state_notifier.dart
@@ -132,8 +132,6 @@ class IsarConnectStateNotifier
ref.refresh(queryResultsPod);
}
- Future<int> getVersion() => _call(ConnectAction.getVersion);
-
Future<List<dynamic>> getSchema() => _call(ConnectAction.getSchema);
Future<List<String>> listInstances() async {

MODIFY
packages/isar_inspector/lib/state/query_state.dart
packages/isar_inspector/lib/state/query_state.dart
@@ -25,10 +25,12 @@ class QueryResult {
QueryResult({
required this.objects,
required this.count,
+ required this.collectionName,
});
final List<QueryObject> objects;
final int count;
+ final String collectionName;
}
final queryResultsPod = FutureProvider<QueryResult>((ref) async {
@@ -59,5 +61,6 @@ final queryResultsPod = FutureProvider<QueryResult>((ref) async {
return QueryResult(
objects: objects,
count: result['count']! as int,
+ collectionName: selectedCollection.name,
);
});

added embedded objects

changed date presentation