Having a little trouble getting started

Hey all,
I have gone through the various processes of installing Forge, created the little hello world app and added it to my test instance for JSM, all good and successful.

My ultimate goal for this is a little app for Agents to select their name, another users name a start and an end date. When they submit this info it will update Assets with the second users name in the relevant field and the two date values.

I am having trouble understanding where you import the various components for the UI Kit. Basically I need a form and 4 text components which I will use for the user and date entry, the updating Assets comes next?!

Maybe I am missing a key document, I am pretty far down the rabbit hole with open chrome tabs with Forge info.

If there is something specific about this, an example or links that would be amazing.

Thanks.

Hey Steven

I’m not sure what you have and haven’t already looked at so forgive me if I tread old ground.

We have example apps for other products which should be transferrable to the JSM context.

This example makes use of forms and entries.

Let me know if there’s any problems.

Hey Josh,

Thanks for that. All I have at the moment is an app deployed with a date picker on it.

Couldn’t find how to get more components in the code without a tonne of errors in the deploy, and haven’t even started to figure out how to update Assets with that info :smiley:

Thanks for the links, I did find that in a tab, just hadn’t look at it for some reason.

Cheers.

That’s very interesting. Importing new components from @forge/ui shouldn’t cause errors in deployment.

If you haven’t solved the problem would you mind sharing the error?

oh I am sure it is user error until I reverse engineer one of those apps in the examples.
I ‘thought’ I could put multiples of this in place just with different Name, label etc but it fails. Just need to hunt around for the right way to structure the jsx file when there are multiple components, which by the sounds of it will be in the link you sent through.

const App = () => {
  return (
    <DatePicker
      name="date"
      label="Leave Start Date"
      description="First day of your OOO period"
      onChange={(value) => console.log(value)}
    />
    
  );
};

Hi Steven,

putting multiples of your DatePicker should work. Try wrapping all of your components in an Fragment…

const App = () => {
return (
<Fragment>
  <DatePicker
  name=“date”
  label=“Leave Start Date”
  description=“First day of your OOO period”
  onChange={(value) => console.log(value)}
  />
  <DatePicker
  name=“date2”
  label=“Leave End Date”
  description=“Last day of your OOO period”
  onChange={(value) => console.log(value)}
  />
</Fragment>

);
};

In React you always need parent components when nesting multiples. If all of them should work together, maybe think about wrapping all of them in a form. https://developer.atlassian.com/platform/forge/ui-kit-components/form/

EDIT: It seems the “DatePicker” Component from the UIKit only works inside an “Form” or “MacroConfig” Component. So wrapping it in a “Fragment” won’t work.
https://developer.atlassian.com/platform/forge/ui-kit-components/form/#usage-notes-3
Example:

const App = () => {
function onSubmit(formProps) {
  console.log(formProps);
}
return (
<Form onSubmit={onSubmit}>
  <DatePicker
  name=“date”
  label=“Leave Start Date”
  description=“First day of your OOO period”
  onChange={(value) => console.log(value)}
  />
  <DatePicker
  name=“date2”
  label=“Leave End Date”
  description=“Last day of your OOO period”
  onChange={(value) => console.log(value)}
  />
</Form>

);
};

Regards
Adrian

Thanks @AdrianSomesan, I am experimenting with the UI Kit 2 at the moment as I assume by the time I wrap my head around all of this that will be the norm.
I appreciate the code snippet.
This will help me structure the collecting of the other data as well (2 x user picker and a boolean)

THEN comes the updating the record in Assets.

Good challenge for an old guy to understand all of this :slight_smile:

1 Like

Hey there,
Just spending some time with this, I just can’t make anything work other than a single date picker field. As soon as I try and add more fields to the form it all fails, when I deploy it the app is blank when clicked on.
If I revert it back to the single date picker, it is fine.

Trying to add a user picker, boolean and the two date fields is proving quite the challenge :smiley:

If the code snippet is short enough you could share it here and we can try on our machines.

1 Like

Hey all,

So going back through comments and other posts on here I have some success (as I said I am old and this is new so I am VERY happy to be this far through).

I have two date fields and a user select box appearing. I cannot figure out how to get a checkbox or something as a boolean (true / false) on the form yet but here is what I have.

import ForgeUI, { Checkbox, Form, DatePicker,render, ProjectPage, Fragment, Text, UserPicker } from '@forge/ui';

