Project import generated by Copybara.

GitOrigin-RevId: d9e9e3fb4e31372ec1fb43b178994ca78fa8fe70
diff --git a/static_src/elements/issue-detail/dialogs/mr-convert-issue/mr-convert-issue.js b/static_src/elements/issue-detail/dialogs/mr-convert-issue/mr-convert-issue.js
new file mode 100644
index 0000000..8da3083
--- /dev/null
+++ b/static_src/elements/issue-detail/dialogs/mr-convert-issue/mr-convert-issue.js
@@ -0,0 +1,186 @@
+// Copyright 2019 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 {LitElement, html, css} from 'lit-element';
+
+import {store, connectStore} from 'reducers/base.js';
+import * as issueV0 from 'reducers/issueV0.js';
+import * as projectV0 from 'reducers/projectV0.js';
+import 'elements/chops/chops-button/chops-button.js';
+import 'elements/chops/chops-dialog/chops-dialog.js';
+import 'elements/framework/mr-error/mr-error.js';
+import {SHARED_STYLES} from 'shared/shared-styles.js';
+
+// TODO(zhangtiff): Make dialog components subclass chops-dialog instead of
+// using slots/containment once we switch to LitElement.
+/**
+ * `<mr-convert-issue>`
+ *
+ * This allows a user to update the structure of an issue to that of
+ * a chosen project template.
+ *
+ */
+export class MrConvertIssue extends connectStore(LitElement) {
+  /** @override */
+  static get styles() {
+    return [
+      SHARED_STYLES,
+      css`
+        label {
+          font-weight: bold;
+          text-align: right;
+        }
+        form {
+          padding: 1em 8px;
+          display: block;
+          font-size: var(--chops-main-font-size);
+        }
+        textarea {
+          font-family: var(--mr-toggled-font-family);
+          min-height: 80px;
+          border: var(--chops-accessible-border);
+          padding: 0.5em 4px;
+        }
+        .edit-actions {
+          width: 100%;
+          margin: 0.5em 0;
+          text-align: right;
+        }
+      `,
+    ];
+  }
+
+  /** @override */
+  render() {
+    return html`
+      <link href="https://fonts.googleapis.com/icon?family=Material+Icons" rel="stylesheet">
+      <chops-dialog closeOnOutsideClick>
+        <h3 class="medium-heading">Convert issue to new template structure</h3>
+        <form id="convertIssueForm">
+          <div class="input-grid">
+            <label for="templateInput">Pick a template: </label>
+            <select id="templateInput" @change=${this._templateInputChanged}>
+              <option value="">--Please choose a project template--</option>
+              ${this.projectTemplates.map((projTempl) => html`
+                <option value=${projTempl.templateName}>
+                  ${projTempl.templateName}
+                </option>`)}
+            </select>
+            <label for="commentContent">Comment: </label>
+            <textarea id="commentContent" placeholder="Add a comment"></textarea>
+            <span></span>
+            <chops-checkbox
+              @checked-change=${this._sendEmailChecked}
+              checked=${this.sendEmail}
+            >Send email</chops-checkbox>
+          </div>
+          <mr-error ?hidden=${!this.convertIssueError}>
+            ${this.convertIssueError && this.convertIssueError.description}
+          </mr-error>
+          <div class="edit-actions">
+            <chops-button @click=${this.close} class="de-emphasized discard-button">
+              Discard
+            </chops-button>
+            <chops-button @click=${this.save} class="emphasized" ?disabled=${!this.selectedTemplate}>
+              Convert issue
+            </chops-button>
+          </div>
+        </form>
+      </chops-dialog>
+    `;
+  }
+
+  /** @override */
+  static get properties() {
+    return {
+      convertingIssue: {
+        type: Boolean,
+      },
+      convertIssueError: {
+        type: Object,
+      },
+      issuePermissions: {
+        type: Object,
+      },
+      issueRef: {
+        type: Object,
+      },
+      projectTemplates: {
+        type: Array,
+      },
+      selectedTemplate: {
+        type: String,
+      },
+      sendEmail: {
+        type: Boolean,
+      },
+    };
+  }
+
+  /** @override */
+  stateChanged(state) {
+    this.convertingIssue = issueV0.requests(state).convert.requesting;
+    this.convertIssueError = issueV0.requests(state).convert.error;
+    this.issueRef = issueV0.viewedIssueRef(state);
+    this.issuePermissions = issueV0.permissions(state);
+    this.projectTemplates = projectV0.viewedTemplates(state);
+  }
+
+  /** @override */
+  constructor() {
+    super();
+    this.selectedTemplate = '';
+    this.sendEmail = true;
+  }
+
+  /** @override */
+  updated(changedProperties) {
+    if (changedProperties.has('convertingIssue')) {
+      if (!this.convertingIssue && !this.convertIssueError) {
+        this.close();
+      }
+    }
+  }
+
+  open() {
+    this.reset();
+    const dialog = this.shadowRoot.querySelector('chops-dialog');
+    dialog.open();
+  }
+
+  close() {
+    const dialog = this.shadowRoot.querySelector('chops-dialog');
+    dialog.close();
+  }
+
+  /**
+   * Resets the user's input.
+   */
+  reset() {
+    this.shadowRoot.querySelector('#convertIssueForm').reset();
+  }
+
+  /**
+   * Dispatches a Redux action to convert the issue to a new template.
+   */
+  save() {
+    const commentContent = this.shadowRoot.querySelector('#commentContent');
+    store.dispatch(issueV0.convert(this.issueRef, {
+      templateName: this.selectedTemplate,
+      commentContent: commentContent.value,
+      sendEmail: this.sendEmail,
+    }));
+  }
+
+  _sendEmailChecked(evt) {
+    this.sendEmail = evt.detail.checked;
+  }
+
+  _templateInputChanged() {
+    this.selectedTemplate = this.shadowRoot.querySelector(
+        '#templateInput').value;
+  }
+}
+
+customElements.define('mr-convert-issue', MrConvertIssue);
diff --git a/static_src/elements/issue-detail/dialogs/mr-convert-issue/mr-convert-issue.test.js b/static_src/elements/issue-detail/dialogs/mr-convert-issue/mr-convert-issue.test.js
new file mode 100644
index 0000000..b68e274
--- /dev/null
+++ b/static_src/elements/issue-detail/dialogs/mr-convert-issue/mr-convert-issue.test.js
@@ -0,0 +1,30 @@
+// Copyright 2019 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 {assert} from 'chai';
+import {MrConvertIssue} from './mr-convert-issue.js';
+
+let element;
+
+describe('mr-convert-issue', () => {
+  beforeEach(() => {
+    element = document.createElement('mr-convert-issue');
+    document.body.appendChild(element);
+  });
+
+  afterEach(() => {
+    document.body.removeChild(element);
+  });
+
+  it('initializes', () => {
+    assert.instanceOf(element, MrConvertIssue);
+  });
+
+  it('no template chosen', async () => {
+    await element.updateComplete;
+
+    const buttons = element.shadowRoot.querySelectorAll('chops-button');
+    assert.isTrue(buttons[buttons.length - 1].disabled);
+  });
+});