forked from naturalcrit/homebrewery
-
Notifications
You must be signed in to change notification settings - Fork 1
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge branch 'master' into addLockNotification-naturalcrit#3326
- Loading branch information
Showing
24 changed files
with
473 additions
and
304 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,103 @@ | ||
name: Limit pull requests | ||
description: > | ||
Limit the number of open pull requests to the repository created by a user | ||
author: ZhongRuoyu (from Homebrew repository) | ||
branding: | ||
icon: alert-triangle | ||
color: yellow | ||
|
||
inputs: | ||
token: | ||
description: GitHub token | ||
required: false | ||
default: ${{ github.token }} | ||
except-users: | ||
description: The users exempted from the limit, one per line | ||
required: false | ||
# https://docs.github.com/en/graphql/reference/enums#commentauthorassociation | ||
except-author-associations: | ||
description: The author associations exempted from the limit, one per line | ||
required: false | ||
comment-limit: | ||
description: > | ||
Post the comment when the user's number of open pull requests exceeds this | ||
number and `comment` is not empty | ||
required: true | ||
default: "10" | ||
comment: | ||
description: The comment to post when the limit is reached | ||
required: false | ||
close-limit: | ||
description: > | ||
Close the pull request when the user's number of open pull requests | ||
exceeds this number and `close` is set to `true` | ||
required: true | ||
default: "50" | ||
close: | ||
description: Whether to close the pull request when the limit is reached | ||
required: true | ||
default: "false" | ||
|
||
runs: | ||
using: composite | ||
steps: | ||
- name: Check the number of pull requests | ||
id: count-pull-requests | ||
run: | | ||
# If the user is exempted, assume they have no pull requests. | ||
if grep -Fiqx '${{ github.actor }}' <<<"$EXCEPT_USERS"; then | ||
echo "::notice::@${{ github.actor }} is exempted from the limit." | ||
echo "count=0" >>"$GITHUB_OUTPUT" | ||
exit 0 | ||
fi | ||
if grep -Fiqx '${{ github.event.pull_request.author_association }}' <<<"$EXCEPT_AUTHOR_ASSOCIATIONS"; then | ||
echo "::notice::@{{ github.actor }} is a ${{ github.event.pull_request.author_association }} exempted from the limit." | ||
echo "count=0" >>"$GITHUB_OUTPUT" | ||
exit 0 | ||
fi | ||
count="$( | ||
gh api \ | ||
--method GET \ | ||
--header 'Accept: application/vnd.github+json' \ | ||
--header 'X-GitHub-Api-Version: 2022-11-28' \ | ||
--field state=open \ | ||
--paginate \ | ||
'/repos/{owner}/{repo}/pulls' | | ||
jq \ | ||
--raw-output \ | ||
--arg USER '${{ github.actor }}' \ | ||
'map(select(.user.login == $USER)) | length' | ||
)" | ||
echo "::notice::@${{ github.actor }} has $count open pull request(s)." | ||
echo "count=$count" >>"$GITHUB_OUTPUT" | ||
env: | ||
GH_REPO: ${{ github.repository }} | ||
GH_TOKEN: ${{ inputs.token }} | ||
EXCEPT_USERS: ${{ inputs.except-users }} | ||
EXCEPT_AUTHOR_ASSOCIATIONS: ${{ inputs.except-author-associations }} | ||
shell: bash | ||
|
||
- name: Comment on pull request | ||
if: > | ||
fromJSON(steps.count-pull-requests.outputs.count) > fromJSON(inputs.comment-limit) && | ||
inputs.comment != '' | ||
run: | | ||
gh pr comment '${{ github.event.pull_request.number }}' \ | ||
--body="${COMMENT_BODY}" | ||
env: | ||
GH_REPO: ${{ github.repository }} | ||
GH_TOKEN: ${{ inputs.token }} | ||
COMMENT_BODY: ${{ inputs.comment }} | ||
shell: bash | ||
|
||
- name: Close pull request | ||
if: > | ||
fromJSON(steps.count-pull-requests.outputs.count) > fromJSON(inputs.close-limit) && | ||
inputs.close == 'true' | ||
run: | | ||
gh pr close '${{ github.event.pull_request.number }}' | ||
env: | ||
GH_REPO: ${{ github.repository }} | ||
GH_TOKEN: ${{ inputs.token }} | ||
shell: bash |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,29 @@ | ||
name: PR Check | ||
on: pull_request_target | ||
env: | ||
GH_REPO: ${{ github.repository }} | ||
GH_NO_UPDATE_NOTIFIER: 1 | ||
GH_PROMPT_DISABLED: 1 | ||
permissions: | ||
contents: read | ||
issues: write | ||
pull-requests: write | ||
statuses: write | ||
jobs: | ||
limit-pull-requests: | ||
if: always() && github.repository_owner == 'naturalcrit' | ||
runs-on: ubuntu-latest | ||
steps: | ||
- name: Checkout | ||
uses: actions/checkout@v2 | ||
|
||
- name : Run limit-pull-requests action | ||
uses: ./.github/actions/limit-pull-requests | ||
with: | ||
except-users: | | ||
dependabot | ||
comment-limit: 3 | ||
comment: | | ||
Hi, thanks for your contribution to the Homebrewery! You already have >=3 open pull requests. Consider completing some of your existing PRs before opening new ones. Thanks! | ||
close-limit: 5 | ||
close: false |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,102 +1,82 @@ | ||
const React = require('react'); | ||
const createClass = require('create-react-class'); | ||
const _ = require('lodash'); | ||
const cx = require('classnames'); | ||
const React = require('react'); | ||
const moment = require('moment'); | ||
|
||
const UIPage = require('../basePages/uiPage/uiPage.jsx'); | ||
|
||
const Nav = require('naturalcrit/nav/nav.jsx'); | ||
const Navbar = require('../../navbar/navbar.jsx'); | ||
|
||
const RecentNavItem = require('../../navbar/recent.navitem.jsx').both; | ||
const Account = require('../../navbar/account.navitem.jsx'); | ||
const NewBrew = require('../../navbar/newbrew.navitem.jsx'); | ||
const HelpNavItem = require('../../navbar/help.navitem.jsx'); | ||
|
||
const NaturalCritIcon = require('naturalcrit/svg/naturalcrit.svg.jsx'); | ||
|
||
let SAVEKEY = ''; | ||
|
||
const AccountPage = createClass({ | ||
displayName : 'AccountPage', | ||
getDefaultProps : function() { | ||
return { | ||
brew : {}, | ||
uiItems : {} | ||
}; | ||
}, | ||
getInitialState : function() { | ||
return { | ||
uiItems : this.props.uiItems | ||
}; | ||
}, | ||
componentDidMount : function(){ | ||
if(!this.state.saveLocation && this.props.uiItems.username) { | ||
SAVEKEY = `HOMEBREWERY-DEFAULT-SAVE-LOCATION-${this.props.uiItems.username}`; | ||
let saveLocation = window.localStorage.getItem(SAVEKEY); | ||
saveLocation = saveLocation ?? (this.state.uiItems.googleId ? 'GOOGLE-DRIVE' : 'HOMEBREWERY'); | ||
this.makeActive(saveLocation); | ||
const AccountPage = (props)=>{ | ||
// destructure props and set state for save location | ||
const { accountDetails, brew } = props; | ||
const [saveLocation, setSaveLocation] = React.useState(''); | ||
|
||
// initialize save location from local storage based on user id | ||
React.useEffect(()=>{ | ||
if(!saveLocation && accountDetails.username) { | ||
SAVEKEY = `HOMEBREWERY-DEFAULT-SAVE-LOCATION-${accountDetails.username}`; | ||
// if no SAVEKEY in local storage, default save location to Google Drive if user has Google account. | ||
let saveLocation = window.localStorage.getItem(SAVEKEY); | ||
saveLocation = saveLocation ?? (accountDetails.googleId ? 'GOOGLE-DRIVE' : 'HOMEBREWERY'); | ||
setActiveSaveLocation(saveLocation); | ||
} | ||
}, | ||
}, []); | ||
|
||
makeActive : function(newSelection){ | ||
if(this.state.saveLocation == newSelection) return; | ||
const setActiveSaveLocation = (newSelection)=>{ | ||
if(saveLocation === newSelection) return; | ||
window.localStorage.setItem(SAVEKEY, newSelection); | ||
this.setState({ | ||
saveLocation : newSelection | ||
}); | ||
}, | ||
|
||
renderButton : function(name, key, shouldRender=true){ | ||
if(!shouldRender) return; | ||
return <button className={this.state.saveLocation==key ? 'active' : ''} onClick={()=>{this.makeActive(key);}}>{name}</button>; | ||
}, | ||
setSaveLocation(newSelection); | ||
}; | ||
|
||
renderNavItems : function() { | ||
return <Navbar> | ||
<Nav.section> | ||
<NewBrew /> | ||
<HelpNavItem /> | ||
<RecentNavItem /> | ||
<Account /> | ||
</Nav.section> | ||
</Navbar>; | ||
}, | ||
// todo: should this be a set of radio buttons (well styled) since it's either/or choice? | ||
const renderSaveLocationButton = (name, key, shouldRender = true)=>{ | ||
if(!shouldRender) return null; | ||
return ( | ||
<button className={saveLocation === key ? 'active' : ''} onClick={()=>{setActiveSaveLocation(key);}}> | ||
{name} | ||
</button> | ||
); | ||
}; | ||
|
||
renderUiItems : function() { | ||
return <> | ||
<div className='dataGroup'> | ||
<h1>Account Information <i className='fas fa-user'></i></h1> | ||
<p><strong>Username: </strong> {this.props.uiItems.username || 'No user currently logged in'}</p> | ||
<p><strong>Last Login: </strong> {moment(this.props.uiItems.issued).format('dddd, MMMM Do YYYY, h:mm:ss a ZZ') || '-'}</p> | ||
</div> | ||
<div className='dataGroup'> | ||
<h3>Homebrewery Information <NaturalCritIcon /></h3> | ||
<p><strong>Brews on Homebrewery: </strong> {this.props.uiItems.mongoCount}</p> | ||
</div> | ||
<div className='dataGroup'> | ||
<h3>Google Information <i className='fab fa-google-drive'></i></h3> | ||
<p><strong>Linked to Google: </strong> {this.props.uiItems.googleId ? 'YES' : 'NO'}</p> | ||
{this.props.uiItems.googleId && | ||
<p> | ||
<strong>Brews on Google Drive: </strong> {this.props.uiItems.googleCount ?? <>Unable to retrieve files - <a href='https://github.com/naturalcrit/homebrewery/discussions/1580'>follow these steps to renew your Google credentials.</a></>} | ||
</p> | ||
} | ||
</div> | ||
<div className='dataGroup'> | ||
<h4>Default Save Location</h4> | ||
{this.renderButton('Homebrewery', 'HOMEBREWERY')} | ||
{this.renderButton('Google Drive', 'GOOGLE-DRIVE', this.state.uiItems.googleId)} | ||
</div> | ||
</>; | ||
}, | ||
// render the entirety of the account page content | ||
const renderAccountPage = ()=>{ | ||
return ( | ||
<> | ||
<div className='dataGroup'> | ||
<h1>Account Information <i className='fas fa-user'></i></h1> | ||
<p><strong>Username: </strong>{accountDetails.username || 'No user currently logged in'}</p> | ||
<p><strong>Last Login: </strong>{moment(accountDetails.issued).format('dddd, MMMM Do YYYY, h:mm:ss a ZZ') || '-'}</p> | ||
</div> | ||
<div className='dataGroup'> | ||
<h3>Homebrewery Information <NaturalCritIcon /></h3> | ||
<p><strong>Brews on Homebrewery: </strong>{accountDetails.mongoCount}</p> | ||
</div> | ||
<div className='dataGroup'> | ||
<h3>Google Information <i className='fab fa-google-drive'></i></h3> | ||
<p><strong>Linked to Google: </strong>{accountDetails.googleId ? 'YES' : 'NO'}</p> | ||
{accountDetails.googleId && ( | ||
<p> | ||
<strong>Brews on Google Drive: </strong>{accountDetails.googleCount ?? ( | ||
<> | ||
Unable to retrieve files - <a href='https://github.com/naturalcrit/homebrewery/discussions/1580'>follow these steps to renew your Google credentials.</a> | ||
</> | ||
)} | ||
</p> | ||
)} | ||
</div> | ||
<div className='dataGroup'> | ||
<h4>Default Save Location</h4> | ||
{renderSaveLocationButton('Homebrewery', 'HOMEBREWERY')} | ||
{renderSaveLocationButton('Google Drive', 'GOOGLE-DRIVE', accountDetails.googleId)} | ||
</div> | ||
</> | ||
); | ||
}; | ||
|
||
render : function(){ | ||
return <UIPage brew={this.props.brew}> | ||
{this.renderUiItems()} | ||
</UIPage>; | ||
} | ||
}); | ||
// return the account page inside the base layout wrapper (with navbar etc). | ||
return ( | ||
<UIPage brew={brew}> | ||
{renderAccountPage()} | ||
</UIPage>); | ||
}; | ||
|
||
module.exports = AccountPage; |
Oops, something went wrong.