const App = () => {
    function onSubmit(formProps) {
        console.log(formProps);
      }

  return (
  <Form onSubmit={onSubmit}>
    <DatePicker
    name="date"
    label="Leave Start Date"
    description="First day of your OOO period"
    onChange={(value) => console.log(value)}
    />
    <DatePicker
    name="date2"
    label="Leave End Date"
    description="Last day of your OOO period"
    onChange={(value) => console.log(value)}
    />
    <UserPicker
    name="User"
    label="Select User"
    onChange={(value) => console.log(value)}
    />
  </Form>
  
  );
  };

So I am stuck with the whole true false toggle and then the next part is I imagine getting the results of this to an automation I guess to check if the person exists in assets and editing their object. All of which I imagine can be done with Forge easy enough (when you know how).

Thanks for all the replies.

S.

Hi Steven,

I’m glad you’re making progress. :slight_smile:
Adding a Toggle should work exactly as adding a User Picker…

import ForgeUI, { Checkbox, Form, DatePicker,render, ProjectPage, Fragment, Text, UserPicker, Toggle } from '@forge/ui';

const App = () => {
    function onSubmit(formProps) {
        console.log(formProps);
      }

  return (
  <Form onSubmit={onSubmit}>
    <DatePicker
    name="date"
    label="Leave Start Date"
    description="First day of your OOO period"
    onChange={(value) => console.log(value)}
    />
    <DatePicker
    name="date2"
    label="Leave End Date"
    description="Last day of your OOO period"
    onChange={(value) => console.log(value)}
    />
    <UserPicker
    name="User"
    label="Select User"
    onChange={(value) => console.log(value)}
    />
    <Toggle
      label="Show section"
      name="isSectionVisible"
      onChange={(value) => console.log(value)}
    />
</Form>

);
};

Regards
Adrian

1 Like

Thanks @AdrianSomesan, apologies for the delay some family issues and then I had some leave booked.

I have this info being collected ‘somewhere’ when it is entered and submitted, just not sure now how to head for updating the information into assets. I assume now I need to trigger an API call to Assets to be able to create a record if my user isn’t there or update the fields if they are there?

I normally do this sort of thing via powershell scripts and am floundering with Forge and Assets at the moment.

Hi @StevenLeesSmith
your info is being “collected” in the formProps parameter. In the “onSubmit” function from my last post, you can handle this data. To work with the Insight Assets of your JSM Instance, you can use this API: Introduction

I should mention, that at the current time, this API can’t really be used in a production context, since Atlassian is not enabling the access to this API via any other authentication but Basic Auth.

A simple example would be the AQL API Request from the documentation

const fetch = require('node-fetch');

fetch('https://api.atlassian.com/jsm/assets/workspace/{workspaceId}/v1/aql/objects', {
  method: 'GET',
  headers: {
    'Accept': 'application/json'
  }
})
  .then(response => {
    console.log(
      `Response: ${response.status} ${response.statusText}`
    );
    return response.text();
  })
  .then(text => console.log(text))
  .catch(err => console.error(err));

Instead of the “Fetch” library from Node.js you should use the fetch function from Atlassian Forge:
https://developer.atlassian.com/platform/forge/runtime-reference/fetch-api/

If you have any problems, feel free to ask.

Regards,
Adrian

1 Like

ah ok thanks for that. I have seen some market place apps that leverage Azure data and update Assets directly that way, I assume they would be using the API to do this or did I misunderstand your reply (yes I am literally running by the skin of my teeth understanding this).

I get the whole API, I have built scripts to integrate assets with multiple external systems and such (all with powershell). Just missing the mark on how this hangs together within Assets when there is data entered via an app.

Hi Steven,

I am not sure if I understood your problem: “Just missing the mark on how this hangs together within Assets when there is data entered via an app.”

If I got it right, you are not sure where the entered data is going and how to use the data inside an API call?
The data you enter in the UI, will end up in the handler function of your form.
In one of my previous posts, I added a code snippet of a form with a “onSubmit” function. Inside this “onSubmit” function, the parameter “formProps” carries the entered data. If you are working inside the “Backend”(UI Kit) you can save this data via the storage api: https://developer.atlassian.com/platform/forge/runtime-reference/storage-api/
or handle it directly…
If you are using CustomUI or UI Kit 2 you can either transmit the data to the “Backend”(UI Kit) via Invocation: https://developer.atlassian.com/platform/forge/custom-ui-bridge/invoke/
or also handle it directly…

