Project import generated by Copybara.

GitOrigin-RevId: d9e9e3fb4e31372ec1fb43b178994ca78fa8fe70
diff --git a/static_src/elements/framework/mr-star/mr-project-star.js b/static_src/elements/framework/mr-star/mr-project-star.js
new file mode 100644
index 0000000..14b2c73
--- /dev/null
+++ b/static_src/elements/framework/mr-star/mr-project-star.js
@@ -0,0 +1,148 @@
+// Copyright 2020 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+import {connectStore, store} from 'reducers/base.js';
+import * as users from 'reducers/users.js';
+import {stars} from 'reducers/stars.js';
+import {projectAndUserToStarName} from 'shared/converters.js';
+import {MrStar} from './mr-star.js';
+import 'shared/typedef.js';
+
+
+/**
+ * `<mr-project-star>`
+ *
+ * A button for starring a project.
+ *
+ */
+export class MrProjectStar extends connectStore(MrStar) {
+  /** @override */
+  static get properties() {
+    return {
+      /**
+       * Resource name of the project being starred.
+       */
+      name: {type: String},
+      /**
+       * List of all stars, indexed by star name.
+       */
+      _stars: {type: Object},
+      /**
+       * Whether project stars are currently being fetched.
+       */
+      _fetchingStars: {type: Boolean},
+      /**
+       * Request data for projects currently being starred.
+       */
+      _starringProjects: {type: Object},
+      /**
+       * Request data for projects currently being unstarred.
+       */
+      _unstarringProjects: {type: Object},
+      /**
+       * The currently logged in user. Required to determine if the user can
+       * star.
+       */
+      _currentUserName: {type: String},
+    };
+  }
+
+  /** @override */
+  constructor() {
+    super();
+    /** @type {string} */
+    this.name = undefined;
+
+    /** @type {boolean} */
+    this._fetchingStars = false;
+
+    /** @type {Object<ProjectStarName, ReduxRequestState>} */
+    this._starringProjects = {};
+
+    /** @type {Object<ProjectStarName, ReduxRequestState>} */
+    this._unstarringProjects = {};
+
+    /** @type {Object<StarName, Star>} */
+    this._stars = {};
+
+    /** @type {string} */
+    this._currentUserName = undefined;
+  }
+
+  /** @override */
+  stateChanged(state) {
+    this._currentUserName = users.currentUserName(state);
+
+    this._stars = stars.byName(state);
+
+    const requests = stars.requests(state);
+    this._fetchingStars = requests.listProjects.requesting;
+    this._starringProjects = requests.starProject;
+    this._unstarringProjects = requests.unstarProject;
+  }
+
+  /** @override */
+  get type() {
+    return 'project';
+  }
+
+  /**
+   * @return {string} The resource name of the ProjectStar.
+   */
+  get _starName() {
+    return projectAndUserToStarName(this.name, this._currentUserName);
+  }
+
+  /**
+   * @return {ProjectStar} The ProjectStar object for the referenced project,
+   *   if one exists.
+   */
+  get _projectStar() {
+    const name = this._starName;
+    if (!(name in this._stars)) return {};
+    return this._stars[name];
+  }
+
+  /**
+   * @return {boolean} Whether there's an in-flight star request.
+   */
+  get _isStarring() {
+    const requestKey = this._starName;
+    if (requestKey in this._starringProjects &&
+        this._starringProjects[requestKey].requesting) {
+      return true;
+    }
+    if (requestKey in this._unstarringProjects &&
+        this._unstarringProjects[requestKey].requesting) {
+      return true;
+    }
+    return false;
+  }
+
+  /** @override */
+  get isLoggedIn() {
+    return !!this._currentUserName;
+  }
+
+  /** @override */
+  get requesting() {
+    return this._fetchingStars || this._isStarring;
+  }
+
+  /** @override */
+  get isStarred() {
+    return !!(this._projectStar && this._projectStar.name);
+  }
+
+  /** @override */
+  star() {
+    store.dispatch(stars.starProject(this.name, this._currentUserName));
+  }
+
+  /** @override */
+  unstar() {
+    store.dispatch(stars.unstarProject(this.name, this._currentUserName));
+  }
+}
+
+customElements.define('mr-project-star', MrProjectStar);