Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: conflict detection UI enhancement #3352

Merged
merged 7 commits into from
Jul 6, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -267,7 +267,7 @@ export class ConflictDetectionChecker implements PostconditionChecker<string> {
)
);
results.different.forEach(file => {
channelService.appendLine(normalize(file));
channelService.appendLine(normalize(file.path));
});
channelService.showChannelOutput();

Expand Down Expand Up @@ -381,7 +381,7 @@ export class TimestampConflictChecker implements PostconditionChecker<string> {
)
);
results.different.forEach(file => {
channelService.appendLine(normalize(file));
channelService.appendLine(normalize(file.path));
});

const choice = await notificationService.showWarningModal(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,8 @@ import { telemetryService } from '../telemetry';
import {
CommonDirDirectoryDiffer,
DirectoryDiffer,
DirectoryDiffResults
DirectoryDiffResults,
TimestampFileProperties
} from './directoryDiffer';
import {
MetadataCacheCallback,
Expand All @@ -42,7 +43,7 @@ export class ConflictDetector {
private static EMPTY_DIFFS = {
localRoot: '',
remoteRoot: '',
different: new Set<string>(),
different: new Set<TimestampFileProperties>(),
scannedLocal: 0,
scannedRemote: 0
};
Expand Down
29 changes: 27 additions & 2 deletions packages/salesforcedx-vscode-core/src/conflict/conflictNode.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,8 @@ export type ConflictFile = {
relPath: string;
localPath: string;
remotePath: string;
localLastModifiedDate: string | undefined;
remoteLastModifiedDate: string | undefined;
};

export class ConflictNode extends vscode.TreeItem {
Expand All @@ -23,11 +25,17 @@ export class ConflictNode extends vscode.TreeItem {
constructor(
label: string,
collapsibleState: vscode.TreeItemCollapsibleState,
parent?: ConflictNode
parent?: ConflictNode,
description?: string | boolean
) {
super(label, collapsibleState);
this._children = [];
this._parent = parent;
this.description = description;
}

public addChildConflictNode(conflictNode: ConflictNode) {
this._children.push(conflictNode);
}

get conflict() {
Expand All @@ -43,7 +51,24 @@ export class ConflictNode extends vscode.TreeItem {
}

get tooltip() {
return this._conflict ? this._conflict.relPath : this.label;
if (this._conflict) {
let tooltipMessage: string = '';
if (this._conflict.remoteLastModifiedDate) {
tooltipMessage += nls.localize(
'conflict_detect_remote_last_modified_date',
`${new Date(this._conflict.remoteLastModifiedDate).toLocaleString()}`
jag-j marked this conversation as resolved.
Show resolved Hide resolved
);
}
if (this._conflict.localLastModifiedDate) {
tooltipMessage += nls.localize(
'conflict_detect_local_last_modified_date',
`${new Date(this._conflict.localLastModifiedDate).toLocaleString()}`
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@violetyao Is this the format we landed on after the last conversation during parking lot?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's based on our slack discussion in this thread! I'll add this item to today's parking lot to double check the format.

);
}
return tooltipMessage;
} else {
return this.label;
}
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -77,10 +77,12 @@ export class ConflictView {
diffResults.different.forEach(p => {
conflicts.push({
remoteLabel,
relPath: p,
fileName: path.basename(p),
relPath: p.path,
fileName: path.basename(p.path),
localPath: diffResults.localRoot,
remotePath: diffResults.remoteRoot
remotePath: diffResults.remoteRoot,
localLastModifiedDate: p.localLastModifiedDate,
remoteLastModifiedDate: p.remoteLastModifiedDate
} as ConflictFile);
});

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,14 @@
import * as fs from 'fs';
import * as path from 'path';

export interface TimestampFileProperties {
path: string;
localLastModifiedDate?: string | undefined;
remoteLastModifiedDate?: string | undefined;
}

export interface DirectoryDiffResults {
different: Set<string>;
different: Set<TimestampFileProperties>;
localRoot: string;
remoteRoot: string;
scannedLocal?: number;
Expand All @@ -34,7 +40,7 @@ export class CommonDirDirectoryDiffer implements DirectoryDiffer {
remoteSourcePath: string
): DirectoryDiffResults {
const localSet = this.listFiles(localSourcePath);
const different = new Set<string>();
const different = new Set<TimestampFileProperties>();

// process remote files to generate differences
let scannedRemote = 0;
Expand All @@ -44,7 +50,9 @@ export class CommonDirDirectoryDiffer implements DirectoryDiffer {
const file1 = path.join(localSourcePath, stats.relPath);
const file2 = path.join(remoteSourcePath, stats.relPath);
if (this.filesDiffer(file1, file2)) {
different.add(stats.relPath);
different.add({
path: stats.relPath
});
}
}
});
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,14 +14,15 @@ import {
PersistentStorageService
} from './';
import { diffComponents } from './componentDiffer';
import { TimestampFileProperties } from './directoryDiffer';
import { CorrelatedComponent } from './metadataCacheService';

export class TimestampConflictDetector {
private diffs: DirectoryDiffResults;
private static EMPTY_DIFFS = {
localRoot: '',
remoteRoot: '',
different: new Set<string>()
different: new Set<TimestampFileProperties>()
};

constructor() {
Expand All @@ -44,10 +45,10 @@ export class TimestampConflictDetector {
data: CorrelatedComponent[]
) {
const cache = PersistentStorageService.getInstance();
const conflicts: Set<string> = new Set<string>();
const conflicts: Set<TimestampFileProperties> = new Set<TimestampFileProperties>();
data.forEach(component => {
let lastModifiedInOrg;
let lastModifiedInCache;
let lastModifiedInOrg: string | undefined;
let lastModifiedInCache: string | undefined;

lastModifiedInOrg = component.lastModifiedDate;
const key = cache.makeKey(component.cacheComponent.type.name, component.cacheComponent.fullName);
Expand All @@ -58,7 +59,11 @@ export class TimestampConflictDetector {
const cachePathRelative = relative(this.diffs.remoteRoot, difference.cachePath);
const projectPathRelative = relative(this.diffs.localRoot, difference.projectPath);
if (cachePathRelative === projectPathRelative) {
conflicts.add(cachePathRelative);
conflicts.add({
path: cachePathRelative,
localLastModifiedDate: lastModifiedInCache,
remoteLastModifiedDate: lastModifiedInOrg
});
}
});
}
Expand Down
2 changes: 2 additions & 0 deletions packages/salesforcedx-vscode-core/src/messages/i18n.ts
Original file line number Diff line number Diff line change
Expand Up @@ -570,6 +570,8 @@ export const messages = {
conflict_detect_no_differences: 'No differences',
conflict_detect_diff_title: '%s//%s ↔ local//%s',
conflict_detect_diff_command_title: 'Compare Files',
conflict_detect_remote_last_modified_date: 'Org last modified date: %s \n',
sbudhirajadoc marked this conversation as resolved.
Show resolved Hide resolved
conflict_detect_local_last_modified_date: 'Local last sync date: %s',

force_source_diff_text: 'SFDX: Diff File Against Org',
force_source_diff_components_not_in_org:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ import {
conflictView,
DirectoryDiffResults
} from '../../../../src/conflict';
import { TimestampFileProperties } from '../../../../src/conflict/directoryDiffer';
import { nls } from '../../../../src/messages';
import { notificationService } from '../../../../src/notifications';
import { sfdxCoreSettings } from '../../../../src/settings';
Expand Down Expand Up @@ -495,7 +496,7 @@ describe('Postcondition Checkers', () => {
const response = await postChecker.handleConflicts(
'manifest.xml',
'admin@example.com',
{ different: new Set<string>() } as DirectoryDiffResults
{ different: new Set<TimestampFileProperties>() } as DirectoryDiffResults
);

expect(response.type).to.equal('CONTINUE');
Expand All @@ -508,10 +509,13 @@ describe('Postcondition Checkers', () => {
it('Should post a warning and return CancelResponse when conflicts are detected and cancelled', async () => {
const postChecker = new ConflictDetectionChecker(retrieveMessages);
const results = {
different: new Set<string>([
'main/default/objects/Property__c/fields/Broker__c.field-meta.xml',
'main/default/aura/auraPropertySummary/auraPropertySummaryController.js'
]),
different: new Set<TimestampFileProperties>([
{
path: 'main/default/objects/Property__c/fields/Broker__c.field-meta.xml'
},
{
path: 'main/default/aura/auraPropertySummary/auraPropertySummaryController.js'
}]),
scannedLocal: 4,
scannedRemote: 6
} as DirectoryDiffResults;
Expand Down Expand Up @@ -546,7 +550,10 @@ describe('Postcondition Checkers', () => {
it('Should post a warning and return ContinueResponse when conflicts are detected and overwritten', async () => {
const postChecker = new ConflictDetectionChecker(retrieveMessages);
const results = {
different: new Set<string>('MyClass.cls')
different: new Set<TimestampFileProperties>([
{
path: 'MyClass.cls'
}])
} as DirectoryDiffResults;
modalStub.returns(nls.localize('conflict_detect_override'));

Expand All @@ -566,7 +573,10 @@ describe('Postcondition Checkers', () => {
it('Should post a warning and return CancelResponse when conflicts are detected and conflicts are shown', async () => {
const postChecker = new ConflictDetectionChecker(retrieveMessages);
const results = {
different: new Set<string>('MyClass.cls')
different: new Set<TimestampFileProperties>([
{
path: 'MyClass.cls'
}])
} as DirectoryDiffResults;
modalStub.returns(nls.localize('conflict_detect_show_conflicts'));

Expand Down Expand Up @@ -655,7 +665,7 @@ describe('Postcondition Checkers', () => {
const response = await postChecker.handleConflicts(
'manifest.xml',
'admin@example.com',
{ different: new Set<string>() } as DirectoryDiffResults
{ different: new Set<TimestampFileProperties>() } as DirectoryDiffResults
);

expect(response.type).to.equal('CONTINUE');
Expand All @@ -668,10 +678,17 @@ describe('Postcondition Checkers', () => {
it('Should post a warning and return CancelResponse when conflicts are detected and cancelled', async () => {
const postChecker = new TimestampConflictChecker(false, retrieveMessages);
const results = {
different: new Set<string>([
'main/default/objects/Property__c/fields/Broker__c.field-meta.xml',
'main/default/aura/auraPropertySummary/auraPropertySummaryController.js'
])
different: new Set<TimestampFileProperties>([
{
path: 'main/default/objects/Property__c/fields/Broker__c.field-meta.xml',
localLastModifiedDate: 'Yesterday',
remoteLastModifiedDate: 'Today'
},
{
path: 'main/default/aura/auraPropertySummary/auraPropertySummaryController.js',
localLastModifiedDate: 'Yesterday',
remoteLastModifiedDate: 'Today'
}])
} as DirectoryDiffResults;
modalStub.returns('Cancel');

Expand Down Expand Up @@ -704,7 +721,12 @@ describe('Postcondition Checkers', () => {
it('Should post a warning and return ContinueResponse when conflicts are detected and overwritten', async () => {
const postChecker = new TimestampConflictChecker(false, retrieveMessages);
const results = {
different: new Set<string>('MyClass.cls')
different: new Set<TimestampFileProperties>([
{
path: 'MyClass.cls',
localLastModifiedDate: 'Yesterday',
remoteLastModifiedDate: 'Today'
}])
} as DirectoryDiffResults;
modalStub.returns(nls.localize('conflict_detect_override'));

Expand All @@ -724,7 +746,12 @@ describe('Postcondition Checkers', () => {
it('Should post a warning and return CancelResponse when conflicts are detected and conflicts are shown', async () => {
const postChecker = new TimestampConflictChecker(false, retrieveMessages);
const results = {
different: new Set<string>('MyClass.cls')
different: new Set<TimestampFileProperties>([
{
path: 'MyClass.cls',
localLastModifiedDate: 'Yesterday',
remoteLastModifiedDate: 'Today'
}])
} as DirectoryDiffResults;
modalStub.returns(nls.localize('conflict_detect_show_conflicts'));

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ import {
PersistentStorageService
} from '../../../src/conflict';
import * as differ from '../../../src/conflict/componentDiffer';
import { TimestampFileProperties } from '../../../src/conflict/directoryDiffer';
import { MetadataCacheResult } from '../../../src/conflict/metadataCacheService';
import { TimestampConflictDetector } from '../../../src/conflict/timestampConflictDetector';
import { nls } from '../../../src/messages';
Expand Down Expand Up @@ -130,9 +131,11 @@ describe('Timestamp Conflict Detector Execution', () => {
path.normalize('/a/b/c')
]);

expect(results.different).to.have.all.keys(
path.normalize('classes/HandlerCostCenter.cls')
);
expect(results.different).to.eql(new Set([{
path: path.normalize('classes/HandlerCostCenter.cls'),
localLastModifiedDate: 'Yesteday',
remoteLastModifiedDate: 'Today'
}]));
});

it('Should not report differences if the component is only local', async () => {
Expand Down Expand Up @@ -164,7 +167,7 @@ describe('Timestamp Conflict Detector Execution', () => {
expect(executorSpy.callCount).to.equal(1);
expect(cacheStub.callCount).to.equal(0);
expect(differStub.callCount).to.equal(0);
expect(results.different).to.eql(new Set<string>());
expect(results.different).to.eql(new Set<TimestampFileProperties>());
});

it('Should not report differences if the component is only remote', async () => {
Expand Down Expand Up @@ -196,7 +199,7 @@ describe('Timestamp Conflict Detector Execution', () => {
expect(executorSpy.callCount).to.equal(1);
expect(cacheStub.callCount).to.equal(0);
expect(differStub.callCount).to.equal(0);
expect(results.different).to.eql(new Set<string>());
expect(results.different).to.eql(new Set<TimestampFileProperties>());
});

it('Should not report differences if the timestamps match', async () => {
Expand Down Expand Up @@ -239,7 +242,7 @@ describe('Timestamp Conflict Detector Execution', () => {
expect(executorSpy.callCount).to.equal(1);
expect(cacheStub.callCount).to.equal(1);
expect(differStub.callCount).to.equal(0);
expect(results.different).to.eql(new Set<string>());
expect(results.different).to.eql(new Set<TimestampFileProperties>());
});

it('Should not report differences if the files match', async () => {
Expand Down Expand Up @@ -303,7 +306,7 @@ describe('Timestamp Conflict Detector Execution', () => {
path.normalize('/a/b/c')
]);

expect(results.different).to.eql(new Set<string>());
expect(results.different).to.eql(new Set<TimestampFileProperties>());
});

it('Should report an error during conflict detection', async () => {
Expand Down
Loading