Added other Jira resources

This commit is contained in:
2025-08-05 10:42:26 +02:00
parent 3a1870a160
commit 64e7c44a7d
6 changed files with 94 additions and 49 deletions

View File

@@ -629,7 +629,7 @@ function bindWorkflowProperties(elementId) {
const totalWidth = properties_component.getBoundingClientRect().width
console.debug("totalWidth", totalWidth)
const minPropertiesWidth = 340; // this value avoid scroll bars
const minPropertiesWidth = 352; // this value avoid scroll bars
const inputSection = document.getElementById(`pi_${elementId}`);
const propertiesSection = document.getElementById(`pp_${elementId}`);

View File

@@ -196,7 +196,7 @@ class WorkflowDesigner(BaseComponent):
def save_properties(self, component_id: str, details: dict):
if component_id in self._state.components:
component = self._state.components[component_id]
component.properties = details
component.properties |= details
undo_redo_attrs = UndoRedoAttrs(f"Set properties for {component.title}", on_undo=self.refresh_state)
self._db.save_state(self._key, self._state, undo_redo_attrs)
@@ -518,7 +518,7 @@ class WorkflowDesigner(BaseComponent):
selected="selected" if name.value == request_type else None)
def _mk_input_group():
if request_type == JiraRequestTypes.Issues.value:
if request_type == JiraRequestTypes.Search.value:
return Div(
Input(type="text",
name="request",
@@ -538,7 +538,7 @@ class WorkflowDesigner(BaseComponent):
)
def _mk_extra_parameters():
if request_type == JiraRequestTypes.Issues.value:
if request_type == JiraRequestTypes.Search.value:
return Input(type="text",
name="fields",
value=component.properties.get("fields", DEFAULT_SEARCH_FIELDS),
@@ -547,7 +547,7 @@ class WorkflowDesigner(BaseComponent):
else:
return None
request_type = component.properties.get("request_type", JiraRequestTypes.Issues.value)
request_type = component.properties.get("request_type", JiraRequestTypes.Search.value)
return Div(
Fieldset(
Legend("JQL", cls="fieldset-legend"),

View File

@@ -186,40 +186,51 @@ class WorkflowDesignerProperties(BaseComponent):
selected="selected" if name.value == request_type else None)
def _mk_input_group():
if request_type == JiraRequestTypes.Issues.value:
if request_type == JiraRequestTypes.Search.value or request_type == "issues": # remove issues at some point
return [
Div(
Input(type="text",
name="fields",
value=self._component.properties.get("fields", DEFAULT_SEARCH_FIELDS),
name=f"{request_type}_fields",
value=self._component.properties.get(f"{request_type}_fields", DEFAULT_SEARCH_FIELDS),
placeholder="default fields",
cls="input w-full"),
P("Jira fields to retrieve"),
),
Div(
Input(type="text",
name="request",
value=self._component.properties.get("request", ""),
name=f"{request_type}_request",
value=self._component.properties.get(f"{request_type}_request", ""),
placeholder="Enter JQL",
cls="input w-full"),
P("Write your jql code"),
)
]
elif request_type == JiraRequestTypes.Comments.value:
elif request_type in (JiraRequestTypes.Issue.value, JiraRequestTypes.Comments.value):
return [
Div(
Input(type="text",
name="request",
value=self._component.properties.get("request", ""),
name=f"{request_type}_request",
value=self._component.properties.get(f"{request_type}_request", ""),
placeholder="Issue id",
cls="input w-full"),
P("Put the issue id here"),
)
]
elif request_type == JiraRequestTypes.Versions.value:
return [
Div(
Input(type="text",
name=f"{request_type}_request",
value=self._component.properties.get(f"{request_type}_request", ""),
placeholder="Project key",
cls="input w-full"),
P("Enter the project key"),
)
]
else:
return [Div("** Not Implemented **")]
return [Div(f"** Not Implemented ** ('{request_type}' not supported yet)")]
request_type = self._component.properties.get("request_type", JiraRequestTypes.Issues.value)
request_type = self._component.properties.get("request_type", JiraRequestTypes.Search.value)
return Div(
Fieldset(
Legend("Jira", cls="fieldset-legend"),

View File

@@ -191,13 +191,14 @@ class WorkflowPlayer(BaseComponent):
component.properties["repository"],
component.properties["table"]))
elif key == (ProcessorTypes.Producer, "Jira"):
request_type = component.properties["request_type"]
engine.add_processor(
JiraDataProducer(self._session,
self._settings_manager,
component.id,
component.properties["request_type"],
component.properties["request"],
component.properties["fields"]))
component.properties[f"{request_type}_request"],
component.properties.get(f"{request_type}_fields", None)))
elif key == (ProcessorTypes.Filter, "Default"):
engine.add_processor(DefaultDataFilter(component.id, component.properties["filter"]))
elif key == (ProcessorTypes.Presenter, "Default"):

View File

@@ -10,7 +10,7 @@ from core.Expando import Expando
JIRA_ROOT = "https://altares.atlassian.net/rest/api/3"
DEFAULT_HEADERS = {"Accept": "application/json"}
DEFAULT_SEARCH_FIELDS = "summary,status,assignee"
logger = logging.getLogger("jql")
logger = logging.getLogger("Jira")
class NotFound(Exception):
@@ -18,8 +18,10 @@ class NotFound(Exception):
class JiraRequestTypes(Enum):
Issues = "issues"
Search = "search"
Issue = "issue"
Comments = "comments"
Versions = "versions"
class Jira:
@@ -41,7 +43,10 @@ class Jira:
self.fields = fields
def test(self):
logger.debug(f"test with no parameters")
url = f"{JIRA_ROOT}/myself"
logger.debug(f" url: {url}")
response = requests.request(
"GET",
@@ -49,16 +54,21 @@ class Jira:
headers=DEFAULT_HEADERS,
auth=self.auth
)
logger.debug(f" response: {response}")
logger.debug(f" response.text: {response.text}")
return response
def issue(self, issue_id: str) -> Expando:
def issue(self, issue_id: str) -> list[Expando]:
"""
Retrieve an issue
:param issue_id:
:return:
"""
logger.debug(f"comments with {issue_id=}")
url = f"{JIRA_ROOT}/issue/{issue_id}"
logger.debug(f" url: {url}")
response = requests.request(
"GET",
@@ -66,8 +76,10 @@ class Jira:
headers=DEFAULT_HEADERS,
auth=self.auth
)
logger.debug(f" response: {response}")
logger.debug(f" response.text: {response.text}")
return Expando(json.loads(response.text))
return [Expando(json.loads(response.text))]
def fields(self) -> list[Expando]:
"""
@@ -86,14 +98,14 @@ class Jira:
as_dict = json.loads(response.text)
return [Expando(field) for field in as_dict]
def issues(self, jql: str, fields=None) -> list[Expando]:
def search(self, jql: str, fields=None) -> list[Expando]:
"""
Executes a JQL and returns the list of issues
:param jql:
:param fields: list of fields to retrieve
:return:
"""
logger.debug(f"Processing jql '{jql}'")
logger.debug(f"search with {jql=}, {fields=}")
if not jql:
raise ValueError("Jql cannot be empty.")
@@ -102,6 +114,7 @@ class Jira:
fields = self.fields
url = f"{JIRA_ROOT}/search"
logger.debug(f" url: {url}")
headers = DEFAULT_HEADERS.copy()
headers["Content-Type"] = "application/json"
@@ -113,15 +126,19 @@ class Jira:
"maxResults": 500, # Does not seem to be used. It's always 100 !
"startAt": 0
}
logger.debug(f" payload: {payload}")
result = []
while True:
logger.debug(f"Request startAt '{payload['startAt']}'")
logger.debug(f" Request startAt '{payload['startAt']}'")
response = requests.request("POST",
url,
data=json.dumps(payload),
headers=headers,
auth=self.auth)
logger.debug(f" response: {response}")
logger.debug(f" response.text: {response.text}")
if response.status_code != 200:
raise Exception(self._format_error(response))
@@ -130,6 +147,7 @@ class Jira:
result += as_dict["issues"]
if as_dict["startAt"] + as_dict["maxResults"] >= as_dict["total"]:
logger.debug(f" response: {response}")
# We retrieve more than the total nuber of items
break
@@ -143,12 +161,18 @@ class Jira:
:param issue_id:
:return:
"""
logger.debug(f"comments with {issue_id=}")
url = f"{JIRA_ROOT}/issue/{issue_id}/comment"
logger.debug(f" url: {url}")
response = requests.request("GET",
url,
headers=DEFAULT_HEADERS,
auth=self.auth)
logger.debug(f" response: {response}")
logger.debug(f" response.text: {response.text}")
if response.status_code != 200:
raise Exception(self._format_error(response))
@@ -156,6 +180,34 @@ class Jira:
result = as_dict["comments"]
return [Expando(issue) for issue in result]
def versions(self, project_key):
"""
Given a project name and a version name
returns fixVersion number in JIRA
:param project_key:
:return:
"""
logger.debug(f"versions with {project_key=}")
url = f"{JIRA_ROOT}/project/{project_key}/versions"
logger.debug(f" url: {url}")
response = requests.request(
"GET",
url,
headers=DEFAULT_HEADERS,
auth=self.auth
)
logger.debug(f" response: {response}")
logger.debug(f" response.text: {response.text}")
if response.status_code != 200:
raise NotFound()
as_list = json.loads(response.text)
return [Expando(version) for version in as_list]
def extract(self, jql, mappings, updates=None) -> list[dict]:
"""
Executes a jql and returns list of dict
@@ -188,30 +240,6 @@ class Jira:
row = {cvs_col: issue.get(jira_path) for jira_path, cvs_col in mappings.items() if cvs_col is not None}
yield row
def get_versions(self, project_key):
"""
Given a project name and a version name
returns fixVersion number in JIRA
:param project_key:
:param version_name:
:return:
"""
url = f"{JIRA_ROOT}/project/{project_key}/versions"
response = requests.request(
"GET",
url,
headers=DEFAULT_HEADERS,
auth=self.auth
)
if response.status_code != 200:
raise NotFound()
as_list = json.loads(response.text)
return [Expando(version) for version in as_list]
def get_version(self, project_key, version_name):
"""
Given a project name and a version name
@@ -221,7 +249,7 @@ class Jira:
:return:
"""
for version in self.get_versions(project_key):
for version in self.versions(project_key):
if version.name == version_name:
return version

View File

@@ -47,4 +47,9 @@ loggers:
AddStuffApp:
level: INFO
handlers: [ console ]
propagate: False
Jira:
level: DEBUG
handlers: [ console ]
propagate: False