From 3c2270d52df982adbe0468bdeda4e7e70263ebe6 Mon Sep 17 00:00:00 2001 From: Ash Wilson Date: Fri, 30 Dec 2016 11:38:38 -0500 Subject: [PATCH 1/7] Test and implement Decoration --- lib/views/decoration.js | 110 +++++++++++++++++++++++++++++++++ test/views/decoration.test.js | 111 ++++++++++++++++++++++++++++++++++ 2 files changed, 221 insertions(+) create mode 100644 lib/views/decoration.js create mode 100644 test/views/decoration.test.js diff --git a/lib/views/decoration.js b/lib/views/decoration.js new file mode 100644 index 0000000000..d31e4f36a6 --- /dev/null +++ b/lib/views/decoration.js @@ -0,0 +1,110 @@ +/** @babel */ + +import React from 'react'; +import {CompositeDisposable} from 'atom'; + +import Portal from './portal'; + +export default class Decoration extends React.Component { + static propTypes = { + editor: React.PropTypes.object.isRequired, + marker: React.PropTypes.object.isRequired, + type: React.PropTypes.oneOf(['line', 'line-number', 'highlight', 'overlay', 'gutter', 'block']).isRequired, + position: React.PropTypes.oneOf(['head', 'tail']), + class: React.PropTypes.string, + children: React.PropTypes.element, + getItem: React.PropTypes.func, + options: React.PropTypes.object, + } + + static defaultProps = { + options: {}, + position: 'head', + getItem: ({portal, subtree}) => subtree, + } + + constructor(props, context) { + super(props, context); + + this.decoration = null; + this.subscriptions = new CompositeDisposable(); + } + + usesItem() { + return this.props.type === 'gutter' || this.props.type === 'overlay' || this.props.type === 'block'; + } + + componentWillReceiveProps(nextProps) { + let recreationRequired = this.props.editor !== nextProps.editor || + this.props.marker !== nextProps.marker || + this.props.type !== nextProps.type || + this.props.position !== nextProps.position || + this.props.class !== nextProps.class || + this.props.getItem !== nextProps.getItem || + this.props.children !== nextProps.children; + + if (!recreationRequired) { + // Compare additional options. + const optionKeys = Object.keys(this.props.options); + const nextOptionKeys = Object.keys(nextProps.options); + + if (optionKeys.length !== nextOptionKeys.length) { + recreationRequired = true; + } else { + for (let i = 0; i < optionKeys.length; i++) { + const key = optionKeys[i]; + if (this.props.options[key] !== nextProps.options[key]) { + recreationRequired = true; + break; + } + } + } + } + + if (recreationRequired) { + this.decoration && this.decoration.destroy(); + this.setupDecoration(); + } + } + + componentDidMount() { + this.setupDecoration(); + } + + render() { + if (this.usesItem()) { + return { this.portal = c; }}>{this.props.children}; + } else { + return null; + } + } + + setupDecoration() { + if (this.decoration) { + return; + } + + let item = null; + if (this.usesItem()) { + item = this.props.getItem({portal: this.portal, subtree: this.portal.getRenderedSubtree()}); + } + + const options = { + ...this.props.options, + type: this.props.type, + position: this.props.position, + class: this.props.class, + item, + }; + + this.decoration = this.props.editor.decorateMarker(this.props.marker, options); + this.subscriptions.add(this.decoration.onDidDestroy(() => { + this.decoration = null; + })); + } + + componentWillUnmount() { + this.decoration && this.decoration.destroy(); + this.subscriptions.dispose(); + } +} diff --git a/test/views/decoration.test.js b/test/views/decoration.test.js new file mode 100644 index 0000000000..72af13e498 --- /dev/null +++ b/test/views/decoration.test.js @@ -0,0 +1,111 @@ +/** @babel */ + +import React from 'react'; +import sinon from 'sinon'; +import {mount} from 'enzyme'; + +import Decoration from '../../lib/views/decoration'; + +describe('Decoration', () => { + let atomEnv, editor, marker; + + beforeEach(async () => { + atomEnv = global.buildAtomEnvironment(); + const workspace = atomEnv.workspace; + + editor = await workspace.open(__filename); + marker = editor.markBufferRange([[2, 0], [6, 0]]); + }); + + afterEach(() => atomEnv.destroy()); + + it('decorates its marker on render', () => { + const app = ( + + ); + mount(app); + + assert.lengthOf(editor.getLineDecorations({position: 'head', class: 'something'}), 1); + }); + + describe('with a subtree', () => { + beforeEach(() => { + sinon.spy(editor, 'decorateMarker'); + }); + + it('creates a block decoration', () => { + const app = ( + +
+ This is a subtree +
+
+ ); + mount(app); + + const args = editor.decorateMarker.firstCall.args; + assert.equal(args[0], marker); + assert.equal(args[1].type, 'block'); + assert.equal(args[1].item.className, 'decoration-subtree'); + assert.equal(args[1].item.textContent, 'This is a subtree'); + }); + + it('creates an overlay decoration', () => { + const app = ( + +
+ This is a subtree +
+
+ ); + mount(app); + + const args = editor.decorateMarker.firstCall.args; + assert.equal(args[0], marker); + assert.equal(args[1].type, 'overlay'); + assert.equal(args[1].item.className, 'decoration-subtree'); + assert.equal(args[1].item.textContent, 'This is a subtree'); + }); + + it('creates a gutter decoration', () => { + const app = ( + +
+ This is a subtree +
+
+ ); + mount(app); + + const args = editor.decorateMarker.firstCall.args; + assert.equal(args[0], marker); + assert.equal(args[1].type, 'gutter'); + assert.equal(args[1].item.className, 'decoration-subtree'); + assert.equal(args[1].item.textContent, 'This is a subtree'); + }); + }); + + it('destroys its decoration on unmount', () => { + const app = ( + + ); + const wrapper = mount(app); + + assert.lengthOf(editor.getLineDecorations({class: 'whatever'}), 1); + + wrapper.unmount(); + + assert.lengthOf(editor.getLineDecorations({class: 'whatever'}), 0); + }); +}); From 79f83ba7bd5315c5a14a27ecfeb78d45e91aeced Mon Sep 17 00:00:00 2001 From: Ash Wilson Date: Mon, 30 Jan 2017 09:29:36 -0500 Subject: [PATCH 2/7] :fire: babel comment --- lib/views/decoration.js | 2 -- 1 file changed, 2 deletions(-) diff --git a/lib/views/decoration.js b/lib/views/decoration.js index d31e4f36a6..c7e436faec 100644 --- a/lib/views/decoration.js +++ b/lib/views/decoration.js @@ -1,5 +1,3 @@ -/** @babel */ - import React from 'react'; import {CompositeDisposable} from 'atom'; From 3ab3dc926beae79684f6753102006857666b528c Mon Sep 17 00:00:00 2001 From: Ash Wilson Date: Mon, 30 Jan 2017 09:41:01 -0500 Subject: [PATCH 3/7] Default getItem() to return the portal element --- lib/views/decoration.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/views/decoration.js b/lib/views/decoration.js index c7e436faec..18605c6347 100644 --- a/lib/views/decoration.js +++ b/lib/views/decoration.js @@ -18,7 +18,7 @@ export default class Decoration extends React.Component { static defaultProps = { options: {}, position: 'head', - getItem: ({portal, subtree}) => subtree, + getItem: ({portal, subtree}) => portal, } constructor(props, context) { From 68f186a958951cc461a2cc224b87b780042fd42d Mon Sep 17 00:00:00 2001 From: Ash Wilson Date: Mon, 30 Jan 2017 10:05:41 -0500 Subject: [PATCH 4/7] Another babel comment :fire: --- test/views/decoration.test.js | 2 -- 1 file changed, 2 deletions(-) diff --git a/test/views/decoration.test.js b/test/views/decoration.test.js index 72af13e498..2b09a5952c 100644 --- a/test/views/decoration.test.js +++ b/test/views/decoration.test.js @@ -1,5 +1,3 @@ -/** @babel */ - import React from 'react'; import sinon from 'sinon'; import {mount} from 'enzyme'; From 21139169121e1fd950101c2f2a850324e6166976 Mon Sep 17 00:00:00 2001 From: Ash Wilson Date: Mon, 30 Jan 2017 11:32:26 -0500 Subject: [PATCH 5/7] Default getItem() to returning the portal --- lib/views/decoration.js | 2 +- test/views/decoration.test.js | 15 +++++++++------ 2 files changed, 10 insertions(+), 7 deletions(-) diff --git a/lib/views/decoration.js b/lib/views/decoration.js index 18605c6347..4497a06569 100644 --- a/lib/views/decoration.js +++ b/lib/views/decoration.js @@ -18,7 +18,7 @@ export default class Decoration extends React.Component { static defaultProps = { options: {}, position: 'head', - getItem: ({portal, subtree}) => portal, + getItem: ({portal, subtree}) => portal.node, } constructor(props, context) { diff --git a/test/views/decoration.test.js b/test/views/decoration.test.js index 2b09a5952c..7146206536 100644 --- a/test/views/decoration.test.js +++ b/test/views/decoration.test.js @@ -50,8 +50,9 @@ describe('Decoration', () => { const args = editor.decorateMarker.firstCall.args; assert.equal(args[0], marker); assert.equal(args[1].type, 'block'); - assert.equal(args[1].item.className, 'decoration-subtree'); - assert.equal(args[1].item.textContent, 'This is a subtree'); + const child = args[1].item.firstElementChild; + assert.equal(child.className, 'decoration-subtree'); + assert.equal(child.textContent, 'This is a subtree'); }); it('creates an overlay decoration', () => { @@ -67,8 +68,9 @@ describe('Decoration', () => { const args = editor.decorateMarker.firstCall.args; assert.equal(args[0], marker); assert.equal(args[1].type, 'overlay'); - assert.equal(args[1].item.className, 'decoration-subtree'); - assert.equal(args[1].item.textContent, 'This is a subtree'); + const child = args[1].item.firstElementChild; + assert.equal(child.className, 'decoration-subtree'); + assert.equal(child.textContent, 'This is a subtree'); }); it('creates a gutter decoration', () => { @@ -84,8 +86,9 @@ describe('Decoration', () => { const args = editor.decorateMarker.firstCall.args; assert.equal(args[0], marker); assert.equal(args[1].type, 'gutter'); - assert.equal(args[1].item.className, 'decoration-subtree'); - assert.equal(args[1].item.textContent, 'This is a subtree'); + const child = args[1].item.firstElementChild; + assert.equal(child.className, 'decoration-subtree'); + assert.equal(child.textContent, 'This is a subtree'); }); }); From c4869d6739d8bb258077e6b1f2eabfc46299cc0c Mon Sep 17 00:00:00 2001 From: Ash Wilson Date: Mon, 30 Jan 2017 11:40:04 -0500 Subject: [PATCH 6/7] Return the Portal --- lib/views/decoration.js | 2 +- test/views/decoration.test.js | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/lib/views/decoration.js b/lib/views/decoration.js index 4497a06569..18605c6347 100644 --- a/lib/views/decoration.js +++ b/lib/views/decoration.js @@ -18,7 +18,7 @@ export default class Decoration extends React.Component { static defaultProps = { options: {}, position: 'head', - getItem: ({portal, subtree}) => portal.node, + getItem: ({portal, subtree}) => portal, } constructor(props, context) { diff --git a/test/views/decoration.test.js b/test/views/decoration.test.js index 7146206536..6747c15db3 100644 --- a/test/views/decoration.test.js +++ b/test/views/decoration.test.js @@ -50,7 +50,7 @@ describe('Decoration', () => { const args = editor.decorateMarker.firstCall.args; assert.equal(args[0], marker); assert.equal(args[1].type, 'block'); - const child = args[1].item.firstElementChild; + const child = args[1].item.node.firstElementChild; assert.equal(child.className, 'decoration-subtree'); assert.equal(child.textContent, 'This is a subtree'); }); @@ -68,7 +68,7 @@ describe('Decoration', () => { const args = editor.decorateMarker.firstCall.args; assert.equal(args[0], marker); assert.equal(args[1].type, 'overlay'); - const child = args[1].item.firstElementChild; + const child = args[1].item.node.firstElementChild; assert.equal(child.className, 'decoration-subtree'); assert.equal(child.textContent, 'This is a subtree'); }); @@ -86,7 +86,7 @@ describe('Decoration', () => { const args = editor.decorateMarker.firstCall.args; assert.equal(args[0], marker); assert.equal(args[1].type, 'gutter'); - const child = args[1].item.firstElementChild; + const child = args[1].item.node.firstElementChild; assert.equal(child.className, 'decoration-subtree'); assert.equal(child.textContent, 'This is a subtree'); }); From 89ee1f1349624506038dbfbd1636c9a61c099498 Mon Sep 17 00:00:00 2001 From: Ash Wilson Date: Mon, 30 Jan 2017 12:48:18 -0500 Subject: [PATCH 7/7] :arrow_up: GraphQL schema --- graphql/schema.graphql | 56 +++++++++- graphql/schema.json | 234 +++++++++++++++++++++++++++++++++++++++++ 2 files changed, 289 insertions(+), 1 deletion(-) diff --git a/graphql/schema.graphql b/graphql/schema.graphql index 982da21ad8..4ae3e130ee 100644 --- a/graphql/schema.graphql +++ b/graphql/schema.graphql @@ -308,6 +308,12 @@ interface Comment { # Check if this comment was created via an email reply. createdViaEmail: Boolean! + # The user who edited the comment. + editor: User + + # The moment the editor made the last edit + lastEditedAt: DateTime + # Identifies the date and time when the object was last updated. updatedAt: DateTime! @@ -464,8 +470,14 @@ type CommitComment implements Node, Comment, Reactable, RepositoryNode { # Identifies the primary key from the database. databaseId: Int @deprecated(reason: "Exposed database IDs will eventually be removed in favor of global Relay IDs.") + + # The user who edited the comment. + editor: User id: ID! + # The moment the editor made the last edit + lastEditedAt: DateTime + # Are reaction live updates enabled for this subject. liveReactionUpdatesEnabled: Boolean! @@ -916,8 +928,14 @@ type GistComment implements Node, Comment { # Check if this comment was created via an email reply. createdViaEmail: Boolean! + + # The user who edited the comment. + editor: User id: ID! + # The moment the editor made the last edit + lastEditedAt: DateTime + # Identifies the date and time when the object was last updated. updatedAt: DateTime! @@ -1218,6 +1236,9 @@ type Issue implements Node, Comment, Issueish, Reactable, RepositoryNode, Timeli # Identifies the primary key from the database. databaseId: Int @deprecated(reason: "Exposed database IDs will eventually be removed in favor of global Relay IDs.") + + # The user who edited the comment. + editor: User id: ID! # A list of labels associated with the Issue or Pull Request. @@ -1235,6 +1256,9 @@ type Issue implements Node, Comment, Issueish, Reactable, RepositoryNode, Timeli before: String ): LabelConnection + # The moment the editor made the last edit + lastEditedAt: DateTime + # Are reaction live updates enabled for this subject. liveReactionUpdatesEnabled: Boolean! @@ -1363,11 +1387,17 @@ type IssueComment implements Node, Comment, Reactable, RepositoryNode { # Identifies the primary key from the database. databaseId: Int @deprecated(reason: "Exposed database IDs will eventually be removed in favor of global Relay IDs.") + + # The user who edited the comment. + editor: User id: ID! # Identifies the issue associated with the comment. issue: Issue! + # The moment the editor made the last edit + lastEditedAt: DateTime + # Are reaction live updates enabled for this subject. liveReactionUpdatesEnabled: Boolean! @@ -2644,6 +2674,9 @@ type PullRequest implements Node, Comment, Issueish, Reactable, RepositoryNode, # Identifies the primary key from the database. databaseId: Int @deprecated(reason: "Exposed database IDs will eventually be removed in favor of global Relay IDs.") + # The user who edited this pull request's body. + editor: User + # Identifies the head Ref associated with the pull request. headRef: Ref @@ -2666,6 +2699,9 @@ type PullRequest implements Node, Comment, Issueish, Reactable, RepositoryNode, before: String ): LabelConnection + # The moment the editor made the last edit + lastEditedAt: DateTime + # Are reaction live updates enabled for this subject. liveReactionUpdatesEnabled: Boolean! @@ -2866,8 +2902,14 @@ type PullRequestReview implements Node, Comment, RepositoryNode { # Identifies the primary key from the database. databaseId: Int @deprecated(reason: "Exposed database IDs will eventually be removed in favor of global Relay IDs.") + + # The user who edited the comment. + editor: User id: ID! + # The moment the editor made the last edit + lastEditedAt: DateTime + # The HTTP URL permalink for this PullRequestReview. path: URI! @@ -2930,8 +2972,14 @@ type PullRequestReviewComment implements Node, Comment, Reactable, RepositoryNod # The diff hunk to which the comment applies. diffHunk: String! + + # The user who edited the comment. + editor: User id: ID! + # The moment the editor made the last edit + lastEditedAt: DateTime + # Are reaction live updates enabled for this subject. liveReactionUpdatesEnabled: Boolean! @@ -3461,7 +3509,7 @@ type ReferencedEvent implements Node, IssueEvent { } # A release contains the content for a release. -type Release implements Node { +type Release implements Node, UniformResourceLocatable { # Identifies the description of the release. description: String id: ID! @@ -3469,6 +3517,9 @@ type Release implements Node { # Identifies the title of the release. name: String! + # The HTTP path for this issue + path: URI! + # List of releases assets which are dependent on this release. releaseAsset( # Returns the first _n_ elements from the list. @@ -3504,6 +3555,9 @@ type Release implements Node { # The Git tag the release points to tag: Ref + + # The HTTP url for this issue + url: URI! } # A release asset contains the content for a release asset. diff --git a/graphql/schema.json b/graphql/schema.json index 66f458803e..048e7ca97b 100644 --- a/graphql/schema.json +++ b/graphql/schema.json @@ -641,6 +641,18 @@ "isDeprecated": true, "deprecationReason": "Exposed database IDs will eventually be removed in favor of global Relay IDs." }, + { + "name": "editor", + "description": "The user who edited the comment.", + "args": [], + "type": { + "kind": "OBJECT", + "name": "User", + "ofType": null + }, + "isDeprecated": false, + "deprecationReason": null + }, { "name": "id", "description": null, @@ -710,6 +722,18 @@ "isDeprecated": false, "deprecationReason": null }, + { + "name": "lastEditedAt", + "description": "The moment the editor made the last edit", + "args": [], + "type": { + "kind": "SCALAR", + "name": "DateTime", + "ofType": null + }, + "isDeprecated": false, + "deprecationReason": null + }, { "name": "liveReactionUpdatesEnabled", "description": "Are reaction live updates enabled for this subject.", @@ -2850,6 +2874,22 @@ "isDeprecated": false, "deprecationReason": null }, + { + "name": "path", + "description": "The HTTP path for this issue", + "args": [], + "type": { + "kind": "NON_NULL", + "name": null, + "ofType": { + "kind": "SCALAR", + "name": "URI", + "ofType": null + } + }, + "isDeprecated": false, + "deprecationReason": null + }, { "name": "releaseAsset", "description": "List of releases assets which are dependent on this release.", @@ -2985,6 +3025,22 @@ }, "isDeprecated": false, "deprecationReason": null + }, + { + "name": "url", + "description": "The HTTP url for this issue", + "args": [], + "type": { + "kind": "NON_NULL", + "name": null, + "ofType": { + "kind": "SCALAR", + "name": "URI", + "ofType": null + } + }, + "isDeprecated": false, + "deprecationReason": null } ], "inputFields": null, @@ -2993,6 +3049,11 @@ "kind": "INTERFACE", "name": "Node", "ofType": null + }, + { + "kind": "INTERFACE", + "name": "UniformResourceLocatable", + "ofType": null } ], "enumValues": null, @@ -6254,6 +6315,18 @@ "isDeprecated": true, "deprecationReason": "Exposed database IDs will eventually be removed in favor of global Relay IDs." }, + { + "name": "editor", + "description": "The user who edited this pull request's body.", + "args": [], + "type": { + "kind": "OBJECT", + "name": "User", + "ofType": null + }, + "isDeprecated": false, + "deprecationReason": null + }, { "name": "headRef", "description": "Identifies the head Ref associated with the pull request.", @@ -6351,6 +6424,18 @@ "isDeprecated": false, "deprecationReason": null }, + { + "name": "lastEditedAt", + "description": "The moment the editor made the last edit", + "args": [], + "type": { + "kind": "SCALAR", + "name": "DateTime", + "ofType": null + }, + "isDeprecated": false, + "deprecationReason": null + }, { "name": "liveReactionUpdatesEnabled", "description": "Are reaction live updates enabled for this subject.", @@ -9799,6 +9884,18 @@ "isDeprecated": true, "deprecationReason": "Exposed database IDs will eventually be removed in favor of global Relay IDs." }, + { + "name": "editor", + "description": "The user who edited the comment.", + "args": [], + "type": { + "kind": "OBJECT", + "name": "User", + "ofType": null + }, + "isDeprecated": false, + "deprecationReason": null + }, { "name": "id", "description": null, @@ -9815,6 +9912,18 @@ "isDeprecated": false, "deprecationReason": null }, + { + "name": "lastEditedAt", + "description": "The moment the editor made the last edit", + "args": [], + "type": { + "kind": "SCALAR", + "name": "DateTime", + "ofType": null + }, + "isDeprecated": false, + "deprecationReason": null + }, { "name": "liveReactionUpdatesEnabled", "description": "Are reaction live updates enabled for this subject.", @@ -10212,6 +10321,30 @@ "isDeprecated": false, "deprecationReason": null }, + { + "name": "editor", + "description": "The user who edited the comment.", + "args": [], + "type": { + "kind": "OBJECT", + "name": "User", + "ofType": null + }, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "lastEditedAt", + "description": "The moment the editor made the last edit", + "args": [], + "type": { + "kind": "SCALAR", + "name": "DateTime", + "ofType": null + }, + "isDeprecated": false, + "deprecationReason": null + }, { "name": "updatedAt", "description": "Identifies the date and time when the object was last updated.", @@ -11186,6 +11319,18 @@ "isDeprecated": true, "deprecationReason": "Exposed database IDs will eventually be removed in favor of global Relay IDs." }, + { + "name": "editor", + "description": "The user who edited the comment.", + "args": [], + "type": { + "kind": "OBJECT", + "name": "User", + "ofType": null + }, + "isDeprecated": false, + "deprecationReason": null + }, { "name": "id", "description": null, @@ -11202,6 +11347,18 @@ "isDeprecated": false, "deprecationReason": null }, + { + "name": "lastEditedAt", + "description": "The moment the editor made the last edit", + "args": [], + "type": { + "kind": "SCALAR", + "name": "DateTime", + "ofType": null + }, + "isDeprecated": false, + "deprecationReason": null + }, { "name": "path", "description": "The HTTP URL permalink for this PullRequestReview.", @@ -11700,6 +11857,18 @@ "isDeprecated": false, "deprecationReason": null }, + { + "name": "editor", + "description": "The user who edited the comment.", + "args": [], + "type": { + "kind": "OBJECT", + "name": "User", + "ofType": null + }, + "isDeprecated": false, + "deprecationReason": null + }, { "name": "id", "description": null, @@ -11716,6 +11885,18 @@ "isDeprecated": false, "deprecationReason": null }, + { + "name": "lastEditedAt", + "description": "The moment the editor made the last edit", + "args": [], + "type": { + "kind": "SCALAR", + "name": "DateTime", + "ofType": null + }, + "isDeprecated": false, + "deprecationReason": null + }, { "name": "liveReactionUpdatesEnabled", "description": "Are reaction live updates enabled for this subject.", @@ -12353,6 +12534,18 @@ "isDeprecated": true, "deprecationReason": "Exposed database IDs will eventually be removed in favor of global Relay IDs." }, + { + "name": "editor", + "description": "The user who edited the comment.", + "args": [], + "type": { + "kind": "OBJECT", + "name": "User", + "ofType": null + }, + "isDeprecated": false, + "deprecationReason": null + }, { "name": "id", "description": null, @@ -12385,6 +12578,18 @@ "isDeprecated": false, "deprecationReason": null }, + { + "name": "lastEditedAt", + "description": "The moment the editor made the last edit", + "args": [], + "type": { + "kind": "SCALAR", + "name": "DateTime", + "ofType": null + }, + "isDeprecated": false, + "deprecationReason": null + }, { "name": "liveReactionUpdatesEnabled", "description": "Are reaction live updates enabled for this subject.", @@ -17196,6 +17401,11 @@ "name": "PullRequest", "ofType": null }, + { + "kind": "OBJECT", + "name": "Release", + "ofType": null + }, { "kind": "OBJECT", "name": "Repository", @@ -21426,6 +21636,18 @@ "isDeprecated": false, "deprecationReason": null }, + { + "name": "editor", + "description": "The user who edited the comment.", + "args": [], + "type": { + "kind": "OBJECT", + "name": "User", + "ofType": null + }, + "isDeprecated": false, + "deprecationReason": null + }, { "name": "id", "description": null, @@ -21442,6 +21664,18 @@ "isDeprecated": false, "deprecationReason": null }, + { + "name": "lastEditedAt", + "description": "The moment the editor made the last edit", + "args": [], + "type": { + "kind": "SCALAR", + "name": "DateTime", + "ofType": null + }, + "isDeprecated": false, + "deprecationReason": null + }, { "name": "updatedAt", "description": "Identifies the date and time when the object was last updated.",