How do I create an artifact with Multi-Value field type? - rally

I'm trying to programatically create a User Story in Rally with pyral. We have some custom fields set up, e.g Client Name, which is a Drop-Down List (Multi-Value), for regular fields I'm able to provide the value as {key: value pairs} (e.g {"Priority": "High"}). How do I work with Multi-Value fields?
When I pass string I get "Error 421 Client Name cannot be null", when I pass an array, it doesn't work either.
c_ClientName: {
_rallyAPIMajor: "2",
_rallyAPIMinor: "0",
_ref: "https://rally1.rallydev.com/slm/webservice/v2.0/HierarchicalRequirement/331721021908/c_ClientName",
_type: "AllowedAttributeValue",
_tagsNameArray: [
{
Name: "Client one",
_ref: "/allowedattributevalue/1234567"
},
{
Name: "Client two",
_ref: "/allowedattributevalue/1234568"
},
{
Name: "Client three",
_ref: "/allowedattributevalue/1234569"
}
],
Count: 3
}
This is what a typical read of existing User stories look like.

Related

JSON SCHEMA Adding dependant element with optional property

I have a JSON SCHEMA problem related to dependant elements.
Here is an basic example of elements who depends on "droplist", if you choose "Option1", both "example1" and "example2" are activated. If you choose "Option2", only "example2" is activated.
{
"type": "object",
"properties": {
"droplist": {
"title": "Choose one",
"type": "string",
"enum": [
"Option1",
"Option2"
]
},
"example1": {
"title": "Example field 1",
"type": "string",
"options": {
"dependencies": {
"droplist": "Option1"
}
}
},
"example2": {
"title": "Example field 2",
"type": "string",
"options": {
"dependencies": {
"droplist": ["Option1", "Option2"]
}
}
}
}
}
Well, I want to achieve the following:
Keep the dependant fields, but if I choose "Option1" and both elements "example1" and "example2" appear, I want "example2" with additional {"minLength": 3} property.
If I Choose "Option2", I expect the original element "example2" WITHOUT minLength property.
Is this possible? Adding an extra property to a dependant element.
Summing up, I want element "example2" to appear with or without a property (minLength in this case), like a dynamic one.
Thanks guys.
You can do this by splitting off your definitions to a place where they can be reused -- this is under definitions in versions up to draft7, and $defs thereafter. You are using the dependencies keyword, which was split into dependentSchemas and dependentRequired in draft2019-09, so I assume you are using draft7 (or earlier).
definitions:
option1:
...
option2_without_minLength:
...
option2:
allOf:
- $ref: '#/definitions/option2_without_minLength'
- minLength: 3
properties:
...
... things using $ref: '#/definitions/option1' etc

Indexes: Search by Boolean?

