How to retrieve all fields from Edit Issue Screen?

I am trying to retrieve all the fields that get presented when one clicks Edit Issue in a specific project, including custom fields. Then later on show these on the UI in my plugin.

As far as my development and test environments go I thought I had achieved this with, but trying it out in a production environment has shown me that there are some fields missing and I can not find the root cause of it.

I had to obfuscate sanitise the code. But I tried to include as much as I can to provide a full picture, hoping it will be easier to understand. I know that the both methods are very similar to each other, refactoring and optimising would be my next step but I must use 2 methods because of the underlying architecture.

Thank you.

This is how I retrieve the Mandatory Fields:

    @Override
    public List<JsonObject> getMandatoryFields(String projectKey, String issueTypeName) {

        Project project = projectManager.getProjectByCurrentKey(projectKey);
        Optional<IssueType> optionalIssueType = getIssueTypeObjectByName(issueTypeName);

        if (projectKey.isEmpty() || issueTypeName.isEmpty() || !optionalIssueType.isPresent()) {
            return new ArrayList<>();
        }

        FieldLayoutManager fieldLayoutManager = ComponentAccessor.getFieldLayoutManager();
        FieldLayout fieldLayout = fieldLayoutManager.getFieldLayout(project.getId(), optionalIssueType.get().getId());
        List<FieldLayoutItem> mandatoryFieldLayoutItems =
            fieldLayout.getRequiredFieldLayoutItems(project, Collections.singletonList(optionalIssueType.get().getName()));

        List<JsonObject> fields = new ArrayList<>();
        for (FieldLayoutItem fieldLayoutItem : mandatoryFieldLayoutItems) {
            OrderableField<Object> orderableField = fieldLayoutItem.getOrderableField();
            String fieldId = orderableField.getId();
                JsonObject fieldAsJson = new JsonObject();
                fieldAsJson.addProperty(KEY_ID, fieldId);
                String fieldName = orderableField.getName();
                fieldAsJson.addProperty(KEY_NAME, fieldName);
                String fieldDescription = fieldLayoutItem.getRawFieldDescription();
                fieldAsJson.addProperty(KEY_DESCRIPTION, fieldDescription == null ? DEFAULT_FIELD_DESCRIPTION : fieldDescription);
                fields.add(fieldAsJson);
        }
        return fields;
    }

And here is how I retrieve the remaining optional fields:

    @Override
    public List<JsonObject> getOptionalFields(String projectKey, String issueTypeName) {
        Project project = projectManager.getProjectByCurrentKey(projectKey);
        Optional<IssueType> optionalIssueType = getIssueTypeObjectByName(issueTypeName);

        if (projectKey.isEmpty() || issueTypeName.isEmpty() || !optionalIssueType.isPresent()) {
            return new ArrayList<>();
        }

        FieldLayoutManager fieldLayoutManager = ComponentAccessor.getFieldLayoutManager();
        FieldLayout fieldLayout = fieldLayoutManager.getFieldLayout(project.getId(), optionalIssueType.get().getId());

        List<FieldLayoutItem> visibleOptionalFieldLayoutItems =
            fieldLayout.getVisibleLayoutItems(project, Collections.singletonList(optionalIssueType.get().getName()));

        List<FieldLayoutItem> optionalFieldsLayoutItems =
            visibleOptionalFieldLayoutItems.stream().filter(e -> !e.isRequired()).collect(Collectors.toList());

        Collections.sort(optionalFieldsLayoutItems, Collections.reverseOrder());

        List<OrderableField> editScreenFields = getAllFieldsFromEditScreen(projectKey, issueTypeName);

        List<JsonObject> optionalFields = new ArrayList<>();
        for (FieldLayoutItem fieldLayoutItem : optionalFieldsLayoutItems) {
            OrderableField<Object> orderableField = fieldLayoutItem.getOrderableField();

            if (!editScreenFields.contains(orderableField)) {
                continue;
            }

            String fieldId = orderableField.getId();
            if (!"issuetype".equalsIgnoreCase(fieldId) && !"reporter".equalsIgnoreCase(orderableField.getName()) &&
                !"attachment".equalsIgnoreCase(orderableField.getName())) {
                JsonObject fieldAsJson = new JsonObject();
                fieldAsJson.addProperty(KEY_ID, fieldId);
                String fieldName = orderableField.getName();
                fieldAsJson.addProperty(KEY_NAME, fieldName);
                String fieldDescription = fieldLayoutItem.getRawFieldDescription();
                fieldAsJson.addProperty(KEY_DESCRIPTION, fieldDescription == null ? DEFAULT_FIELD_DESCRIPTION : fieldDescription);
                optionalFields.add(fieldAsJson);
            }
        }

        return optionalFields;
    }

