\S+)/i);
@@ -97,7 +91,7 @@ const refreshAssignees = () => {
} else {
$(el).append(`
`);
}
@@ -159,27 +153,19 @@ export default function () {
}
allreadySetup = true;
- let refreshPickerTimeoutID;
- let refreshAssigneesTimeoutID;
+ // Draw them once when the page is loaded
setTimeout(refreshPicker, 500);
setTimeout(refreshAssignees, 500);
- // Listen for when the sidebar is redrawn, then redraw our pickers
- $(document).bind('DOMNodeRemoved', (e) => {
- if ($(e.target).hasClass('sidebar-assignee')) {
- // Make sure that only one setTimeout runs at a time
- clearTimeout(refreshAssigneesTimeoutID);
- refreshAssigneesTimeoutID = setTimeout(refreshAssignees, 500);
+ // Every second, check to see if the pickers are still there, and if not, redraw them
+ setInterval(() => {
+ if (!$('.k2picker-wrapper').length) {
+ refreshPicker();
}
-
- if ($(e.target).is('#partial-discussion-sidebar')) {
- // Make sure that only one setTimeout runs at a time
- clearTimeout(refreshPickerTimeoutID);
- refreshPickerTimeoutID = setTimeout(refreshPicker, 500);
- clearTimeout(refreshAssigneesTimeoutID);
- refreshAssigneesTimeoutID = setTimeout(refreshAssignees, 500);
+ if (!$('.js-issue-assignees .k2-element').length) {
+ refreshAssignees();
}
- });
+ }, 1000);
};
return IssuePage;
diff --git a/src/js/module/dashboard/Legend.js b/src/js/module/dashboard/Legend.js
index fc9551bb..ed552205 100644
--- a/src/js/module/dashboard/Legend.js
+++ b/src/js/module/dashboard/Legend.js
@@ -46,6 +46,11 @@ function Legend() {
{' '}
Issue owner
+
+ ☆
+ {' '}
+ Issue is owned by someone else
+
I
{' '}
diff --git a/src/js/module/dashboard/ListIssuesAssigned.js b/src/js/module/dashboard/ListIssuesAssigned.js
index 6f44f6be..6c8392ec 100644
--- a/src/js/module/dashboard/ListIssuesAssigned.js
+++ b/src/js/module/dashboard/ListIssuesAssigned.js
@@ -24,9 +24,11 @@ class ListIssuesAssigned extends React.Component {
this.state = {shouldHideHeldIssues: false};
this.state = {shouldHideUnderReviewIssues: false};
+ this.state = {shouldHideOwnedBySomeoneElseIssues: false};
this.fetch = this.fetch.bind(this);
this.toggleHeldFilter = this.toggleHeldFilter.bind(this);
this.toggleUnderReviewFilter = this.toggleUnderReviewFilter.bind(this);
+ this.toggleOwnedBySomeoneElseFilter = this.toggleOwnedBySomeoneElseFilter.bind(this);
}
componentDidMount() {
@@ -56,6 +58,10 @@ class ListIssuesAssigned extends React.Component {
this.setState(prevState => ({shouldHideUnderReviewIssues: !prevState.shouldHideUnderReviewIssues}));
}
+ toggleOwnedBySomeoneElseFilter() {
+ this.setState(prevState => ({shouldHideOwnedBySomeoneElseIssues: !prevState.shouldHideOwnedBySomeoneElseIssues}));
+ }
+
render() {
if (!this.props.issues) {
return (
@@ -90,6 +96,12 @@ class ListIssuesAssigned extends React.Component {
Under Review
+
+
+
@@ -100,6 +112,7 @@ class ListIssuesAssigned extends React.Component {
data={_.pick(this.props.issues, issue => _.findWhere(issue.labels, {name: 'Hourly'}))}
hideIfHeld={this.state.shouldHideHeldIssues}
hideIfUnderReview={this.state.shouldHideUnderReviewIssues}
+ hideIfOwnedBySomeoneElse={this.state.shouldHideOwnedBySomeoneElseIssues}
/>
@@ -109,6 +122,7 @@ class ListIssuesAssigned extends React.Component {
data={_.pick(this.props.issues, issue => _.findWhere(issue.labels, {name: 'Daily'}))}
hideIfHeld={this.state.shouldHideHeldIssues}
hideIfUnderReview={this.state.shouldHideUnderReviewIssues}
+ hideIfOwnedBySomeoneElse={this.state.shouldHideOwnedBySomeoneElseIssues}
/>
@@ -118,6 +132,7 @@ class ListIssuesAssigned extends React.Component {
data={_.pick(this.props.issues, issue => _.findWhere(issue.labels, {name: 'Weekly'}))}
hideIfHeld={this.state.shouldHideHeldIssues}
hideIfUnderReview={this.state.shouldHideUnderReviewIssues}
+ hideIfOwnedBySomeoneElse={this.state.shouldHideOwnedBySomeoneElseIssues}
/>
@@ -127,6 +142,7 @@ class ListIssuesAssigned extends React.Component {
data={_.pick(this.props.issues, issue => _.findWhere(issue.labels, {name: 'Monthly'}))}
hideIfHeld={this.state.shouldHideHeldIssues}
hideIfUnderReview={this.state.shouldHideUnderReviewIssues}
+ hideIfOwnedBySomeoneElse={this.state.shouldHideOwnedBySomeoneElseIssues}
/>
@@ -139,6 +155,7 @@ class ListIssuesAssigned extends React.Component {
data={_.pick(this.props.issues, issue => _.intersection(_.map(issue.labels, label => label.name), ['Hourly', 'Daily', 'Weekly', 'Monthly']).length === 0)}
hideIfHeld={this.state.shouldHideHeldIssues}
hideIfUnderReview={this.state.shouldHideUnderReviewIssues}
+ hideIfOwnedBySomeoneElse={this.state.shouldHideOwnedBySomeoneElseIssues}
/>
diff --git a/tools/checkRuntimeVersions.sh b/tools/checkRuntimeVersions.sh
index 5ebb0894..abe64ef8 100755
--- a/tools/checkRuntimeVersions.sh
+++ b/tools/checkRuntimeVersions.sh
@@ -2,8 +2,8 @@
installedNodeVersion="$(node -v)"
installedNpmVersion="$(npm -v)"
-desiredNodeVersion="v20.10.0"
-desiredNpmVersion="10.2.3"
+desiredNodeVersion="v20.15.1"
+desiredNpmVersion="10.7.0"
if [[ "$installedNodeVersion" != "$desiredNodeVersion" ]]; then
echo "⚠️ [ERROR] Wrong version of node installed! You are currently running $installedNodeVersion. Please install node $desiredNodeVersion from https://nodejs.org/en/download/releases/"
diff --git a/webpack.common.js b/webpack.common.js
index 211da34c..90ffc8d5 100644
--- a/webpack.common.js
+++ b/webpack.common.js
@@ -5,87 +5,102 @@ const MiniCssExtractPlugin = require('mini-css-extract-plugin');
const {IgnorePlugin} = require('webpack');
const ESLintPlugin = require('eslint-webpack-plugin');
-module.exports = {
- context: path.resolve(__dirname, '.'),
- entry: {
- content: './src/js/content.js',
- events: './src/js/events.js',
- },
- output: {
- filename: '[name].js',
- path: path.resolve(__dirname, 'dist'),
- },
- resolve: {
- extensions: ['.jsx', '.js'],
- },
+module.exports = (env) => {
+ const isFirefox = env && env.platform === 'firefox';
- plugins: [
- new CleanWebpackPlugin(),
- new MiniCssExtractPlugin(),
+ return {
+ context: path.resolve(__dirname, '.'),
+ entry: {
+ content: './src/js/content.js',
+ events: './src/js/events.js',
+ },
+ output: {
+ filename: '[name].js',
+ path: path.resolve(__dirname, 'dist'),
+ },
+ resolve: {
+ extensions: ['.jsx', '.js'],
+ },
- // This is necessary because when moment.js is imported, it require()s some locale files which aren't needed and this results
- // in console errors. By ignoring those imports, it allows everything to work without errors. More can be read about this here:
- // https://webpack.js.org/plugins/ignore-plugin/#example-of-ignoring-moment-locales
- new IgnorePlugin({
- resourceRegExp: /^\.\/locale$/,
- }),
+ plugins: [
+ new CleanWebpackPlugin(),
+ new MiniCssExtractPlugin(),
- new ESLintPlugin({
- cache: false,
- emitWarning: true,
- overrideConfigFile: path.resolve(__dirname, '.eslintrc.js'),
- }),
+ // This is necessary because when moment.js is imported, it require()s some locale files which aren't needed and this results
+ // in console errors. By ignoring those imports, it allows everything to work without errors. More can be read about this here:
+ // https://webpack.js.org/plugins/ignore-plugin/#example-of-ignoring-moment-locales
+ new IgnorePlugin({
+ resourceRegExp: /^\.\/locale$/,
+ }),
- // Copies icons and manifest file into our dist folder
- new CopyPlugin({
- patterns: [
- {from: './assets/', to: path.resolve(__dirname, 'dist')}
- ]
- }),
- ],
+ new ESLintPlugin({
+ cache: false,
+ emitWarning: true,
+ overrideConfigFile: path.resolve(__dirname, '.eslintrc.js'),
+ }),
- module: {
- rules: [
- // Load .html files as strings, used for underscore templates
- {
- test: /\.html$/i,
- use: 'underscore-template-loader'
- },
+ // Conditional copy of manifest files and other assets
+ new CopyPlugin({
+ patterns: [
+ {
+ from: './assets/',
+ to: path.resolve(__dirname, 'dist'),
+ globOptions: {
+ ignore: ['**/manifest*.json'], // Ignore all manifest*.json files
+ },
+ },
+ {
+ // Conditionally copy the manifest based on platform
+ from: isFirefox ? './assets/manifest-firefox.json' : './assets/manifest.json',
+ to: path.resolve(__dirname, 'dist/manifest.json'),
+ },
+ ],
+ }),
+ ],
- // Transpiles ES6 and JSX
- {
- test: /\.js$/,
- use: {
- loader: 'babel-loader',
+ module: {
+ rules: [
+ // Load .html files as strings, used for underscore templates
+ {
+ test: /\.html$/i,
+ use: 'underscore-template-loader'
},
- /**
- * Exclude node_modules except two packages we need to convert for rendering HTML because they import
- * "react-native" internally and use JSX which we need to convert to JS for the browser.
- *
- * You can remove something from this list if it doesn't use JSX/JS that needs to be transformed by babel.
- */
- include: [
- path.resolve(__dirname, 'src'),
- path.resolve(__dirname, 'node_modules/react-native-onyx'),
- ],
- exclude: [
- path.resolve(__dirname, 'node_modules/react-native-onyx/node_modules'),
- ],
- },
- {
- test: /\.s[ac]ss$/i,
- use: [
- // Outputs the generated CSS to the dist folder
- MiniCssExtractPlugin.loader,
+ // Transpiles ES6 and JSX
+ {
+ test: /\.js$/,
+ use: {
+ loader: 'babel-loader',
+ },
- // Translates CSS into CommonJS
- 'css-loader',
+ /**
+ * Exclude node_modules except two packages we need to convert for rendering HTML because they import
+ * "react-native" internally and use JSX which we need to convert to JS for the browser.
+ *
+ * You can remove something from this list if it doesn't use JSX/JS that needs to be transformed by babel.
+ */
+ include: [
+ path.resolve(__dirname, 'src'),
+ path.resolve(__dirname, 'node_modules/react-native-onyx'),
+ ],
+ exclude: [
+ path.resolve(__dirname, 'node_modules/react-native-onyx/node_modules'),
+ ],
+ },
+ {
+ test: /\.s[ac]ss$/i,
+ use: [
+ // Outputs the generated CSS to the dist folder
+ MiniCssExtractPlugin.loader,
- // Compiles Sass to CSS
- 'sass-loader',
- ],
- },
- ]
- },
+ // Translates CSS into CommonJS
+ 'css-loader',
+
+ // Compiles Sass to CSS
+ 'sass-loader',
+ ],
+ },
+ ]
+ },
+ };
};
diff --git a/webpack.dev.js b/webpack.dev.js
index 696b65c0..3a20f125 100644
--- a/webpack.dev.js
+++ b/webpack.dev.js
@@ -1,7 +1,7 @@
const {merge} = require('webpack-merge');
const common = require('./webpack.common.js');
-module.exports = merge(common, {
+module.exports = (env) => merge(common(env), {
mode: 'development',
devtool: 'inline-source-map',
watch: true,
diff --git a/webpack.prod.js b/webpack.prod.js
index 6dd931a8..42648fc8 100644
--- a/webpack.prod.js
+++ b/webpack.prod.js
@@ -1,6 +1,6 @@
const {merge} = require('webpack-merge');
const common = require('./webpack.common.js');
-module.exports = merge(common, {
- mode: 'production',
+module.exports = (env) => merge(common(env), {
+ mode: 'production',
});