-
Notifications
You must be signed in to change notification settings - Fork 58
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
[ENG-6669] Institutional Access project Request Modal #2433
Changes from all commits
51fd954
3a29a83
5a7fe94
13f0699
0039fc6
660cee2
2fe05c7
5300c97
002ccc8
bf8ab2c
1abd4e4
d54a71d
dae4684
6fb0bee
9b21ce4
524eef0
4057df3
19fb416
4b74341
983ac69
e7f569d
715bee8
a92edbf
9a3e056
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,13 @@ | ||
import { inject as service } from '@ember/service'; | ||
import config from 'ember-osf-web/config/environment'; | ||
const { OSF: { apiUrl } } = config; | ||
import OsfAdapter from './osf-adapter'; | ||
|
||
export default class NodeRequestAdapter extends OsfAdapter { | ||
@service session; | ||
|
||
urlForCreateRecord(modelName, snapshot) { | ||
const nodeId = snapshot.record.target; | ||
return `${apiUrl}/v2/nodes/${nodeId}/requests/`; | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -9,6 +9,16 @@ import InstitutionModel from 'ember-osf-web/models/institution'; | |
import { SuggestedFilterOperators } from 'ember-osf-web/models/related-property-path'; | ||
import SearchResultModel from 'ember-osf-web/models/search-result'; | ||
import { Filter } from 'osf-components/components/search-page/component'; | ||
import { waitFor } from '@ember/test-waiters'; | ||
import { task } from 'ember-concurrency'; | ||
import { taskFor } from 'ember-concurrency-ts'; | ||
import Toast from 'ember-toastr/services/toast'; | ||
import Intl from 'ember-intl/services/intl'; | ||
import Store from '@ember-data/store'; | ||
import CurrentUser from 'ember-osf-web/services/current-user'; | ||
import {MessageTypeChoices} from 'ember-osf-web/models/user-message'; | ||
import {RequestTypeChoices} from 'ember-osf-web/models/node-request'; | ||
|
||
import config from 'ember-osf-web/config/environment'; | ||
|
||
const shareDownloadFlag = config.featureFlagNames.shareDownload; | ||
|
@@ -49,6 +59,20 @@ export default class InstitutionalObjectList extends Component<InstitutionalObje | |
@tracked sortParam?: string; | ||
@tracked visibleColumns = this.args.columns.map(column => column.name); | ||
@tracked dirtyVisibleColumns = [...this.visibleColumns]; // track changes to visible columns before they are saved | ||
@tracked selectedPermissions = 'write'; | ||
@tracked projectRequestModalShown = false; | ||
@tracked activeTab = 'request-access'; // Default tab | ||
@tracked messageText = ''; | ||
@tracked bccSender = false; | ||
@tracked replyTo = false; | ||
@tracked selectedUserId = ''; | ||
@tracked selectedNodeId = ''; | ||
@tracked showSendMessagePrompt = false; | ||
@service toast!: Toast; | ||
@service intl!: Intl; | ||
@service store!: Store; | ||
@service currentUser!: CurrentUser; | ||
|
||
|
||
get queryOptions() { | ||
const options = { | ||
|
@@ -151,4 +175,125 @@ export default class InstitutionalObjectList extends Component<InstitutionalObje | |
updatePage(newPage: string) { | ||
this.page = newPage; | ||
} | ||
|
||
@action | ||
openProjectRequestModal(contributor: any) { | ||
this.selectedUserId = contributor.userId; | ||
this.selectedNodeId = contributor.nodeId; | ||
this.projectRequestModalShown = true; | ||
} | ||
|
||
@action | ||
handleBackToSendMessage() { | ||
this.activeTab = 'send-message'; | ||
this.showSendMessagePrompt = false; | ||
setTimeout(() => { | ||
this.projectRequestModalShown = true; // Reopen the main modal | ||
}, 200); | ||
|
||
} | ||
|
||
@action | ||
closeSendMessagePrompt() { | ||
this.showSendMessagePrompt = false; // Hide confirmation modal without reopening | ||
} | ||
|
||
@action | ||
toggleProjectRequestModal() { | ||
this.projectRequestModalShown = !this.projectRequestModalShown; | ||
} | ||
|
||
@action | ||
updateselectedPermissions(permission: string) { | ||
this.selectedPermissions = permission; | ||
} | ||
|
||
@action | ||
setActiveTab(tabName: string) { | ||
this.activeTab = tabName; | ||
} | ||
|
||
|
||
@action | ||
resetFields() { | ||
this.selectedPermissions = 'write'; | ||
this.bccSender = false; | ||
this.replyTo = false; | ||
} | ||
|
||
@task | ||
@waitFor | ||
async handleSend() { | ||
try { | ||
if (this.activeTab === 'send-message') { | ||
await taskFor(this._sendUserMessage).perform(); | ||
} else if (this.activeTab === 'request-access') { | ||
await taskFor(this._sendNodeRequest).perform(); | ||
} | ||
|
||
this.toast.success( | ||
this.intl.t('institutions.dashboard.object-list.request-project-message-modal.message_sent_success'), | ||
); | ||
this.resetFields(); | ||
} catch (error) { | ||
const errorDetail = error?.errors?.[0]?.detail.user || error?.errors?.[0]?.detail || ''; | ||
const errorCode = parseInt(error?.errors?.[0]?.status, 10); | ||
|
||
if (errorCode === 400 && errorDetail.includes('does not have Access Requests enabled')) { | ||
// Product wanted special handling for this error that involve a second pop-up modal | ||
// Timeout to allow the modal to exit, can't have two OSFDialogs open at same time | ||
setTimeout(() => { | ||
this.showSendMessagePrompt = true; // Timeout to allow the modal to exit | ||
}, 200); | ||
Comment on lines
+245
to
+247
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Similar to a comment above, I would avoid using
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. As mentioned in the comment above this actual will temporarily cause where both modals are open simultaneously. |
||
} else if ([400, 403].includes(errorCode)) { | ||
// Handle more specific errors 403s could result due if a project quickly switches it's institution | ||
this.toast.error(errorDetail); | ||
} else if (errorDetail.includes('Request was throttled')) { // 429 response not in JSON payload. | ||
this.toast.error(errorDetail); | ||
} else { | ||
this.toast.error( | ||
this.intl.t('institutions.dashboard.object-list.request-project-message-modal.message_sent_failed'), | ||
); | ||
} | ||
} finally { | ||
this.projectRequestModalShown = false; // Close the main modal | ||
} | ||
} | ||
|
||
@task | ||
@waitFor | ||
async _sendUserMessage() { | ||
Johnetordoff marked this conversation as resolved.
Show resolved
Hide resolved
|
||
const userMessage = this.store.createRecord('user-message', { | ||
messageText: this.messageText.trim(), | ||
messageType: MessageTypeChoices.InstitutionalRequest, | ||
bccSender: this.bccSender, | ||
replyTo: this.replyTo, | ||
institution: this.args.institution, | ||
user: this.selectedUserOsfGuid, | ||
}); | ||
await userMessage.save(); | ||
} | ||
|
||
@task | ||
@waitFor | ||
async _sendNodeRequest() { | ||
Johnetordoff marked this conversation as resolved.
Show resolved
Hide resolved
|
||
const nodeRequest = this.store.createRecord('node-request', { | ||
comment: this.messageText.trim(), | ||
requestType: RequestTypeChoices.InstitutionalRequest, | ||
requestedPermissions: this.selectedPermissions, | ||
bccSender: this.bccSender, | ||
replyTo: this.replyTo, | ||
institution: this.args.institution, | ||
messageRecipient: this.selectedUserOsfGuid, | ||
target: this.selectedNodeId, | ||
}); | ||
await nodeRequest.save(); | ||
} | ||
|
||
get selectedUserOsfGuid() { | ||
const url = new URL(this.selectedUserId); | ||
const pathSegments = url.pathname.split('/').filter(Boolean); | ||
return pathSegments[pathSegments.length - 1] || ''; // Last non-empty segment | ||
} | ||
|
||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,14 @@ | ||
|
||
.icon-message { | ||
opacity: 0; | ||
color: $color-text-blue-dark; | ||
background-color: inherit !important; | ||
border: 0 !important; | ||
box-shadow: 0 !important; | ||
} | ||
|
||
.icon-message:hover { | ||
opacity: 1; | ||
background-color: inherit !important; | ||
} | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is there a reason why we have a
setTimeout
here? I'd like to avoid any unneeded timeouts if possibleThere was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes, I'll leave a comment here, I clarified this but only later on line 243, and not very well. The reason for the timeout is that ember bans having two dialogue modals open at the same time and the modal closing animation happens too slowly, so just
opens modal2 before the modal1 close animation is complete. Causing the framework to produce an error because there are technically two open modals. Product wanted a modal on this, because the toast message is not enough.