All the retrieved fields later on get inserted with JS into the UI.
Which looks like this:

    function addDynamicFieldsForProjectAndIssueType(index, value, identifier) {
        let mandatoryFields = jQuery('#tcm-mandatory-fields-header');
        let fieldId = value["id"];
        let fieldName = value["name"];
        let fieldDescription = value["description"] === "No description available" ? "" : value["description"];

        let currentRow = $('<div class="ui-state-default g-row tcm-' + identifier + '-field"></div>');
        let checkbox;
        if (identifier == "mandatory") {
            checkbox = '<div class="checkbox"><input class="checkbox" type="checkbox" id="checkbox-' + fieldId + '" name="' + fieldId + '[check]" checked disabled>' +
                '<input name="' + fieldId + '[fieldtype]" value="mandatory" hidden><label for="checkbox-' + fieldId + '">' + fieldName + '</label></div>';
        } else {
            checkbox = '<div class="checkbox"><input class="checkbox" type="checkbox" id="checkbox-' + fieldId + '" name="' + fieldId + '[check]">' +
                '<input name="' + fieldId + '[fieldtype]" value="optional" hidden><label for="checkbox-' + fieldId + '">' + fieldName + '</label></div>';
        }

        let inputField = '<input class="text" type="hidden" id="tcm-creation-optional-field-' + fieldId + '" name="' + fieldId + '[value]" value="' + fieldName + '">';

        let description = ' <input class="text long-field" type="text"  name="' + fieldId + '[description]"' +
            'id="tcm-creation-issuetype-description" placeholder="No description available"' +
            'value="' + fieldDescription + '"/></div>';

        currentRow.append(checkbox);
        currentRow.append(inputField);
        currentRow.append(description);

        $(".tcs-optional-fields-grid").append(currentRow);
        mandatoryFields.after(currentRow);
    }

The two methods retrieving the fields

getVisibleFieldLayoutItems();
getRequiredFieldLayoutItems();

were not returning proper results. Changed both to use getFieldLayoutItems(); and then filtering the results.

This is the code now :

    @Override
    public List<JsonObject> getMandatoryFields(String projectKey, String issueTypeName) {

        Project project = projectManager.getProjectByCurrentKey(projectKey);
        Optional<IssueType> optionalIssueType = getIssueTypeObjectByName(issueTypeName);

        if (projectKey.isEmpty() || issueTypeName.isEmpty() || !optionalIssueType.isPresent()) {
            return new ArrayList<>();
        }

        FieldLayoutManager fieldLayoutManager = ComponentAccessor.getFieldLayoutManager();
        FieldLayout fieldLayout = fieldLayoutManager.getFieldLayout(project.getId(), optionalIssueType.get().getId());
// Changes start____________________________________________________
        List<FieldLayoutItem> fieldLayoutItems =
            fieldLayout.getFieldLayoutItems();

        List<FieldLayoutItem> mandatoryFieldLayoutItems =
            fieldLayoutItems.stream().filter(e -> e.isRequired()).collect(Collectors.toList());

        Collections.sort(mandatoryFieldLayoutItems, Collections.reverseOrder());
// Changes end____________________________________________________
        List<JsonObject> fields = new ArrayList<>();
        for (FieldLayoutItem fieldLayoutItem : mandatoryFieldLayoutItems) {
            OrderableField<Object> orderableField = fieldLayoutItem.getOrderableField();
            String fieldId = orderableField.getId();
            if (!"issuetype".equalsIgnoreCase(fieldId) && !"reporter".equalsIgnoreCase(orderableField.getName()) &&
                !"attachment".equalsIgnoreCase(orderableField.getName())) {
                JsonObject fieldAsJson = new JsonObject();
                fieldAsJson.addProperty(KEY_ID, fieldId);
                String fieldName = orderableField.getName();
                fieldAsJson.addProperty(KEY_NAME, fieldName);
                String fieldDescription = fieldLayoutItem.getRawFieldDescription();
                fieldAsJson.addProperty(KEY_DESCRIPTION, fieldDescription == null ? DEFAULT_FIELD_DESCRIPTION : fieldDescription);
                fields.add(fieldAsJson);
            }
        }

        return fields;
    }