Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(jira-server): Save and allow to reuse recent search queries in the scope phase of poker meeting for JiraServer #6551

Merged
merged 25 commits into from
May 31, 2022

Conversation

igorlesnenko
Copy link
Contributor

@igorlesnenko igorlesnenko commented May 12, 2022

Fixes: #5820

This PR introduces a new PostgreSQL table and new mutaton for storing integrations search queries.

Recent Jira Server search queries are now automatically saved

Also see the next issue with suggeted improvements: #6567

How to test:

  • Create a poker Meeting with Jira Server integration connected
  • On a Jira Server tab:
  • Enter any search string and pick any found issue, see the search query was saved in the dropdown menu.
  • Select any project in the project filter menu, enter any search string and pick any found issue, see the search query was saved in the dropdown menu.
  • Clear the search query and the project filter, select both previous saved queries, see that they were executed correctly
  • Remove queries, see they were removed correctly

@igorlesnenko igorlesnenko changed the title feat(jira-server): persist search query feat(jira-server): Automatically save search queries for JiraS erver in the scope phase of poker meeting May 17, 2022
@igorlesnenko igorlesnenko changed the title feat(jira-server): Automatically save search queries for JiraS erver in the scope phase of poker meeting feat(jira-server): Automatically save search queries for JiraServer in the scope phase of poker meeting May 17, 2022
@igorlesnenko igorlesnenko changed the title feat(jira-server): Automatically save search queries for JiraServer in the scope phase of poker meeting feat(jira-server): Save and list recent search queries for JiraServer in the scope phase of poker meeting May 17, 2022
@igorlesnenko igorlesnenko changed the title feat(jira-server): Save and list recent search queries for JiraServer in the scope phase of poker meeting feat(jira-server): Save and show recent search queries for JiraServer in the scope phase of poker meeting May 17, 2022
@igorlesnenko igorlesnenko changed the title feat(jira-server): Save and show recent search queries for JiraServer in the scope phase of poker meeting feat(jira-server): Save and allow to reuse recent search queries in the scope phase of poker meeting for JiraServer May 17, 2022
@igorlesnenko igorlesnenko marked this pull request as ready for review May 18, 2022 12:14
$providerId: Int
$jiraServerSearchQuery: JiraServerSearchQueryInput
) {
persistIntegrationSearchQuery(
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We still need to wrap the generic mutation in an individual one on a frontend to request the specific integration response above. An issue with the suggestion to improve: #6567

$teamId: ID!
$service: IntegrationProviderServiceEnum!
$providerId: Int
$jiraServerSearchQuery: JiraServerSearchQueryInput
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There is currently no way to accept union as input, so we need to define individual fields for each integration like we do for add integration provider mutation.
An alternative approach is to use JSON type, but it will require additional validation on the backend.
Later we will be able to use oneof as soon as it will be released in graphql

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

For oneof you would need to group all input union types into one input object and just add the directive. All it does is adding server side verification. We can already arrange the types in this form and we could also implement the directive now if you feel it's worth it.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

oneof feels cleaner, as we do not need to pass service, however I think it is ok as is for now


const mutation = graphql`
mutation RemoveJiraServerSearchQueryMutation($id: ID!, $teamId: ID!) {
removeIntegrationSearchQuery(id: $id, teamId: $teamId) {
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We still need to wrap the generic mutation in an individual one on a frontend to request the specific integration response above. An issue with the suggestion to improve: #6567

) {
return {error: {message: `Provider does not exists`}}
}
await upsertIntegrationSearchQueryWithProviderId({
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We need to define two separate SQL queries to correctly handle ON CONFLICT with nullable providerId field

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Now we handle uniqueness and sorting on PostgreSQL side, instead of doing that manually in code

return null
}

const searchQueries = await getLatestIntegrationSearchQueriesWithProviderId({
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Two separate SQL queries to be able to request AND providerId IS null

@igorlesnenko igorlesnenko requested a review from Dschoordsch May 18, 2022 13:17
Copy link
Contributor

@Dschoordsch Dschoordsch left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Only looked at the DB part yet. I don't see why we need two separate kinds of queries and indexes. Even with allowing null for "providerId" that's just another value.

@igorlesnenko igorlesnenko requested a review from Dschoordsch May 19, 2022 13:39
@Dschoordsch Dschoordsch requested a review from nickoferrall May 20, 2022 10:04
@Dschoordsch
Copy link
Contributor

Let's get a reviewer review in first, @nickoferrall could you please take a look?

@Dschoordsch Dschoordsch requested review from Dschoordsch and removed request for Dschoordsch May 20, 2022 10:05
Copy link
Contributor

@nickoferrall nickoferrall left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This looks great! I've tested it and everything is working. One tiny issue is when removing a saved query, it currently takes the user to that query. Instead, I think it should just remove the saved query and not alter the current search.

removing-saved-query

@igorlesnenko igorlesnenko requested a review from nickoferrall May 24, 2022 13:20
@name removeIntegrationSearchQueryQuery
*/
DELETE FROM "IntegrationSearchQuery"
WHERE "id" = :id AND "userId" = :userId AND "teamId" = :teamId;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

+1 Why do we need "userId" and "teamId" here if "id" is already the primary key?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@Dschoordsch I added this as a validation, to not fetch IntegrationQuery first and manually check userId and teamId.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could you leave a comment so it's clear for the next one?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Added a comment

packages/server/graphql/types/JiraServerIntegration.ts Outdated Show resolved Hide resolved
packages/server/graphql/types/JiraServerIntegration.ts Outdated Show resolved Hide resolved
return ''
}

return `jiraServer:${auth.providerId}`
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

-2 The id is not unique, a user can have the same provider for multiple teams, each team has a different auth. Thus you need to use jiraServer:${auth}.id here.

The main issue here is that we're mixing the providers (which are per team and should be non-null) with the auth (which is per team member and should be nullable). So what we really should do is:

  • make JiraServerIntegration nullable (also GitLab, AzureDevOps, MSTeams, ...)
  • move IntegrationProvider fields to Team object.

No need to do it in this change, but we should address that.

Copy link
Contributor Author

@igorlesnenko igorlesnenko May 30, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@Dschoordsch

a user can have the same provider for multiple teams

So in future provider will be added to the whole organisation?
Currently, I see that we have teamId column in the IntegrationProvider table.
Can we have IntegrationProviderTeam table with id | providerId | teamId columns?

Copy link
Contributor Author

@igorlesnenko igorlesnenko May 30, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

auth object does not have id. Made it like this:

return `jiraServer:${teamId}:${auth.providerId}

Copy link
Contributor

@Dschoordsch Dschoordsch May 30, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That's the current state, each "IntegrationProvider" has scope "org" or "team". Right now the organization is derived from the team, but we may store it separately at some point #6014

}

return {
id: searchQuery.id,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

-1 This will not be unique, so we need to prefix it. There is already SearchQueryId.join but that's Meeting specific.

Copy link
Contributor Author

@igorlesnenko igorlesnenko May 30, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@Dschoordsch pushed a commit that uses toGlobalId and fromGlobalId from graphql-relay package. I think this way we can avoid creating a new function every time. What do you think?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The issue with the proposal #6642

source: RemoveIntegrationSearchQuerySuccessSource
) => RemoveIntegrationSearchQuerySuccessSource
} = {
jiraServerIntegration: (source) => {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

+1 did you test this resolver is actually necessary? Also you would usually import the generated types here

const RemoveIntegrationSearchQuerySuccess: RemoveIntegrationSearchQuerySuccessResolvers = {

You might need to define the JiraServerIntegration source properly though.

Copy link
Contributor Author

@igorlesnenko igorlesnenko May 30, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@Dschoordsch Does not work for me without this resolver, jiraServerIntegration returned as `null.

Picking generated type RemoveIntegrationSearchQuerySuccessResolvers does not work in this case as I need to just forward plain source here, not actually resolve.

@igorlesnenko igorlesnenko requested a review from Dschoordsch May 30, 2022 18:43
@vercel
Copy link

vercel bot commented May 31, 2022

The latest updates on your projects. Learn more about Vercel for Git ↗︎

Name Status Preview Updated
parabol ❌ Failed (Inspect) May 31, 2022 at 10:19AM (UTC)

@igorlesnenko igorlesnenko merged commit 018ab70 into master May 31, 2022
@igorlesnenko igorlesnenko deleted the jira-server-persist-search branch May 31, 2022 10:32
@github-actions github-actions bot mentioned this pull request Sep 26, 2022
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Jira Server: persist search query
3 participants