Closed zamar3 closed 2 years ago
Hi @zamar3. Thanks for reporting this and sharing some of this initial context. Would it be possible for you to share with us a minimal set of model schemas in which this behavior is reproducible? Without knowing more about your use case, I think it will be really difficult to replicate on our end with more-or-less "happy-case" models.
One of the things that jumps out at me is perhaps somehow different authorization between the app and the admin console - it may also be helpful if you could share with us the basic structure of your amplifyconfiguration.dart
(with your account details scrubbed out)
When I try to query with same parameters on the Amplify Admin console, I get all results. I have also tried to access data through datastore and it comes out fine
When you say this, do you mean that from a new project, using DataStore seems to give you back the desired results or from the same project?
/*
* Copyright 2021 Amazon.com, Inc. or its affiliates. All Rights Reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License").
* You may not use this file except in compliance with the License.
* A copy of the License is located at
*
* http://aws.amazon.com/apache2.0
*
* or in the "license" file accompanying this file. This file is distributed
* on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
* express or implied. See the License for the specific language governing
* permissions and limitations under the License.
*/
// NOTE: This file is generated and may not follow lint rules defined in your app
// Generated files can be excluded from analysis in analysis_options.yaml
// For more info, see: https://dart.dev/guides/language/analysis-options#excluding-code-from-analysis
// ignore_for_file: public_member_api_docs, file_names, unnecessary_new, prefer_if_null_operators, prefer_const_constructors, slash_for_doc_comments, annotate_overrides, non_constant_identifier_names, unnecessary_string_interpolations, prefer_adjacent_string_concatenation, unnecessary_const, dead_code
import 'package:amplify_core/amplify_core.dart';
import 'package:collection/collection.dart';
import 'package:flutter/foundation.dart';
/** This is an auto generated class representing the IndividualRecipee type in your schema. */
@immutable
class IndividualRecipee extends Model {
static const classType = const _IndividualRecipeeModelType();
final String id;
final String? _mealTemplateIDNumber;
final String? _weekNo;
final String? _dayNo;
final String? _mealType;
final String? _qty;
final String? _measure;
final String? _description;
final String? _proteins;
final String? _carbs;
final String? _fat;
final String? _calories;
final List<String>? _ingredients;
final String? _ingredientsFCDID;
final String? _category;
final String? _type;
final String? _foodTemplateID;
final TemporalDateTime? _createdAt;
final TemporalDateTime? _updatedAt;
@override
getInstanceType() => classType;
@override
String getId() {
return id;
}
String? get mealTemplateIDNumber {
return _mealTemplateIDNumber;
}
String? get weekNo {
return _weekNo;
}
String? get dayNo {
return _dayNo;
}
String? get mealType {
return _mealType;
}
String? get qty {
return _qty;
}
String? get measure {
return _measure;
}
String? get description {
return _description;
}
String? get proteins {
return _proteins;
}
String? get carbs {
return _carbs;
}
String? get fat {
return _fat;
}
String? get calories {
return _calories;
}
List<String>? get ingredients {
return _ingredients;
}
String? get ingredientsFCDID {
return _ingredientsFCDID;
}
String? get category {
return _category;
}
String? get type {
return _type;
}
String? get foodTemplateID {
return _foodTemplateID;
}
TemporalDateTime? get createdAt {
return _createdAt;
}
TemporalDateTime? get updatedAt {
return _updatedAt;
}
const IndividualRecipee._internal({required this.id, mealTemplateIDNumber, weekNo, dayNo, mealType, qty, measure, description, proteins, carbs, fat, calories, ingredients, ingredientsFCDID, category, type, foodTemplateID, createdAt, updatedAt}): _mealTemplateIDNumber = mealTemplateIDNumber, _weekNo = weekNo, _dayNo = dayNo, _mealType = mealType, _qty = qty, _measure = measure, _description = description, _proteins = proteins, _carbs = carbs, _fat = fat, _calories = calories, _ingredients = ingredients, _ingredientsFCDID = ingredientsFCDID, _category = category, _type = type, _foodTemplateID = foodTemplateID, _createdAt = createdAt, _updatedAt = updatedAt;
factory IndividualRecipee({String? id, String? mealTemplateIDNumber, String? weekNo, String? dayNo, String? mealType, String? qty, String? measure, String? description, String? proteins, String? carbs, String? fat, String? calories, List<String>? ingredients, String? ingredientsFCDID, String? category, String? type, String? foodTemplateID}) {
return IndividualRecipee._internal(
id: id == null ? UUID.getUUID() : id,
mealTemplateIDNumber: mealTemplateIDNumber,
weekNo: weekNo,
dayNo: dayNo,
mealType: mealType,
qty: qty,
measure: measure,
description: description,
proteins: proteins,
carbs: carbs,
fat: fat,
calories: calories,
ingredients: ingredients != null ? List<String>.unmodifiable(ingredients) : ingredients,
ingredientsFCDID: ingredientsFCDID,
category: category,
type: type,
foodTemplateID: foodTemplateID);
}
bool equals(Object other) {
return this == other;
}
@override
bool operator ==(Object other) {
if (identical(other, this)) return true;
return other is IndividualRecipee &&
id == other.id &&
_mealTemplateIDNumber == other._mealTemplateIDNumber &&
_weekNo == other._weekNo &&
_dayNo == other._dayNo &&
_mealType == other._mealType &&
_qty == other._qty &&
_measure == other._measure &&
_description == other._description &&
_proteins == other._proteins &&
_carbs == other._carbs &&
_fat == other._fat &&
_calories == other._calories &&
DeepCollectionEquality().equals(_ingredients, other._ingredients) &&
_ingredientsFCDID == other._ingredientsFCDID &&
_category == other._category &&
_type == other._type &&
_foodTemplateID == other._foodTemplateID;
}
@override
int get hashCode => toString().hashCode;
@override
String toString() {
var buffer = new StringBuffer();
buffer.write("IndividualRecipee {");
buffer.write("id=" + "$id" + ", ");
buffer.write("mealTemplateIDNumber=" + "$_mealTemplateIDNumber" + ", ");
buffer.write("weekNo=" + "$_weekNo" + ", ");
buffer.write("dayNo=" + "$_dayNo" + ", ");
buffer.write("mealType=" + "$_mealType" + ", ");
buffer.write("qty=" + "$_qty" + ", ");
buffer.write("measure=" + "$_measure" + ", ");
buffer.write("description=" + "$_description" + ", ");
buffer.write("proteins=" + "$_proteins" + ", ");
buffer.write("carbs=" + "$_carbs" + ", ");
buffer.write("fat=" + "$_fat" + ", ");
buffer.write("calories=" + "$_calories" + ", ");
buffer.write("ingredients=" + (_ingredients != null ? _ingredients!.toString() : "null") + ", ");
buffer.write("ingredientsFCDID=" + "$_ingredientsFCDID" + ", ");
buffer.write("category=" + "$_category" + ", ");
buffer.write("type=" + "$_type" + ", ");
buffer.write("foodTemplateID=" + "$_foodTemplateID" + ", ");
buffer.write("createdAt=" + (_createdAt != null ? _createdAt!.format() : "null") + ", ");
buffer.write("updatedAt=" + (_updatedAt != null ? _updatedAt!.format() : "null"));
buffer.write("}");
return buffer.toString();
}
IndividualRecipee copyWith({String? id, String? mealTemplateIDNumber, String? weekNo, String? dayNo, String? mealType, String? qty, String? measure, String? description, String? proteins, String? carbs, String? fat, String? calories, List<String>? ingredients, String? ingredientsFCDID, String? category, String? type, String? foodTemplateID}) {
return IndividualRecipee._internal(
id: id ?? this.id,
mealTemplateIDNumber: mealTemplateIDNumber ?? this.mealTemplateIDNumber,
weekNo: weekNo ?? this.weekNo,
dayNo: dayNo ?? this.dayNo,
mealType: mealType ?? this.mealType,
qty: qty ?? this.qty,
measure: measure ?? this.measure,
description: description ?? this.description,
proteins: proteins ?? this.proteins,
carbs: carbs ?? this.carbs,
fat: fat ?? this.fat,
calories: calories ?? this.calories,
ingredients: ingredients ?? this.ingredients,
ingredientsFCDID: ingredientsFCDID ?? this.ingredientsFCDID,
category: category ?? this.category,
type: type ?? this.type,
foodTemplateID: foodTemplateID ?? this.foodTemplateID);
}
IndividualRecipee.fromJson(Map<String, dynamic> json)
: id = json['id'],
_mealTemplateIDNumber = json['mealTemplateIDNumber'],
_weekNo = json['weekNo'],
_dayNo = json['dayNo'],
_mealType = json['mealType'],
_qty = json['qty'],
_measure = json['measure'],
_description = json['description'],
_proteins = json['proteins'],
_carbs = json['carbs'],
_fat = json['fat'],
_calories = json['calories'],
_ingredients = json['ingredients']?.cast<String>(),
_ingredientsFCDID = json['ingredientsFCDID'],
_category = json['category'],
_type = json['type'],
_foodTemplateID = json['foodTemplateID'],
_createdAt = json['createdAt'] != null ? TemporalDateTime.fromString(json['createdAt']) : null,
_updatedAt = json['updatedAt'] != null ? TemporalDateTime.fromString(json['updatedAt']) : null;
Map<String, dynamic> toJson() => {
'id': id, 'mealTemplateIDNumber': _mealTemplateIDNumber, 'weekNo': _weekNo, 'dayNo': _dayNo, 'mealType': _mealType, 'qty': _qty, 'measure': _measure, 'description': _description, 'proteins': _proteins, 'carbs': _carbs, 'fat': _fat, 'calories': _calories, 'ingredients': _ingredients, 'ingredientsFCDID': _ingredientsFCDID, 'category': _category, 'type': _type, 'foodTemplateID': _foodTemplateID, 'createdAt': _createdAt?.format(), 'updatedAt': _updatedAt?.format()
};
static final QueryField ID = QueryField(fieldName: "individualRecipee.id");
static final QueryField MEALTEMPLATEIDNUMBER = QueryField(fieldName: "mealTemplateIDNumber");
static final QueryField WEEKNO = QueryField(fieldName: "weekNo");
static final QueryField DAYNO = QueryField(fieldName: "dayNo");
static final QueryField MEALTYPE = QueryField(fieldName: "mealType");
static final QueryField QTY = QueryField(fieldName: "qty");
static final QueryField MEASURE = QueryField(fieldName: "measure");
static final QueryField DESCRIPTION = QueryField(fieldName: "description");
static final QueryField PROTEINS = QueryField(fieldName: "proteins");
static final QueryField CARBS = QueryField(fieldName: "carbs");
static final QueryField FAT = QueryField(fieldName: "fat");
static final QueryField CALORIES = QueryField(fieldName: "calories");
static final QueryField INGREDIENTS = QueryField(fieldName: "ingredients");
static final QueryField INGREDIENTSFCDID = QueryField(fieldName: "ingredientsFCDID");
static final QueryField CATEGORY = QueryField(fieldName: "category");
static final QueryField TYPE = QueryField(fieldName: "type");
static final QueryField FOODTEMPLATEID = QueryField(fieldName: "foodTemplateID");
static var schema = Model.defineSchema(define: (ModelSchemaDefinition modelSchemaDefinition) {
modelSchemaDefinition.name = "IndividualRecipee";
modelSchemaDefinition.pluralName = "IndividualRecipees";
modelSchemaDefinition.authRules = [
AuthRule(
authStrategy: AuthStrategy.PUBLIC,
operations: [
ModelOperation.CREATE,
ModelOperation.UPDATE,
ModelOperation.DELETE,
ModelOperation.READ
])
];
modelSchemaDefinition.addField(ModelFieldDefinition.id());
modelSchemaDefinition.addField(ModelFieldDefinition.field(
key: IndividualRecipee.MEALTEMPLATEIDNUMBER,
isRequired: false,
ofType: ModelFieldType(ModelFieldTypeEnum.string)
));
modelSchemaDefinition.addField(ModelFieldDefinition.field(
key: IndividualRecipee.WEEKNO,
isRequired: false,
ofType: ModelFieldType(ModelFieldTypeEnum.string)
));
modelSchemaDefinition.addField(ModelFieldDefinition.field(
key: IndividualRecipee.DAYNO,
isRequired: false,
ofType: ModelFieldType(ModelFieldTypeEnum.string)
));
modelSchemaDefinition.addField(ModelFieldDefinition.field(
key: IndividualRecipee.MEALTYPE,
isRequired: false,
ofType: ModelFieldType(ModelFieldTypeEnum.string)
));
modelSchemaDefinition.addField(ModelFieldDefinition.field(
key: IndividualRecipee.QTY,
isRequired: false,
ofType: ModelFieldType(ModelFieldTypeEnum.string)
));
modelSchemaDefinition.addField(ModelFieldDefinition.field(
key: IndividualRecipee.MEASURE,
isRequired: false,
ofType: ModelFieldType(ModelFieldTypeEnum.string)
));
modelSchemaDefinition.addField(ModelFieldDefinition.field(
key: IndividualRecipee.DESCRIPTION,
isRequired: false,
ofType: ModelFieldType(ModelFieldTypeEnum.string)
));
modelSchemaDefinition.addField(ModelFieldDefinition.field(
key: IndividualRecipee.PROTEINS,
isRequired: false,
ofType: ModelFieldType(ModelFieldTypeEnum.string)
));
modelSchemaDefinition.addField(ModelFieldDefinition.field(
key: IndividualRecipee.CARBS,
isRequired: false,
ofType: ModelFieldType(ModelFieldTypeEnum.string)
));
modelSchemaDefinition.addField(ModelFieldDefinition.field(
key: IndividualRecipee.FAT,
isRequired: false,
ofType: ModelFieldType(ModelFieldTypeEnum.string)
));
modelSchemaDefinition.addField(ModelFieldDefinition.field(
key: IndividualRecipee.CALORIES,
isRequired: false,
ofType: ModelFieldType(ModelFieldTypeEnum.string)
));
modelSchemaDefinition.addField(ModelFieldDefinition.field(
key: IndividualRecipee.INGREDIENTS,
isRequired: false,
isArray: true,
ofType: ModelFieldType(ModelFieldTypeEnum.collection, ofModelName: describeEnum(ModelFieldTypeEnum.string))
));
modelSchemaDefinition.addField(ModelFieldDefinition.field(
key: IndividualRecipee.INGREDIENTSFCDID,
isRequired: false,
ofType: ModelFieldType(ModelFieldTypeEnum.string)
));
modelSchemaDefinition.addField(ModelFieldDefinition.field(
key: IndividualRecipee.CATEGORY,
isRequired: false,
ofType: ModelFieldType(ModelFieldTypeEnum.string)
));
modelSchemaDefinition.addField(ModelFieldDefinition.field(
key: IndividualRecipee.TYPE,
isRequired: false,
ofType: ModelFieldType(ModelFieldTypeEnum.string)
));
modelSchemaDefinition.addField(ModelFieldDefinition.field(
key: IndividualRecipee.FOODTEMPLATEID,
isRequired: false,
ofType: ModelFieldType(ModelFieldTypeEnum.string)
));
modelSchemaDefinition.addField(ModelFieldDefinition.nonQueryField(
fieldName: 'createdAt',
isRequired: false,
isReadOnly: true,
ofType: ModelFieldType(ModelFieldTypeEnum.dateTime)
));
modelSchemaDefinition.addField(ModelFieldDefinition.nonQueryField(
fieldName: 'updatedAt',
isRequired: false,
isReadOnly: true,
ofType: ModelFieldType(ModelFieldTypeEnum.dateTime)
));
});
}
class _IndividualRecipeeModelType extends ModelType<IndividualRecipee> {
const _IndividualRecipeeModelType();
@override
IndividualRecipee fromJson(Map<String, dynamic> jsonData) {
return IndividualRecipee.fromJson(jsonData);
}
}
Above is the affected model schema
const amplifyconfig = ''' {
"UserAgent": "aws-amplify-cli/2.0",
"Version": "1.0",
"api": {
"plugins": {
"awsAPIPlugin": {
"nuscriptionapp": {
"endpointType": "GraphQL",
"endpoint": "https://zlthcdqwfvhglc6h3ofyud4uuq.appsync-api.us-west-2.amazonaws.com/graphql",
"region": "us-west-2",
"authorizationType": "API_KEY",
"apiKey": "******************************"
}
}
}
},
"auth": {
"plugins": {
"awsCognitoAuthPlugin": {
"UserAgent": "aws-amplify-cli/0.1.0",
"Version": "0.1.0",
"IdentityManager": {
"Default": {}
},
"AppSync": {
"Default": {
"ApiUrl": "https://zlthcdqwfvhglc6h3ofyud4uuq.appsync-api.us-west-2.amazonaws.com/graphql",
"Region": "us-west-2",
"AuthMode": "API_KEY",
"ApiKey": "*******************************",
"ClientDatabasePrefix": "nuscriptionapp_API_KEY"
},
"nuscriptionapp_AWS_IAM": {
"ApiUrl": "https://zlthcdqwfvhglc6h3ofyud4uuq.appsync-api.us-west-2.amazonaws.com/graphql",
"Region": "us-west-2",
"AuthMode": "AWS_IAM",
"ClientDatabasePrefix": "nuscriptionapp_AWS_IAM"
}
},
"CredentialsProvider": {
"CognitoIdentity": {
"Default": {
"PoolId": "us-west-2:4d0dcba7-5790-4af8-b835-f02fd8b32cc0",
"Region": "us-west-2"
}
}
},
"CognitoUserPool": {
"Default": {
"PoolId": "us-west-2_wws61Epqn",
"AppClientId": "3l8ij6mn9boiqqcnh80e6bigjg",
"Region": "us-west-2"
}
},
"Auth": {
"Default": {
"authenticationFlowType": "USER_SRP_AUTH",
"loginMechanisms": [
"EMAIL"
],
"signupAttributes": [
"EMAIL"
],
"passwordProtectionSettings": {
"passwordPolicyMinLength": 8,
"passwordPolicyCharacters": []
},
"mfaConfiguration": "OFF",
"mfaTypes": [
"SMS"
],
"verificationMechanisms": [
"EMAIL"
],
"socialProviders": [],
"usernameAttributes": [
"EMAIL"
]
}
},
"S3TransferUtility": {
"Default": {
"Bucket": "nuscriptionapp7b76235532324404808193b15bb8a58d144847-staging",
"Region": "us-west-2"
}
}
}
}
},
"storage": {
"plugins": {
"awsS3StoragePlugin": {
"bucket": "nuscriptionapp7b76235532324404808193b15bb8a58d144847-staging",
"region": "us-west-2",
"defaultAccessLevel": "guest"
}
}
}
}''';
amplifyconfiguration.dart
Thanks for sharing the above @zamar3 . Could you also help me understand how you set your project up? Did you create your models by creating your GraphQL Schemas locally and then using Amplify CLI or did you create them entirely through Amplify Studio?
I appreciate you sharing the model file with me - I will try to reproduce based on this, but if you could also share a minimal GraphQL schema (based upon your existing the query that is only returning partial results, that would be of great help as well.amplify/backend/api/amplifyDatasource/schema.graphql
) that exhibits this behavior +
Edit: I was able to replicate the codegen'd model with a GraphQL schema based upon the model shared
Hi @zamar3 I was able to create a project with the model in question and add them via a sample Flutter application e.g.
IndividualRecipee recipee = IndividualRecipee(ingredients: const ['apple', 'banana']);
final request = ModelMutations.create(recipee);
final response = await Amplify.API.mutate(request: request).response;
print(response.data);
// flutter: IndividualRecipee {id=<uuid>, mealTemplateIDNumber=null, weekNo=null, dayNo=null, mealType=null, qty=null, measure=null, description=null, proteins=null, carbs=null, fat=null, calories=null, ingredients=[apple, banana], ingredientsFCDID=null, category=null, type=null, foodTemplateID=null, createdAt=2022-03-23T22:19:22.697000000Z, updatedAt=2022-03-23T22:19:22.697000000Z}
as well as list them via my sample app
final request = ModelQueries.list(IndividualRecipee.classType);
final response = await Amplify.API.query(request: request).response;
List<IndividualRecipee?>? recipees = response.data?.items;
if (recipees != null) print('Query result: ' + recipees.toString());
// flutter: Query result: [IndividualRecipee {id=87f84411-edfd-4b7b-a67b-e5ab8e00c462, mealTemplateIDNumber=null, weekNo=null, dayNo=null, mealType=null, qty=null, measure=null, description=null, proteins=null, carbs=null, fat=null, calories=null, ingredients=[blood orange], ingredientsFCDID=null, category=null, type=null, foodTemplateID=null, createdAt=2022-03-23T22:19:40.822000000Z, updatedAt=2022-03-23T22:19:40.822000000Z}, IndividualRecipee {id=8d1c5276-257e-42e0-b630-bb0866c0cae2, mealTemplateIDNumber=null, weekNo=null, dayNo=null, mealType=null, qty=null, measure=null, description=null, proteins=null, carbs=null, fat=null, calories=null, ingredients=[honeydew, gooseberry], ingredientsFCDID=null, category=null, type=null, foodTemplateID=null, createdAt=2022-03-23T22:19:11.639000000Z, updatedAt=2022-03-23T22:19:11.639000000Z}, IndividualRecipee {id=8d2f6ac0-2cbc-47d4-a0f4-db588631a62b, mealTemplateIDNumber=null, weekNo=null, dayNo=null, mealType=null, qty=null, measure=null, description=null, <…>
or through AWS AppSync:
query MyQuery {
listIndividualRecipees {
items {
id
ingredients
}
}
}
At this time, I think the straight forward path appears to be in working order so it would be helpful if you could share with me:
try {
final request = ModelQueries.list(IndividualRecipee.classType,
where: IndividualRecipee.MEALTEMPLATEIDNUMBER
.eq("c5224c80-a9ef-11ec-a382-5fff6fdaeeae"));
final response = await Amplify.API.query(request: request).response;
List<IndividualRecipee?>? foods = response.data?.items;
if (foods == null) {
print('errors: ' + response.errors.toString());
return;
}
} on ApiException catch (e) {
print('Query failed: $e');
}
Above is the code for building query. I added the data with the code below.
try {
IndividualRecipee newProviderTemplate = IndividualRecipee(
mealTemplateIDNumber: docID,
weekNo: week.toString(),
dayNo: day.toString(),
mealType: selectedMeals[meal],
);
final request = ModelMutations.create(newProviderTemplate);
final response = await Amplify.API.mutate(request: request).response;
} on ApiException catch (e) {
print('Mutation failed: $e');
}
Hmm, I tried the snippet provided for creation mutations and was able to add 40 IndividualRecipee
entries with a hardcoded mealTemplateIDNumber
as "c5224c80-a9ef-11ec-a382-5fff6fdaeeae"
IndividualRecipee newProviderTemplate = IndividualRecipee(
mealTemplateIDNumber: "c5224c80-a9ef-11ec-a382-5fff6fdaeeae",
weekNo: "",
dayNo: "",
mealType: "",
);
final request = ModelMutations.create(newProviderTemplate);
final response = await Amplify.API.mutate(request: request).response;
Then, using the snipped provided for querying, I was able to list them out with the predicate
IndividualRecipee.MEALTEMPLATEIDNUMBER.eq("c5224c80-a9ef-11ec-a382-5fff6fdaeeae")
as my where
clause.
final request = ModelQueries.list(IndividualRecipee.classType,
where: IndividualRecipee.MEALTEMPLATEIDNUMBER.eq("c5224c80-a9ef-11ec-a382-5fff6fdaeeae"));
final response = await Amplify.API.query(request: request).response;
List<IndividualRecipee?>? foods = response.data?.items;
print(foods.length); // 40
I apologize for the churn but so far, everything seems pretty straightforward and working correctly. Next thing we should check now is to figure out what is different between the listing queries you are providing here vs against the console and DataStore. Could you please provide
so that we can try to ascertain what's different? Thanks!
Hi @zamar3 - Just wanted to check in with you on this. Are you still experiencing this issue?
Going to close this issue as it was not readily reproducible with a new app created with the provided info. Please feel free to reopen this issue with new information if it persists.
Hello, So, I've been off this project for a while now and I lost access to my "zamar3" account, I want to report that I am still having this issue, I'm using the most recent version of Amplify packages
Do I need to open a new issue on this?
Description
I am accessing my database via API and I have noticed that when I query the database from my flutter app, I don't get all the desired query results. When I try to query with same parameters on the Amplify Admin console, I get all results. I have also tried to access data through datastore and it comes out fine. I only have issue when I decide to use API. There is a particular query I'm running with API that returns just 6 records but on Admin console it returns over 40 records.
Categories
Steps to Reproduce
Screenshots
No response
Platforms
Environment
Dependencies
Device
IphONE 12 mini
OS
IOS 14.4
CLI Version
7.6.21
Additional Context
No response