Forge app issues while deploying

I have created a app to export issues.
But I am facing issues while deploying it I will share my manifest.yml and index.js file and also the error please help me resolve this.


manifest file
modules:
jira:issueNavigatorAction:
- key: export-issues-action
title: Export All Issues
icon: https://developer.atlassian.com/platform/forge/images/export.svg
resource: main
resolver:
function: resolver
render: native

function:
- key: resolver
handler: index.handler

resources:

  • key: main
    path: static/index.html
    tunnel:
    port: 3000

app:
id: ari:cloud:ecosystem::app/d3cf4dcf-ad4f-4e4d-ba80-bbab6a288e4d
runtime:
name: nodejs20.x

permissions:
scopes:
- read:jira-work
- read:jira-user
- read:issue-details:jira

index file
const api = require(“@forge/api”);

exports.handler = async (req) => {
const jql = “ORDER BY created DESC”;
const response = await api.asApp().requestJira(/rest/api/3/search?jql=${encodeURIComponent(jql)}&maxResults=50);
const data = await response.json();

const issues = data.issues.map(issue => ({
key: issue.key,
summary: issue.fields.summary,
status: issue.fields.status.name,
assignee: issue.fields.assignee?.displayName || “Unassigned”,
reporter: issue.fields.reporter.displayName,
created: issue.fields.created
}));

const csv = [
[“Key”, “Summary”, “Status”, “Assignee”, “Reporter”, “Created”],

issues.map(i => [i.key, i.summary, i.status, i.assignee, i.reporter, i.created])
].map(row => row.map(field => "${field}").join(“,”)).join(“\n”);

return new Response(csv, {
headers: {
‘Content-Type’: ‘text/csv’,
‘Content-Disposition’: ‘attachment; filename=“issues.csv”’
}
});
};

and this is the error

D:\forge-export-csv\manifest.yml
13:15 error function handler property ‘index.handler’ cannot find associated file with name ‘index.jt’ valid-module-required

Hi @JaydeepKapure ,

Does your index file have the right extension? I’m seeing .jt, should not be .js?

1 Like

Yes It is correct as .js I am getting error as
D:\forge-export-csv\manifest.yml
13:15 error function handler property ‘index.handler’ cannot find associated file with name ‘index.jt’ valid-module-required

@JaydeepKapure are you exporting a function called handler on that index.jt file?

Yes is there any other way

Try to run the deploy with --verbose.

It gives the same error

Please share the output.

Is your index.js inside the src folder?

I have already shared the ss it is outside

Sorry I did not see the SS. My bad.
I think it’s the root cause. try to create a folder called src and move the index.js to inside of it and try it again.

1 Like

I have tried that as well but still same error

I’d just run forge create to get a working template and folder structure. The you can either restructure your current code base or replace the app ID in manifest and copy code over.

1 Like

I have tried that multiple times but still same error can you check my both files is it correct

Nothing wrong with your code. It’s either your folder structure or file naming.

Simplest way for you to debug this is:

  1. Create a new Forge app with forge create
  2. That will generate the correct folder structure and file names
  3. Copy across your existing code into those files

Ok I will use template Jira issue navigator action ui-kit

Ok I have create new and Now I have 2 files Frontend and backend.

But it is deployed and installed successfully I can also see the button but when I click on it there are no action performed and when I inspect there are no errors.
can you please check the code.
also is there any way to check the logs

Backend
import api from “@forge/api”;
import Resolver from “@forge/resolver”;

const resolver = new Resolver();

resolver.define(“exportIssuesToCSV”, async () => {
const jql = “ORDER BY created DESC”;
const response = await api.asApp().requestJira(/rest/api/3/search?jql=${encodeURIComponent(jql)}&maxResults=50);
const data = await response.json();

const issues = data.issues.map(issue => ({
key: issue.key,
summary: issue.fields.summary,
status: issue.fields.status.name,
assignee: issue.fields.assignee ? issue.fields.assignee.displayName : “Unassigned”,
reporter: issue.fields.reporter.displayName,
created: issue.fields.created
}));

const csv = [
[“Key”, “Summary”, “Status”, “Assignee”, “Reporter”, “Created”],

issues.map(i => [i.key, i.summary, i.status, i.assignee, i.reporter, i.created])
]
.map(row => row.map(field => "${field}").join(“,”))
.join(“\n”);

return csv;
});

export const handler = resolver.getDefinitions();

UI
import React, { useState } from “react”;
import { invoke } from “@forge/bridge”;

const App = () => {
const [loading, setLoading] = useState(false);

const handleExport = async () => {
setLoading(true);
const csv = await invoke(“exportIssuesToCSV”);
const blob = new Blob([csv], { type: “text/csv” });
const url = window.URL.createObjectURL(blob);
const a = document.createElement(“a”);
a.href = url;
a.download = “issues.csv”;
a.click();
window.URL.revokeObjectURL(url);
setLoading(false);
};

return (



{loading ? “Exporting
” : “Export Issues to CSV”}


);
};

export default App;