I'm having some trouble with FaunaDB Indexes. FQL is quite powerful but the docs seem to be limited (for now) to only a few examples/use cases. (Searching by String)
I have a collection of Orders, with a few fields: status, id, client, material and date.
My goal is to search/filter for orders depending on their Status, OPEN OR CLOSED (Boolean true/false).
Here is the Index I created:
CreateIndex({
name: "orders_all_by_open_asc",
unique: false,
serialized: true,
source: Collection("orders"),
terms: [{ field: ["data", "status"] }],
values: [
{ field: ["data", "unique_id"] },
{ field: ["data", "client"] },
{ field: ["data", "material"] },
{ field: ["data", "date"] }
]
}
So with this Index, I want to specify either TRUE or FALSE and get all corresponding orders, including their data (fields).
I'm having two problems:
When I pass TRUE OR FALSE using the Javascript Driver, nothing is returned :( Is it possible to search by Booleans at all, or only by String/Number?
Here is my Query (in FQL, using the Shell):
Match(Index("orders_all_by_open_asc"), true)
And unfortunately, nothing is returned. I'm probably doing this wrong.
Second (slightly unrelated) question. When I create an Index and specify a bunch of Values, it seems the data returned is in Array format, with only the values, not the Fields. An example:
[
1001,
"client1",
"concrete",
"2021-04-13T00:00:00.000Z",
],
[
1002,
"client2",
"wood",
"2021-04-13T00:00:00.000Z",
]
This format is bad for me, because my front-end expects receiving an Object with the Fields as a key and the Values as properties. Example:
data:
{
unique_id : 1001,
client : "client1",
material : "concrete",
date: "2021-04-13T00:00:00.000Z"
},
{
unique_id : 1002,
client : "client2",
material : "wood",
date: "2021-04-13T00:00:00.000Z"
},
etc..
Is there any way to get the Field as well as the Value when using Index values, or will it always return an Array (and not an object)?
Could I use a Lambda or something for this?
I do have another Query that uses Map and Lambda to good effect, and returns the entire document, including the Ref and Data fields:
Map(
Paginate(
Match(Index("orders_by_date"), date),
),
Lambda('item', Get(Var('item')))
)
This works very nicely but unfortunately, it also performs one Get request per Document returned and that seems very inefficient.
This new Index I'm wanting to build, to filter by Order Status, will be used to return hundreds of Orders, hundreds of times a day. So I'm trying to keep it as efficient as possible, but if it can only return an Array it won't be useful.
Thanks in advance!! Indexes are great but hard to grasp, so any insight will be appreciated.
You didn't show us exactly what you have done, so here's an example that shows that filtering on boolean values does work using the index you created as-is:
> CreateCollection({ name: "orders" })
{
ref: Collection("orders"),
ts: 1618350087320000,
history_days: 30,
name: 'orders'
}
> Create(Collection("orders"), { data: {
unique_id: 1,
client: "me",
material: "stone",
date: Now(),
status: true
}})
{
ref: Ref(Collection("orders"), "295794155241603584"),
ts: 1618350138800000,
data: {
unique_id: 1,
client: 'me',
material: 'stone',
date: Time("2021-04-13T21:42:18.784Z"),
status: true
}
}
> Create(Collection("orders"), { data: {
unique_id: 2,
client: "you",
material: "muslin",
date: Now(),
status: false
}})
{
ref: Ref(Collection("orders"), "295794180038328832"),
ts: 1618350162440000,
data: {
unique_id: 2,
client: 'you',
material: 'muslin',
date: Time("2021-04-13T21:42:42.437Z"),
status: false
}
}
> CreateIndex({
name: "orders_all_by_open_asc",
unique: false,
serialized: true,
source: Collection("orders"),
terms: [{ field: ["data", "status"] }],
values: [
{ field: ["data", "unique_id"] },
{ field: ["data", "client"] },
{ field: ["data", "material"] },
{ field: ["data", "date"] }
]
})
{
ref: Index("orders_all_by_open_asc"),
ts: 1618350185940000,
active: true,
serialized: true,
name: 'orders_all_by_open_asc',
unique: false,
source: Collection("orders"),
terms: [ { field: [ 'data', 'status' ] } ],
values: [
{ field: [ 'data', 'unique_id' ] },
{ field: [ 'data', 'client' ] },
{ field: [ 'data', 'material' ] },
{ field: [ 'data', 'date' ] }
],
partitions: 1
}
> Paginate(Match(Index("orders_all_by_open_asc"), true))
{ data: [ [ 1, 'me', 'stone', Time("2021-04-13T21:42:18.784Z") ] ] }
> Paginate(Match(Index("orders_all_by_open_asc"), false))
{ data: [ [ 2, 'you', 'muslin', Time("2021-04-13T21:42:42.437Z") ] ] }
It's a little more work, but you can compose whatever return format that you like:
> Map(
Paginate(Match(Index("orders_all_by_open_asc"), false)),
Lambda(
["unique_id", "client", "material", "date"],
{
unique_id: Var("unique_id"),
client: Var("client"),
material: Var("material"),
date: Var("date"),
}
)
)
{
data: [
{
unique_id: 2,
client: 'you',
material: 'muslin',
date: Time("2021-04-13T21:42:42.437Z")
}
]
}
It's still an array of results, but each result is now an object with the appropriate field names.
Not too familiar with FQL, but I am somewhat familiar with SQL languages. Essentially, database languages usually treat all of your values as strings until they don't need to anymore. Instead, your query should use the string definition that FQL is expecting. I believe it should be OPEN or CLOSED in your case. You can simply have an if statement in java to determine whether to search for "OPEN" or "CLOSED".
To answer your second question, I don't know for FQL, but if that is what is returned, then your approach with a lamda seems to be fine. Not much else you can do about it from your end other than hope that you get a different way to get entries in API form somewhere in the future. At the end of the day, an O(n) operation in this context is not too bad, and only having to return a hundred or so orders shouldn't be the most painful thing in the world.
If you are truly worried about this, you can break up the request into portions, so you return only the first 100, then when frontend wants the next set, you send the next 100. You can cache the results too to make it very fast from the front-end perspective.
Another suggestion, maybe I am wrong and failed at searching the docs, but I will post anyway just in case it's helpful.
My index was failing to return objects, example data here is the client field:
"data": {
"status": "LIVRAISON",
"open": true,
"unique_id": 1001,
"client": {
"name": "TEST1",
"contact_name": "Bob",
"email": "bob#client.com",
"phone": "555-555-5555"
Here, the client field returned as null even though it was specified in the Index.
From reading the docs, here: https://docs.fauna.com/fauna/current/api/fql/indexes?lang=javascript#value
In the Value Objects section, I was able to understand that for Objects, the Index Field must be defined as an Array, one for each Object key. Example for my data:
{ field: ['data', 'client', 'name'] },
{ field: ['data', 'client', 'contact_name'] },
{ field: ['data', 'client', 'email'] },
{ field: ['data', 'client', 'phone'] },
This was slightly confusing, because my beginner brain expected that defining the 'client' field would simply return the entire object, like so:
{ field: ['data', 'client'] },
The only part about this in the docs was this sentence: The field ["data", "address", "street"] refers to the street field contained in an address object within the document’s data object.
This is enough information, but maybe it would deserve its own section, with a longer example? Of course the simple sentence works, but with a sub-section called 'Adding Objects to Fields' or something, this would make it extra-clear.
Hoping my moments of confusion will help out. Loving FaunaDB so far, keep up the great work :)

How do I access an asset's URL when linked via reference in Sanity Studio?

I want to upload PDFs in Sanity Studio, then link to those PDFs in the main site content.
I've added a reference to a document which has a 'file' field in it to my simpleBlockContent input in Sanity Studio.
I've created a document schema for the PDF:
export default {
title: "PDF Upload",
name: "pdfDocument",
type: "document",
fields: [
{
name: "title",
type: "string",
title: "Title",
description: "This title will be used as a caption for the download.",
},
{
name: "pdfFile",
type: "file",
title: "PDF File",
options: {
accept: ".pdf",
},
validation: (Rule) => Rule.required(),
description: "Note that the file name will be visible to end users downloading the file.",
},
],
};
And I'm attempting to reference it in my input component's schema:
export default {
title: "Simple Block Content",
name: "simpleBlockContent",
type: "array",
of: [
{
title: "Block",
type: "block",
styles: [],
marks: {
annotations: [
{
name: "pdfLink",
type: "object",
title: "PDF download link",
fields: [
{
name: "pdfReference",
type: "reference",
title: "PDF Document",
to: [{ type: "pdfDocument" }],
},
],
},
],
},
},
],
};
However when I add pdfLink to my serializers.js in the frontend, nothing resembling a link to the file is present in the data passed to it from my _rawContent graphql query that handles all other page content.
How can I access the information needed to build a URL that links to the uploaded asset?
I've yet to do this in a serializer, but it looks as though the asset URL should be accessible in the returned document, according to the docs:
Example of returned asset document:
{
"_id": "image-abc123_0G0Pkg3JLakKCLrF1podAdE9-538x538-jpg",
"_type": "sanity.imageAsset", // type is prefixed by sanity schema
"assetId": "0G0Pkg3JLakKCLrF1podAdE9",
"path": "images/myproject/mydataset/abc123_0G0Pkg3JLakKCLrF1podAdE9-538x538.jpg",
"url": "https://cdn.sanity.io/images/myproject/mydataset/abc123_0G0Pkg3JLakKCLrF1podAdE9-538x538.jpg",
"originalFilename": "bicycle.jpg",
"size": 2097152, // File size, in bytes
"metadata": {
"dimensions": {
"height": 538,
"width": 538,
"aspectRatio": 1.0
},
"location":{ // only present if the original image contained location metadata
"lat": 59.9241370,
"lon": 10.7583846,
"alt": 21.0
}
}
}
I was looking for a way to get instant link in sanity studio when someone upload file in sanity and couldn't find any good solution so I came up with my own
Problem
let people upload files to sanity and get instant link that they can copy and paste in blog, case study etc
Solution
use slug as in option you have acces to doc where you can generate link my code
import { tryGetFile } from '#sanity/asset-utils'; // this function creates production link
const pdfUploader = {
name: 'pdfUploader',
title: 'Upload PDF and Get Link',
type: 'document',
preview: {
select: {
title: 'title',
},
},
fields: [
{
name: 'title',
title: 'Title',
description: 'Name displayed on pdf list',
type: 'string',
validation: (Rule) => [Rule.required()],
},
{
name: 'pdfFile',
title: 'Upload PDF File',
description: 'PDF File you want to upload, once you upload click generate URL',
type: 'file',
validation: (Rule) => [Rule.required()],
},
{
name: 'generatedPDFURL',
title: 'Generate URL Link to this pdf',
description:
'Click GENERATE to get Link to pdf file, if you by mistake change it, click generate again. Then Copy link below and paste it anywhere you want',
type: 'slug',
options: {
// this source takes all data that is currently in this document and pass it as argument
// then tryGetFile() - getting file from sanity with all atributes like url, original name etc
source: ({ pdfFile }) => {
if (!pdfFile) return 'Missing PDF File';
const { asset } = tryGetFile(pdfFile?.asset?._ref, {
// put your own envs
dataset: process.env.SANITY_DATASET,
projectId: process.env.SANITY_PROJECT_ID,
});
return asset?.url;
},
// this slugify prevent from changing "/" to "-" it keeps the original link and prevent from slugifying
slugify: (link) => link,
},
validation: (Rule) => [Rule.required()],
},
],
};
export default pdfUploader;
After this in sanity upload file and then click GENERATE to get link
Hope it helps people who are looking for similar solution, slug is not perfect choice but it's working :)

VueJS is copying data from previous JSON node on push()

I'm facing a weird issue on VueJS.
The API give me a JSON like this:
{
movies: [
{
name: "Name 2",
cover: "cover_image.jpg",
chars: [
{
name: "Character 1",
picture: "picture.jpg"
},
{
name: "Character 2",
picture: "picture.jpg"
}
]
},
{
name: "Name 1",
cover: "cover_image.jpg",
chars: [
{
name: "Character N",
picture: "picture.jpg"
},
{
name: "Character Z",
picture: "picture.jpg"
}
]
}
]
}
I'm using this JSON to populate a few boxes on screen. Note that each node has a sub-node.
All working so far.
When I push() a new object into the JSON, the new box appears correctly on page but it's copying the sub-node of previous node. So the Movie 3 is displaying its correct main infos (name and cover) but is copying the characters of Movie 2.
When I refresh the page it's all fine.
Testing API through Postman it's fine as well.
Maybe it could be some cache of VueJS?
I'm using components to display each box.
Thank you!

ExtJS bidirectional complex data binding Form

give a JSON data like this
{ name: { firstname: 'First Name', lastname: 'Last Name' } }
I can model use model mapping
fields: [
{Name: 'firstname', mapping: 'name.firstname'},
{Name: 'lastname', mapping: 'name.lastname'}
]
It allow us to load the data into form like this
First Name: [ First Name ]
Last Name: [ Last Name ]
However when we submit the form Ext serialize the content as
{ "firstname": "New first name", "lastname": "New last name"}
// instead of
{ "name": { "firstname": "...", "lastname": "..."} }
Is there anyway I can tell Ext to serialize the object back to the nest form, regards.
P.S: my Edit.js taking from Ext MVC application guide http://docs.sencha.com/extjs/4.2.2/#!/guide/application_architecture
You need to configure two properties in your json writer. You need to set nameProperty: 'mapping', and expandData: true. For example, if you are configuring this writer in the proxy in your model, it would look like this:
proxy: {
// other proxy config...
writer: {
type: 'json',
nameProperty: 'mapping',
expandData: true
}
}
nameProperty determines where the property name for each field comes from: either the name property or the mapping property. So, using your example, this will produce an object like this:
{ 'name.firstname': 'New first name', 'name.lastname': 'New last name' }
This is quite what you want yet, and that is where expandData comes in. This tells it to expand those dot-delimited properties in the example above, and create nested objects.
{ 'name': { 'firstname': 'New first name', 'lastname': 'New last name' } }
Docs:
nameProperty
expandData