Regards,
Adrian

Thanks for the additional info, I will go back and keep working through this… I will get this to work :smiley:

hmm ok just wanting to make sure I can do what I am hoping as I am going around in a pretty big circle with links at the moment.

With this collected data, once I know how to work with it (I can see it just logs it to the console in the function, is there a way to just write this to a simple object type in assets?

The user, start and end time and the value of the toggle?

Not sure what to do about an existing record and such but unclear if I am actually trying to achieve something that is reasonable.

Well here is the mess I have ended up in and it doesn’t work :smiley:

import ForgeUI, { Form, DatePicker, UserPicker, Toggle, render, QueuePage } from '@forge/ui';
import fetch from '@forge/api';

const App = () => {
  async function createAsset(attributeValues) {
    const accessToken = 'ATATT3xFfGF0qgyC52Ig6I8bSgPFp3rfm8P5kXAIWVRzPvXUSx7mvOh29meTUfJ-erYZi766oeXqtOqUo=9B6C94EA'; // Replace with your actual access token
    const assetsUrl = 'https://api.atlassian.com/jsm/assets/workspace/2ae01f14-f028-4b04ad/v1';

    try {
      const response = await fetch(`${assetsUrl}/object/create`, {
        method: 'POST',
        headers: {
          'Authorization': `Bearer ${accessToken}`,
          'Content-Type': 'application/json',
        },
        body: JSON.stringify({
          objectTypeId: '256', // Replace with the actual object type ID
          leaveStartDate: attributeValues.Name
        }),
      });

      if (response.ok) {
        const responseData = await response.json();
        console.log('New asset created in Assets:', responseData);
      } else {
        console.error('Error creating asset in Assets:', response.statusText);
      }
    } catch (error) {
      console.error('Error:', error);
    }
  }

  async function onSubmit(formProps) {
    const newAssetValues = {
      leaveStartDate: formProps.date

      // Add more attribute values as needed
    };

    try {
      await createAsset(newAssetValues);
      console.log('Asset creation successful');
    } catch (error) {
      console.error('Error creating asset:', error);
    }
  }

  return (
    <Form onSubmit={onSubmit}>
      <DatePicker
        name="date"
        label="Leave Start Date"
        description="First day of your OOO period"
      />
      <DatePicker
        name="date2"
        label="Leave End Date"
        description="Last day of your OOO period"
      />
      <UserPicker
        name="User"
        label="Select User"
      />
      <Toggle
        label="Out of Office already"
        name="isSectionVisible"
      />
      {/* Add more form fields as needed */}
    </Form>
  );
};

export const run = render(
  <QueuePage>
    <App />
  </QueuePage>
);

Objecttype 256 is the id from my test one and I was just assuming to put the date in the Name field for the moment to get something over, Name is text so assumed it would work.

I would say there is a bucketload wrong here, just getting myself in a tangle.

HI there,

foremost, I hope this i not your actual accessToken…
If that’s the case, please remove that ASAP.

Your code is actually almost working :slight_smile:
In the “onSubmit” function, you create a const “newAssetValues” with the key “leaveStartDate” which holds the value “formProps.date”.
Then you call the “createAsset” function with “newAssetValues” as a parameter. In your defined body howevery you try to set leaveStartDate with attributeValues.name. I think that has to be the other way around. You want the Name value to be the date. Since in the “createAssets” function you defined the parameter to be called “attributeValues”, you would set the name like this:

body: JSON.stringify({
          objectTypeId: '256', // Replace with the actual object type ID
          attributes: [
            {
              objectTypeAttributeId: 135, // Replace with actual Object Type Attribute Id
              objectAttributeValues: [
                {
                   value: attributeValues.leaveStartDate
                }
               ]
            },
        })

Also you have to define the Attribute you want to set via a ID. So you need the Attribute ID from the Name Attribute. I never know if those “api.atlassian.com” calls work. So i change the prefix of the domain to be my baseUrl. In the case of the Insight calls you need to add “gateway/api/”. (https://youJiraInstance.atlassian.net/gateway/api/jsm/assets/workspace/workspaceId/v1)

Regards
Adrian

Thanks for that detailed answer, not 100% sure how that hangs together but will look in more detail tomorrow.

Token and such had been tinkered with when added to the ticket.

Appreciate your patience with this one.

1 Like