Skip to content

Commit 5835857

Browse files
committed
feat: color coding
1 parent 2b81062 commit 5835857

File tree

2 files changed

+111
-75
lines changed

2 files changed

+111
-75
lines changed

messages/list.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -58,7 +58,7 @@ Use one of the "org login" commands or "org create scratch" to add or create a s
5858

5959
# noResultsFound
6060

61-
No %s found.
61+
No Orgs found.
6262

6363
# cleanWarning
6464

src/commands/org/list.ts

Lines changed: 110 additions & 74 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
import { Flags, loglevel, SfCommand } from '@salesforce/sf-plugins-core';
99
import { AuthInfo, ConfigAggregator, ConfigInfo, Connection, Org, SfError, Messages, Logger } from '@salesforce/core';
1010
import { Interfaces } from '@oclif/core';
11+
import * as chalk from 'chalk';
1112
import { OrgListUtil, identifyActiveOrgByStatus } from '../../shared/orgListUtil';
1213
import { getStyledObject } from '../../shared/orgHighlighter';
1314
import { ExtendedAuthFields, FullyPopulatedScratchOrgFields } from '../../shared/orgTypes';
@@ -89,13 +90,15 @@ export class OrgListCommand extends SfCommand<OrgListResult> {
8990
: groupedSortedOrgs.scratchOrgs.filter(identifyActiveOrgByStatus),
9091
};
9192

92-
// this.printOrgTable(result.nonScratchOrgs, flags['skip-connection-status']);
93-
this.printOrgTable(result.devHubs, flags['skip-connection-status'], 'DevHubs');
94-
this.printOrgTable(result.regularOrgs, flags['skip-connection-status'], 'Orgs');
95-
this.printOrgTable(result.sandboxes, flags['skip-connection-status'], 'Sandboxes');
96-
93+
this.printOrgTable({
94+
devHubs: result.devHubs,
95+
regularOrgs: result.regularOrgs,
96+
sandboxes: result.sandboxes,
97+
skipconnectionstatus: flags['skip-connection-status'],
98+
});
9799
this.printScratchOrgTable(result.scratchOrgs);
98100

101+
this.info('Legend: (D)=Default DevHub, (U)=Default Org');
99102
return result;
100103
}
101104

@@ -128,35 +131,61 @@ export class OrgListCommand extends SfCommand<OrgListResult> {
128131
);
129132
}
130133

131-
protected printOrgTable(nonScratchOrgs: ExtendedAuthFields[], skipconnectionstatus: boolean, title: string): void {
132-
if (!nonScratchOrgs.length) {
133-
this.info(messages.getMessage('noResultsFound', [title]));
134-
} else {
135-
this.info(title);
136-
const rows = nonScratchOrgs
137-
.map((row) => getStyledObject(row))
138-
.map((org) =>
139-
Object.fromEntries(
140-
Object.entries(org).filter(([key]) =>
141-
['defaultMarker', 'alias', 'username', 'orgId', 'connectedStatus'].includes(key)
142-
)
143-
)
144-
);
134+
protected printOrgTable({
135+
devHubs,
136+
regularOrgs,
137+
sandboxes,
138+
skipconnectionstatus,
139+
}: {
140+
devHubs: ExtendedAuthFields[];
141+
regularOrgs: ExtendedAuthFields[];
142+
sandboxes: ExtendedAuthFields[];
143+
skipconnectionstatus: boolean;
144+
}): void {
145+
if (!devHubs.length && !regularOrgs.length && !sandboxes.length) {
146+
this.info(messages.getMessage('noResultsFound'));
147+
return;
148+
}
149+
this.log();
150+
this.info('Non-scratch orgs');
151+
const nonScratchOrgs = [
152+
...devHubs
153+
.map(addType('DevHub'))
154+
.map(colorEveryFieldButConnectedStatus(chalk.cyanBright))
155+
.map((row) => getStyledObject(row)),
145156

146-
this.table(rows, {
157+
...regularOrgs.map(colorEveryFieldButConnectedStatus(chalk.magentaBright)).map((row) => getStyledObject(row)),
158+
159+
...sandboxes
160+
.map(addType('Sandbox'))
161+
.map(colorEveryFieldButConnectedStatus(chalk.yellowBright))
162+
.map((row) => getStyledObject(row)),
163+
];
164+
165+
this.table(
166+
nonScratchOrgs.map((org) =>
167+
Object.fromEntries(
168+
Object.entries(org).filter(([key]) =>
169+
['type', 'defaultMarker', 'alias', 'username', 'orgId', 'connectedStatus'].includes(key)
170+
)
171+
)
172+
),
173+
{
147174
defaultMarker: {
148175
header: '',
149-
get: (data): string => data.defaultMarker ?? '',
176+
},
177+
type: {
178+
header: 'Type',
150179
},
151180
alias: {
152-
header: 'ALIAS',
153-
get: (data): string => data.alias ?? '',
181+
header: 'Alias',
154182
},
155-
username: { header: 'USERNAME' },
156-
orgId: { header: 'ORG ID' },
157-
...(!skipconnectionstatus ? { connectedStatus: { header: 'CONNECTED STATUS' } } : {}),
158-
});
159-
}
183+
username: { header: 'Username' },
184+
orgId: { header: 'Org ID' },
185+
...(!skipconnectionstatus ? { connectedStatus: { header: 'Status' } } : {}),
186+
}
187+
);
188+
160189
this.log();
161190
}
162191

@@ -165,54 +194,31 @@ export class OrgListCommand extends SfCommand<OrgListResult> {
165194
this.info(messages.getMessage('noActiveScratchOrgs'));
166195
} else {
167196
this.info(this.flags.all ? 'Scratch Orgs' : 'Active Scratch Orgs (use --all to see all)');
197+
168198
// One or more rows are available.
169199
// we only need a few of the props for our table. Oclif table doesn't like extra props non-string props.
170200
const rows = scratchOrgs
171201
.map(getStyledObject)
172-
.map((org) =>
173-
Object.fromEntries(
174-
Object.entries(org).filter(([key]) =>
175-
[
176-
'defaultMarker',
177-
'alias',
178-
'username',
179-
'orgId',
180-
'status',
181-
'expirationDate',
182-
'devHubOrgId',
183-
'createdDate',
184-
'instanceUrl',
185-
].includes(key)
186-
)
187-
)
188-
);
189-
this.table(
190-
rows,
191-
{
192-
defaultMarker: {
193-
header: '',
194-
get: (data): string => data.defaultMarker ?? '',
195-
},
196-
alias: {
197-
header: 'ALIAS',
198-
get: (data): string => data.alias ?? '',
199-
},
200-
username: { header: 'USERNAME' },
201-
orgId: { header: 'ORG ID' },
202-
...(this.flags.all || this.flags.verbose ? { status: { header: 'STATUS' } } : {}),
203-
...(this.flags.verbose
204-
? {
205-
devHubOrgId: { header: 'DEV HUB' },
206-
createdDate: { header: 'CREATED DATE' },
207-
instanceUrl: { header: 'INSTANCE URL' },
208-
}
209-
: {}),
210-
expirationDate: { header: 'EXPIRATION DATE' },
211-
}
212-
// {
213-
// title: 'Scratch orgs',
214-
// }
215-
);
202+
.map((org) => Object.fromEntries(Object.entries(org).filter(scratchOrgFieldFilter)));
203+
this.table(rows, {
204+
defaultMarker: {
205+
header: '',
206+
},
207+
alias: {
208+
header: 'Alias',
209+
},
210+
username: { header: 'Username' },
211+
orgId: { header: 'Org ID' },
212+
...(this.flags.all || this.flags.verbose ? { status: { header: 'Status' } } : {}),
213+
...(this.flags.verbose
214+
? {
215+
devHubOrgId: { header: 'Dev Hub ID' },
216+
instanceUrl: { header: 'Instance URL' },
217+
createdDate: { header: 'Created', get: (data): string => data.createdDate?.split('T')[0] ?? '' },
218+
}
219+
: {}),
220+
expirationDate: { header: 'Expires' },
221+
});
216222
}
217223
this.log();
218224
}
@@ -226,8 +232,9 @@ const decorateWithDefaultStatus = <T extends ExtendedAuthFields | FullyPopulated
226232

227233
// sort by alias then username
228234
const comparator = <T extends ExtendedAuthFields | FullyPopulatedScratchOrgFields>(a: T, b: T): number => {
229-
const aliasCompareResult = (a.alias ?? '').localeCompare(b.alias ?? '');
230-
return aliasCompareResult !== 0 ? aliasCompareResult : (a.username ?? '').localeCompare(b.username);
235+
const emptiesLast = Array(10).fill('z').join('');
236+
const aliasCompareResult = (a.alias ?? emptiesLast).localeCompare(b.alias ?? emptiesLast);
237+
return aliasCompareResult !== 0 ? aliasCompareResult : (a.username ?? emptiesLast).localeCompare(b.username);
231238
};
232239

233240
const getAuthFileNames = async (): Promise<string[]> => {
@@ -242,3 +249,32 @@ const getAuthFileNames = async (): Promise<string[]> => {
242249
}
243250
}
244251
};
252+
253+
type ExtendedAuthFieldsWithType = ExtendedAuthFields & { type?: string };
254+
const addType =
255+
(type: string) =>
256+
(val: ExtendedAuthFields): ExtendedAuthFieldsWithType => ({ ...val, type });
257+
258+
const colorEveryFieldButConnectedStatus =
259+
(colorFn: chalk.Chalk) =>
260+
(row: ExtendedAuthFieldsWithType): ExtendedAuthFieldsWithType =>
261+
Object.fromEntries(
262+
Object.entries(row).map(([key, val]) => [
263+
key,
264+
typeof val === 'string' && key !== 'connectedStatus' ? colorFn(val) : val,
265+
])
266+
// TS is not smart enough to know this didn't change any types
267+
) as ExtendedAuthFieldsWithType;
268+
269+
const scratchOrgFieldFilter = ([key]: [string, string]): boolean =>
270+
[
271+
'defaultMarker',
272+
'alias',
273+
'username',
274+
'orgId',
275+
'status',
276+
'expirationDate',
277+
'devHubOrgId',
278+
'createdDate',
279+
'instanceUrl',
280+
].includes(key);

0 commit comments

Comments
 (0)