Compare commits

...

20 Commits

Author SHA1 Message Date
Hai Cao
31bee67f00 bump STS (#23148) 2023-05-16 14:40:54 -07:00
Alan Ren
e2949d4494 add securable settings (#22936) (#23141)
* wip

* Update typings

* nullable

* update test service

* support securables

* updata test data

* fix issues

* fix build failure

* update test mocks

* fix typo

* fix reference

* fix findobjectdialog issue

* update SearchResultItem type

* fix table component perf issue

* hide effective permission for server role

* hide effective permission for app role and db role

* vbump sts and fix a couple issues

* STS update and UI update

* fix user login display issue

* vbump sts
2023-05-15 15:35:47 -07:00
Cheena Malhotra
b6bd726066 Support advanced options in command line arguments (#23104) (#23124) 2023-05-12 13:51:15 -07:00
Benjin Dubishar
0fe638974d Fixing issue where sqlcmdvars wouldn't load from publish profile in ADS (#23116) (#23121)
* fixing issue where sqlcmdvars wouldn't load from publish profile in ADS

* in -> of
2023-05-12 13:50:26 -07:00
Benjin Dubishar
f364e52079 Fix deploy/generatePlan/saveProfile when no sqlcmdvars are defined (#23112) (#23120)
* fix deploy/generate when no sqlcmdvars are defined

* saveProfile
2023-05-12 13:50:02 -07:00
Maddy
84143d3caf remove the access point (#23105) (#23114) 2023-05-11 19:31:57 -07:00
Kim Santiago
0cfaf69647 fix sqlcmd variables not getting loaded correctly in vscode (#23103) (#23108) 2023-05-11 19:31:34 -07:00
Aasim Khan
343d878457 Adding telemetry to ads OE filter (#23089) (#23106)
* Adding telemetry to ads oe filter

* Fixing prop names

* fixing prop name

* Fixing localized strings

* Update src/sql/azdata.proposed.d.ts



* Update src/sql/workbench/contrib/objectExplorer/browser/serverTreeView.ts



---------

Co-authored-by: Charles Gagnon <chgagnon@microsoft.com>
2023-05-11 19:31:07 -07:00
Cheena Malhotra
7d0cfc4f99 Support migrating credentials to new format (#23088) (#23095) 2023-05-11 18:41:11 -07:00
Barbara Valdez
f13406570e update workbench file and fix relative link not working in markdown (#23109) (#23113) 2023-05-11 16:52:05 -07:00
Benjin Dubishar
c44ecf56f2 Fixing bug where SQLCMD vars weren't getting JSONified (#23082) (#23096)
* changing param for sqlcmdvars back to Record since Json.stringify doesn't handle Maps

* swapping over savePublishProfile
2023-05-10 23:12:12 -07:00
Aasim Khan
f10fc9b56d Adding back OE filtering in rmay release. (#23070) 2023-05-10 08:41:26 -07:00
Benjin Dubishar
72acd2af83 Bumping SQL Tools Service (#23046) (#23051) 2023-05-09 14:09:15 -07:00
Cheena Malhotra
6112eabc3c Fixes import wizard to work with enabled SQL auth provider (#23004) (#23052) 2023-05-09 11:12:19 -07:00
Lewis Sanchez
27bac701bb Use notification prompt before running a command (#23035) (#23048)
* Use notification prompt before running a command

https://github.com/microsoft/vscode/pull/179702/commits

* Removes unused declarations
2023-05-09 11:10:46 -07:00
Cheena Malhotra
0bcd010d9a Fixes build folder compilation + enable linux .deb files (#23006) (#23042) 2023-05-09 11:10:14 -07:00
Aasim Khan
bca671bc3f disabling async tree by default (#23037) 2023-05-09 11:09:33 -07:00
Aasim Khan
706ba6c974 Adding filtering dialog and action to OE (#22937) (#23036)
* Adding init change

* Adding filter cache in OE

* Adding more filtering changes

* Fixed stuff with dialog

* Fixing filter

* Adding support for connecitons

* Fixed stuff

* filtering

* Fixing  date

* Filters

* Removing is filtering supported

* Removing contracts

* Fixing filters

* Fixing cache

* Adding some accessibility changes

* Reverting some more changes to pull in changes from the main

* Adding comments

* Fixing boolean operators

* Fixing stuff

* Fixing stuff

* Fixing error handling and making dialog generic

* Fixing more stuff

* Making filter a generic dialog

* adding erase icon

* removing floating promises

* Fixing compile issue

* Adding support for choice filter with different and actual value.

* Adding null checks

* Adding durability type fix

* Fixing filtering for providers that do not play well with empty filter properties
2023-05-09 11:07:03 -07:00
Kim Santiago
8e38295691 vbump sql projects to 1.1.1 (#23029) (#23039) 2023-05-08 16:44:44 -07:00
Alan Ren
a97d882e3c fix #174264 (#174845) (#23027) (#23034)
Co-authored-by: Sandeep Somavarapu <sasomava@microsoft.com>
2023-05-08 15:49:00 -07:00
108 changed files with 3190 additions and 2357 deletions

View File

@@ -4,6 +4,7 @@
* Licensed under the Source EULA. See License.txt in the project root for license information. * Licensed under the Source EULA. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/ *--------------------------------------------------------------------------------------------*/
Object.defineProperty(exports, "__esModule", { value: true }); Object.defineProperty(exports, "__esModule", { value: true });
exports.OctoKitIssue = exports.OctoKit = void 0;
const core_1 = require("@actions/core"); const core_1 = require("@actions/core");
const github_1 = require("@actions/github"); const github_1 = require("@actions/github");
const child_process_1 = require("child_process"); const child_process_1 = require("child_process");
@@ -20,7 +21,6 @@ class OctoKit {
} }
async *query(query) { async *query(query) {
const q = query.q + ` repo:${this.params.owner}/${this.params.repo}`; const q = query.q + ` repo:${this.params.owner}/${this.params.repo}`;
console.log(`Querying for ${q}:`);
const options = this.octokit.search.issuesAndPullRequests.endpoint.merge({ const options = this.octokit.search.issuesAndPullRequests.endpoint.merge({
...query, ...query,
q, q,
@@ -41,19 +41,17 @@ class OctoKit {
}; };
for await (const pageResponse of this.octokit.paginate.iterator(options)) { for await (const pageResponse of this.octokit.paginate.iterator(options)) {
await timeout(); await timeout();
await utils_1.logRateLimit(this.token); await (0, utils_1.logRateLimit)(this.token);
const page = pageResponse.data; const page = pageResponse.data;
console.log(`Page ${++pageNum}: ${page.map(({ number }) => number).join(' ')}`);
yield page.map((issue) => new OctoKitIssue(this.token, this.params, this.octokitIssueToIssue(issue))); yield page.map((issue) => new OctoKitIssue(this.token, this.params, this.octokitIssueToIssue(issue)));
} }
} }
async createIssue(owner, repo, title, body) { async createIssue(owner, repo, title, body) {
core_1.debug(`Creating issue \`${title}\` on ${owner}/${repo}`); (0, core_1.debug)(`Creating issue \`${title}\` on ${owner}/${repo}`);
if (!this.options.readonly) if (!this.options.readonly)
await this.octokit.issues.create({ owner, repo, title, body }); await this.octokit.issues.create({ owner, repo, title, body });
} }
octokitIssueToIssue(issue) { octokitIssueToIssue(issue) {
var _a, _b, _c, _d, _e, _f;
return { return {
author: { name: issue.user.login, isGitHubApp: issue.user.type === 'Bot' }, author: { name: issue.user.login, isGitHubApp: issue.user.type === 'Bot' },
body: issue.body, body: issue.body,
@@ -64,8 +62,8 @@ class OctoKit {
locked: issue.locked, locked: issue.locked,
numComments: issue.comments, numComments: issue.comments,
reactions: issue.reactions, reactions: issue.reactions,
assignee: (_b = (_a = issue.assignee) === null || _a === void 0 ? void 0 : _a.login) !== null && _b !== void 0 ? _b : (_d = (_c = issue.assignees) === null || _c === void 0 ? void 0 : _c[0]) === null || _d === void 0 ? void 0 : _d.login, assignee: issue.assignee?.login ?? issue.assignees?.[0]?.login,
milestoneId: (_f = (_e = issue.milestone) === null || _e === void 0 ? void 0 : _e.number) !== null && _f !== void 0 ? _f : null, milestoneId: issue.milestone?.number ?? null,
createdAt: +new Date(issue.created_at), createdAt: +new Date(issue.created_at),
updatedAt: +new Date(issue.updated_at), updatedAt: +new Date(issue.updated_at),
closedAt: issue.closed_at ? +new Date(issue.closed_at) : undefined, closedAt: issue.closed_at ? +new Date(issue.closed_at) : undefined,
@@ -73,10 +71,10 @@ class OctoKit {
} }
async hasWriteAccess(user) { async hasWriteAccess(user) {
if (user.name in this.writeAccessCache) { if (user.name in this.writeAccessCache) {
core_1.debug('Got permissions from cache for ' + user); (0, core_1.debug)('Got permissions from cache for ' + user);
return this.writeAccessCache[user.name]; return this.writeAccessCache[user.name];
} }
core_1.debug('Fetching permissions for ' + user); (0, core_1.debug)('Fetching permissions for ' + user);
const permissions = (await this.octokit.repos.getCollaboratorPermissionLevel({ const permissions = (await this.octokit.repos.getCollaboratorPermissionLevel({
...this.params, ...this.params,
username: user.name, username: user.name,
@@ -96,14 +94,14 @@ class OctoKit {
} }
} }
async createLabel(name, color, description) { async createLabel(name, color, description) {
core_1.debug('Creating label ' + name); (0, core_1.debug)('Creating label ' + name);
if (!this.options.readonly) if (!this.options.readonly)
await this.octokit.issues.createLabel({ ...this.params, color, description, name }); await this.octokit.issues.createLabel({ ...this.params, color, description, name });
else else
this.mockLabels.add(name); this.mockLabels.add(name);
} }
async deleteLabel(name) { async deleteLabel(name) {
core_1.debug('Deleting label ' + name); (0, core_1.debug)('Deleting label ' + name);
try { try {
if (!this.options.readonly) if (!this.options.readonly)
await this.octokit.issues.deleteLabel({ ...this.params, name }); await this.octokit.issues.deleteLabel({ ...this.params, name });
@@ -116,7 +114,7 @@ class OctoKit {
} }
} }
async readConfig(path) { async readConfig(path) {
core_1.debug('Reading config at ' + path); (0, core_1.debug)('Reading config at ' + path);
const repoPath = `.github/${path}.json`; const repoPath = `.github/${path}.json`;
const data = (await this.octokit.repos.getContents({ ...this.params, path: repoPath })).data; const data = (await this.octokit.repos.getContents({ ...this.params, path: repoPath })).data;
if ('type' in data && data.type === 'file') { if ('type' in data && data.type === 'file') {
@@ -128,10 +126,10 @@ class OctoKit {
throw Error('Found directory at config path when expecting file' + JSON.stringify(data)); throw Error('Found directory at config path when expecting file' + JSON.stringify(data));
} }
async releaseContainsCommit(release, commit) { async releaseContainsCommit(release, commit) {
if (utils_1.getInput('commitReleasedDebuggingOverride')) { if ((0, utils_1.getInput)('commitReleasedDebuggingOverride')) {
return true; return true;
} }
return new Promise((resolve, reject) => child_process_1.exec(`git -C ./repo merge-base --is-ancestor ${commit} ${release}`, (err) => !err || err.code === 1 ? resolve(!err) : reject(err))); return new Promise((resolve, reject) => (0, child_process_1.exec)(`git -C ./repo merge-base --is-ancestor ${commit} ${release}`, (err) => !err || err.code === 1 ? resolve(!err) : reject(err)));
} }
} }
exports.OctoKit = OctoKit; exports.OctoKit = OctoKit;
@@ -142,7 +140,7 @@ class OctoKitIssue extends OctoKit {
this.issueData = issueData; this.issueData = issueData;
} }
async addAssignee(assignee) { async addAssignee(assignee) {
core_1.debug('Adding assignee ' + assignee + ' to ' + this.issueData.number); (0, core_1.debug)('Adding assignee ' + assignee + ' to ' + this.issueData.number);
if (!this.options.readonly) { if (!this.options.readonly) {
await this.octokit.issues.addAssignees({ await this.octokit.issues.addAssignees({
...this.params, ...this.params,
@@ -152,7 +150,7 @@ class OctoKitIssue extends OctoKit {
} }
} }
async closeIssue() { async closeIssue() {
core_1.debug('Closing issue ' + this.issueData.number); (0, core_1.debug)('Closing issue ' + this.issueData.number);
if (!this.options.readonly) if (!this.options.readonly)
await this.octokit.issues.update({ await this.octokit.issues.update({
...this.params, ...this.params,
@@ -161,16 +159,15 @@ class OctoKitIssue extends OctoKit {
}); });
} }
async lockIssue() { async lockIssue() {
core_1.debug('Locking issue ' + this.issueData.number); (0, core_1.debug)('Locking issue ' + this.issueData.number);
if (!this.options.readonly) if (!this.options.readonly)
await this.octokit.issues.lock({ ...this.params, issue_number: this.issueData.number }); await this.octokit.issues.lock({ ...this.params, issue_number: this.issueData.number });
} }
async getIssue() { async getIssue() {
if (isIssue(this.issueData)) { if (isIssue(this.issueData)) {
core_1.debug('Got issue data from query result ' + this.issueData.number); (0, core_1.debug)('Got issue data from query result ' + this.issueData.number);
return this.issueData; return this.issueData;
} }
console.log('Fetching issue ' + this.issueData.number);
const issue = (await this.octokit.issues.get({ const issue = (await this.octokit.issues.get({
...this.params, ...this.params,
issue_number: this.issueData.number, issue_number: this.issueData.number,
@@ -179,7 +176,7 @@ class OctoKitIssue extends OctoKit {
return (this.issueData = this.octokitIssueToIssue(issue)); return (this.issueData = this.octokitIssueToIssue(issue));
} }
async postComment(body) { async postComment(body) {
core_1.debug(`Posting comment ${body} on ${this.issueData.number}`); (0, core_1.debug)(`Posting comment ${body} on ${this.issueData.number}`);
if (!this.options.readonly) if (!this.options.readonly)
await this.octokit.issues.createComment({ await this.octokit.issues.createComment({
...this.params, ...this.params,
@@ -188,7 +185,7 @@ class OctoKitIssue extends OctoKit {
}); });
} }
async deleteComment(id) { async deleteComment(id) {
core_1.debug(`Deleting comment ${id} on ${this.issueData.number}`); (0, core_1.debug)(`Deleting comment ${id} on ${this.issueData.number}`);
if (!this.options.readonly) if (!this.options.readonly)
await this.octokit.issues.deleteComment({ await this.octokit.issues.deleteComment({
owner: this.params.owner, owner: this.params.owner,
@@ -197,7 +194,7 @@ class OctoKitIssue extends OctoKit {
}); });
} }
async setMilestone(milestoneId) { async setMilestone(milestoneId) {
core_1.debug(`Setting milestone for ${this.issueData.number} to ${milestoneId}`); (0, core_1.debug)(`Setting milestone for ${this.issueData.number} to ${milestoneId}`);
if (!this.options.readonly) if (!this.options.readonly)
await this.octokit.issues.update({ await this.octokit.issues.update({
...this.params, ...this.params,
@@ -206,7 +203,7 @@ class OctoKitIssue extends OctoKit {
}); });
} }
async *getComments(last) { async *getComments(last) {
core_1.debug('Fetching comments for ' + this.issueData.number); (0, core_1.debug)('Fetching comments for ' + this.issueData.number);
const response = this.octokit.paginate.iterator(this.octokit.issues.listComments.endpoint.merge({ const response = this.octokit.paginate.iterator(this.octokit.issues.listComments.endpoint.merge({
...this.params, ...this.params,
issue_number: this.issueData.number, issue_number: this.issueData.number,
@@ -223,7 +220,7 @@ class OctoKitIssue extends OctoKit {
} }
} }
async addLabel(name) { async addLabel(name) {
core_1.debug(`Adding label ${name} to ${this.issueData.number}`); (0, core_1.debug)(`Adding label ${name} to ${this.issueData.number}`);
if (!(await this.repoHasLabel(name))) { if (!(await this.repoHasLabel(name))) {
throw Error(`Action could not execute becuase label ${name} is not defined.`); throw Error(`Action could not execute becuase label ${name} is not defined.`);
} }
@@ -235,7 +232,7 @@ class OctoKitIssue extends OctoKit {
}); });
} }
async removeLabel(name) { async removeLabel(name) {
core_1.debug(`Removing label ${name} from ${this.issueData.number}`); (0, core_1.debug)(`Removing label ${name} from ${this.issueData.number}`);
try { try {
if (!this.options.readonly) if (!this.options.readonly)
await this.octokit.issues.removeLabel({ await this.octokit.issues.removeLabel({
@@ -246,14 +243,12 @@ class OctoKitIssue extends OctoKit {
} }
catch (err) { catch (err) {
if (err.status === 404) { if (err.status === 404) {
console.log(`Label ${name} not found on issue`);
return; return;
} }
throw err; throw err;
} }
} }
async getClosingInfo() { async getClosingInfo() {
var _a;
if ((await this.getIssue()).open) { if ((await this.getIssue()).open) {
return; return;
} }
@@ -267,13 +262,12 @@ class OctoKitIssue extends OctoKit {
for (const timelineEvent of timelineEvents) { for (const timelineEvent of timelineEvents) {
if (timelineEvent.event === 'closed') { if (timelineEvent.event === 'closed') {
closingCommit = { closingCommit = {
hash: (_a = timelineEvent.commit_id) !== null && _a !== void 0 ? _a : undefined, hash: timelineEvent.commit_id ?? undefined,
timestamp: +new Date(timelineEvent.created_at), timestamp: +new Date(timelineEvent.created_at),
}; };
} }
} }
} }
console.log(`Got ${closingCommit} as closing commit of ${this.issueData.number}`);
return closingCommit; return closingCommit;
} }
} }

View File

@@ -25,7 +25,6 @@ export class OctoKit implements GitHub {
async *query(query: Query): AsyncIterableIterator<GitHubIssue[]> { async *query(query: Query): AsyncIterableIterator<GitHubIssue[]> {
const q = query.q + ` repo:${this.params.owner}/${this.params.repo}` const q = query.q + ` repo:${this.params.owner}/${this.params.repo}`
console.log(`Querying for ${q}:`)
const options = this.octokit.search.issuesAndPullRequests.endpoint.merge({ const options = this.octokit.search.issuesAndPullRequests.endpoint.merge({
...query, ...query,
@@ -50,7 +49,6 @@ export class OctoKit implements GitHub {
await timeout() await timeout()
await logRateLimit(this.token) await logRateLimit(this.token)
const page: Array<Octokit.SearchIssuesAndPullRequestsResponseItemsItem> = pageResponse.data const page: Array<Octokit.SearchIssuesAndPullRequestsResponseItemsItem> = pageResponse.data
console.log(`Page ${++pageNum}: ${page.map(({ number }) => number).join(' ')}`)
yield page.map( yield page.map(
(issue) => new OctoKitIssue(this.token, this.params, this.octokitIssueToIssue(issue)), (issue) => new OctoKitIssue(this.token, this.params, this.octokitIssueToIssue(issue)),
) )
@@ -199,7 +197,6 @@ export class OctoKitIssue extends OctoKit implements GitHubIssue {
return this.issueData return this.issueData
} }
console.log('Fetching issue ' + this.issueData.number)
const issue = ( const issue = (
await this.octokit.issues.get({ await this.octokit.issues.get({
...this.params, ...this.params,
@@ -286,7 +283,6 @@ export class OctoKitIssue extends OctoKit implements GitHubIssue {
}) })
} catch (err) { } catch (err) {
if (err.status === 404) { if (err.status === 404) {
console.log(`Label ${name} not found on issue`)
return return
} }
throw err throw err
@@ -314,7 +310,6 @@ export class OctoKitIssue extends OctoKit implements GitHubIssue {
} }
} }
} }
console.log(`Got ${closingCommit} as closing commit of ${this.issueData.number}`)
return closingCommit return closingCommit
} }
} }

View File

@@ -4,17 +4,18 @@
* Licensed under the Source EULA. See License.txt in the project root for license information. * Licensed under the Source EULA. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/ *--------------------------------------------------------------------------------------------*/
Object.defineProperty(exports, "__esModule", { value: true }); Object.defineProperty(exports, "__esModule", { value: true });
exports.TestbedIssue = exports.Testbed = void 0;
class Testbed { class Testbed {
constructor(config) { constructor(config) {
var _a, _b, _c, _d, _e;
this.config = { this.config = {
globalLabels: (_a = config === null || config === void 0 ? void 0 : config.globalLabels) !== null && _a !== void 0 ? _a : [], globalLabels: config?.globalLabels ?? [],
configs: (_b = config === null || config === void 0 ? void 0 : config.configs) !== null && _b !== void 0 ? _b : {}, configs: config?.configs ?? {},
writers: (_c = config === null || config === void 0 ? void 0 : config.writers) !== null && _c !== void 0 ? _c : [], writers: config?.writers ?? [],
releasedCommits: (_d = config === null || config === void 0 ? void 0 : config.releasedCommits) !== null && _d !== void 0 ? _d : [], releasedCommits: config?.releasedCommits ?? [],
queryRunner: (_e = config === null || config === void 0 ? void 0 : config.queryRunner) !== null && _e !== void 0 ? _e : async function* () { queryRunner: config?.queryRunner ??
yield []; async function* () {
}, yield [];
},
}; };
} }
async *query(query) { async *query(query) {
@@ -47,16 +48,15 @@ class Testbed {
exports.Testbed = Testbed; exports.Testbed = Testbed;
class TestbedIssue extends Testbed { class TestbedIssue extends Testbed {
constructor(globalConfig, issueConfig) { constructor(globalConfig, issueConfig) {
var _a, _b, _c;
super(globalConfig); super(globalConfig);
issueConfig = issueConfig !== null && issueConfig !== void 0 ? issueConfig : {}; issueConfig = issueConfig ?? {};
issueConfig.comments = (_a = issueConfig === null || issueConfig === void 0 ? void 0 : issueConfig.comments) !== null && _a !== void 0 ? _a : []; issueConfig.comments = issueConfig?.comments ?? [];
issueConfig.labels = (_b = issueConfig === null || issueConfig === void 0 ? void 0 : issueConfig.labels) !== null && _b !== void 0 ? _b : []; issueConfig.labels = issueConfig?.labels ?? [];
issueConfig.issue = { issueConfig.issue = {
author: { name: 'JacksonKearl' }, author: { name: 'JacksonKearl' },
body: 'issue body', body: 'issue body',
locked: false, locked: false,
numComments: ((_c = issueConfig === null || issueConfig === void 0 ? void 0 : issueConfig.comments) === null || _c === void 0 ? void 0 : _c.length) || 0, numComments: issueConfig?.comments?.length || 0,
number: 1, number: 1,
open: true, open: true,
title: 'issue title', title: 'issue title',
@@ -90,7 +90,7 @@ class TestbedIssue extends Testbed {
} }
async postComment(body, author) { async postComment(body, author) {
this.issueConfig.comments.push({ this.issueConfig.comments.push({
author: { name: author !== null && author !== void 0 ? author : 'bot' }, author: { name: author ?? 'bot' },
body, body,
id: Math.random(), id: Math.random(),
timestamp: +new Date(), timestamp: +new Date(),

View File

@@ -8,15 +8,15 @@ const core = require("@actions/core");
const github_1 = require("@actions/github"); const github_1 = require("@actions/github");
const octokit_1 = require("../api/octokit"); const octokit_1 = require("../api/octokit");
const utils_1 = require("../utils/utils"); const utils_1 = require("../utils/utils");
const token = utils_1.getRequiredInput('token'); const token = (0, utils_1.getRequiredInput)('token');
const label = utils_1.getRequiredInput('label'); const label = (0, utils_1.getRequiredInput)('label');
async function main() { async function main() {
const pr = new octokit_1.OctoKitIssue(token, github_1.context.repo, { number: github_1.context.issue.number }); const pr = new octokit_1.OctoKitIssue(token, github_1.context.repo, { number: github_1.context.issue.number });
pr.addLabel(label); pr.addLabel(label);
} }
main() main()
.then(() => utils_1.logRateLimit(token)) .then(() => (0, utils_1.logRateLimit)(token))
.catch(async (error) => { .catch(async (error) => {
core.setFailed(error.message); core.setFailed(error.message);
await utils_1.logErrorToIssue(error.message, true, token); await (0, utils_1.logErrorToIssue)(error.message, true, token);
}); });

View File

@@ -1,24 +1,25 @@
{ {
"name": "github-actions", "name": "github-actions",
"version": "1.0.0", "version": "1.0.0",
"description": "GitHub Actions", "description": "GitHub Actions",
"scripts": { "scripts": {
"test": "mocha -r ts-node/register **/*.test.ts", "test": "mocha -r ts-node/register **/*.test.ts",
"build": "tsc -p ./tsconfig.json", "build": "tsc -p ./tsconfig.json",
"lint": "eslint -c .eslintrc --fix --ext .ts .", "compile": "tsc -p ./tsconfig.json",
"watch-typecheck": "tsc --watch" "lint": "eslint -c .eslintrc --fix --ext .ts .",
}, "watch-typecheck": "tsc --watch"
"repository": { },
"type": "git", "repository": {
"url": "git+https://github.com/microsoft/azuredatastudio.git" "type": "git",
}, "url": "git+https://github.com/microsoft/azuredatastudio.git"
"keywords": [], },
"author": "", "keywords": [],
"dependencies": { "author": "",
"@actions/core": "^1.2.6", "dependencies": {
"@actions/github": "^2.1.1", "@actions/core": "^1.2.6",
"axios": "^0.21.4", "@actions/github": "^2.1.1",
"axios": "^0.21.4",
"ts-node": "^8.6.2", "ts-node": "^8.6.2",
"typescript": "^3.8.3" "typescript": "^3.8.3"
} }
} }

View File

@@ -4,13 +4,16 @@
* Licensed under the Source EULA. See License.txt in the project root for license information. * Licensed under the Source EULA. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/ *--------------------------------------------------------------------------------------------*/
Object.defineProperty(exports, "__esModule", { value: true }); Object.defineProperty(exports, "__esModule", { value: true });
exports.logErrorToIssue = exports.logRateLimit = exports.daysAgoToHumanReadbleDate = exports.daysAgoToTimestamp = exports.loadLatestRelease = exports.normalizeIssue = exports.getRequiredInput = exports.getInput = void 0;
const core = require("@actions/core"); const core = require("@actions/core");
const github_1 = require("@actions/github"); const github_1 = require("@actions/github");
const axios_1 = require("axios"); const axios_1 = require("axios");
const octokit_1 = require("../api/octokit"); const octokit_1 = require("../api/octokit");
exports.getInput = (name) => core.getInput(name) || undefined; const getInput = (name) => core.getInput(name) || undefined;
exports.getRequiredInput = (name) => core.getInput(name, { required: true }); exports.getInput = getInput;
exports.normalizeIssue = (issue) => { const getRequiredInput = (name) => core.getInput(name, { required: true });
exports.getRequiredInput = getRequiredInput;
const normalizeIssue = (issue) => {
const { body, title } = issue; const { body, title } = issue;
const isBug = body.includes('bug_report_template') || /Issue Type:.*Bug.*/.test(body); const isBug = body.includes('bug_report_template') || /Issue Type:.*Bug.*/.test(body);
const isFeatureRequest = body.includes('feature_request_template') || /Issue Type:.*Feature Request.*/.test(body); const isFeatureRequest = body.includes('feature_request_template') || /Issue Type:.*Feature Request.*/.test(body);
@@ -33,23 +36,25 @@ exports.normalizeIssue = (issue) => {
issueType: isBug ? 'bug' : isFeatureRequest ? 'feature_request' : 'unknown', issueType: isBug ? 'bug' : isFeatureRequest ? 'feature_request' : 'unknown',
}; };
}; };
exports.loadLatestRelease = async (quality) => (await axios_1.default.get(`https://vscode-update.azurewebsites.net/api/update/darwin/${quality}/latest`)).data; exports.normalizeIssue = normalizeIssue;
exports.daysAgoToTimestamp = (days) => +new Date(Date.now() - days * 24 * 60 * 60 * 1000); const loadLatestRelease = async (quality) => (await axios_1.default.get(`https://vscode-update.azurewebsites.net/api/update/darwin/${quality}/latest`)).data;
exports.daysAgoToHumanReadbleDate = (days) => new Date(Date.now() - days * 24 * 60 * 60 * 1000).toISOString().replace(/\.\d{3}\w$/, ''); exports.loadLatestRelease = loadLatestRelease;
exports.logRateLimit = async (token) => { const daysAgoToTimestamp = (days) => +new Date(Date.now() - days * 24 * 60 * 60 * 1000);
exports.daysAgoToTimestamp = daysAgoToTimestamp;
const daysAgoToHumanReadbleDate = (days) => new Date(Date.now() - days * 24 * 60 * 60 * 1000).toISOString().replace(/\.\d{3}\w$/, '');
exports.daysAgoToHumanReadbleDate = daysAgoToHumanReadbleDate;
const logRateLimit = async (token) => {
const usageData = (await new github_1.GitHub(token).rateLimit.get()).data.resources; const usageData = (await new github_1.GitHub(token).rateLimit.get()).data.resources;
['core', 'graphql', 'search'].forEach(async (category) => { ['core', 'graphql', 'search'].forEach(async (category) => {
const usage = 1 - usageData[category].remaining / usageData[category].limit; const usage = 1 - usageData[category].remaining / usageData[category].limit;
const message = `Usage at ${usage} for ${category}`; const message = `Usage at ${usage} for ${category}`;
if (usage > 0) {
console.log(message);
}
if (usage > 0.5) { if (usage > 0.5) {
await exports.logErrorToIssue(message, false, token); await (0, exports.logErrorToIssue)(message, false, token);
} }
}); });
}; };
exports.logErrorToIssue = async (message, ping, token) => { exports.logRateLimit = logRateLimit;
const logErrorToIssue = async (message, ping, token) => {
// Attempt to wait out abuse detection timeout if present // Attempt to wait out abuse detection timeout if present
await new Promise((resolve) => setTimeout(resolve, 10000)); await new Promise((resolve) => setTimeout(resolve, 10000));
const dest = github_1.context.repo.repo === 'vscode-internalbacklog' const dest = github_1.context.repo.repo === 'vscode-internalbacklog'
@@ -70,3 +75,4 @@ ${JSON.stringify(github_1.context, null, 2).replace(/<!--/gu, '<@--').replace(/-
--> -->
`); `);
}; };
exports.logErrorToIssue = logErrorToIssue;

View File

@@ -58,13 +58,10 @@ export const daysAgoToHumanReadbleDate = (days: number) =>
new Date(Date.now() - days * 24 * 60 * 60 * 1000).toISOString().replace(/\.\d{3}\w$/, '') new Date(Date.now() - days * 24 * 60 * 60 * 1000).toISOString().replace(/\.\d{3}\w$/, '')
export const logRateLimit = async (token: string) => { export const logRateLimit = async (token: string) => {
const usageData = (await new GitHub(token).rateLimit.get()).data.resources const usageData = (await new GitHub(token).rateLimit.get()).data.resources;
;(['core', 'graphql', 'search'] as const).forEach(async (category) => { (['core', 'graphql', 'search'] as const).forEach(async (category) => {
const usage = 1 - usageData[category].remaining / usageData[category].limit const usage = 1 - usageData[category].remaining / usageData[category].limit
const message = `Usage at ${usage} for ${category}` const message = `Usage at ${usage} for ${category}`
if (usage > 0) {
console.log(message)
}
if (usage > 0.5) { if (usage > 0.5) {
await logErrorToIssue(message, false, token) await logErrorToIssue(message, false, token)
} }

View File

@@ -285,6 +285,8 @@ node-fetch@^2.3.0:
version "2.6.7" version "2.6.7"
resolved "https://registry.yarnpkg.com/node-fetch/-/node-fetch-2.6.7.tgz#24de9fba827e3b4ae44dc8b20256a379160052ad" resolved "https://registry.yarnpkg.com/node-fetch/-/node-fetch-2.6.7.tgz#24de9fba827e3b4ae44dc8b20256a379160052ad"
integrity sha512-ZjMPFEfVx5j+y2yF35Kzx5sF7kDzxuDj6ziH4FFbOp87zKDZNx8yExJIb05OGF4Nlt9IHFIMBkRl41VdvcNdbQ== integrity sha512-ZjMPFEfVx5j+y2yF35Kzx5sF7kDzxuDj6ziH4FFbOp87zKDZNx8yExJIb05OGF4Nlt9IHFIMBkRl41VdvcNdbQ==
dependencies:
whatwg-url "^5.0.0"
npm-run-path@^2.0.0: npm-run-path@^2.0.0:
version "2.0.2" version "2.0.2"
@@ -371,6 +373,11 @@ strip-eof@^1.0.0:
resolved "https://registry.yarnpkg.com/strip-eof/-/strip-eof-1.0.0.tgz#bb43ff5598a6eb05d89b59fcd129c983313606bf" resolved "https://registry.yarnpkg.com/strip-eof/-/strip-eof-1.0.0.tgz#bb43ff5598a6eb05d89b59fcd129c983313606bf"
integrity sha1-u0P/VZim6wXYm1n80SnJgzE2Br8= integrity sha1-u0P/VZim6wXYm1n80SnJgzE2Br8=
tr46@~0.0.3:
version "0.0.3"
resolved "https://registry.yarnpkg.com/tr46/-/tr46-0.0.3.tgz#8184fd347dac9cdc185992f3a6622e14b9d9ab6a"
integrity sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==
ts-node@^8.6.2: ts-node@^8.6.2:
version "8.9.0" version "8.9.0"
resolved "https://registry.yarnpkg.com/ts-node/-/ts-node-8.9.0.tgz#d7bf7272dcbecd3a2aa18bd0b96c7d2f270c15d4" resolved "https://registry.yarnpkg.com/ts-node/-/ts-node-8.9.0.tgz#d7bf7272dcbecd3a2aa18bd0b96c7d2f270c15d4"
@@ -388,9 +395,9 @@ tunnel@0.0.6, tunnel@^0.0.6:
integrity sha512-1h/Lnq9yajKY2PEbBadPXj3VxsDDu844OnaAo52UVmIzIvwwtBPIuNvkjuzBlTWpfJyUbG3ez0KSBibQkj4ojg== integrity sha512-1h/Lnq9yajKY2PEbBadPXj3VxsDDu844OnaAo52UVmIzIvwwtBPIuNvkjuzBlTWpfJyUbG3ez0KSBibQkj4ojg==
typescript@^3.8.3: typescript@^3.8.3:
version "3.8.3" version "3.9.10"
resolved "https://registry.yarnpkg.com/typescript/-/typescript-3.8.3.tgz#409eb8544ea0335711205869ec458ab109ee1061" resolved "https://registry.yarnpkg.com/typescript/-/typescript-3.9.10.tgz#70f3910ac7a51ed6bef79da7800690b19bf778b8"
integrity sha512-MYlEfn5VrLNsgudQTVJeNaQFUAI7DkhnOjdpAp4T+ku1TfQClewlbSuTVHiA+8skNBgaf02TL/kLOvig4y3G8w== integrity sha512-w6fIxVE/H1PkLKcCPsFqKE7Kv7QUwhU8qQY2MueZXWx5cPZdwFupLgKK3vntcK98BtNHZtAF4LA/yl2a7k8R6Q==
universal-user-agent@^4.0.0: universal-user-agent@^4.0.0:
version "4.0.1" version "4.0.1"
@@ -411,6 +418,19 @@ uuid@^8.3.2:
resolved "https://registry.yarnpkg.com/uuid/-/uuid-8.3.2.tgz#80d5b5ced271bb9af6c445f21a1a04c606cefbe2" resolved "https://registry.yarnpkg.com/uuid/-/uuid-8.3.2.tgz#80d5b5ced271bb9af6c445f21a1a04c606cefbe2"
integrity sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg== integrity sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==
webidl-conversions@^3.0.0:
version "3.0.1"
resolved "https://registry.yarnpkg.com/webidl-conversions/-/webidl-conversions-3.0.1.tgz#24534275e2a7bc6be7bc86611cc16ae0a5654871"
integrity sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==
whatwg-url@^5.0.0:
version "5.0.0"
resolved "https://registry.yarnpkg.com/whatwg-url/-/whatwg-url-5.0.0.tgz#966454e8765462e37644d3626f6742ce8b70965d"
integrity sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==
dependencies:
tr46 "~0.0.3"
webidl-conversions "^3.0.0"
which@^1.2.9: which@^1.2.9:
version "1.3.1" version "1.3.1"
resolved "https://registry.yarnpkg.com/which/-/which-1.3.1.tgz#a45043d54f5805316da8d62f9f50918d3da70b0a" resolved "https://registry.yarnpkg.com/which/-/which-1.3.1.tgz#a45043d54f5805316da8d62f9f50918d3da70b0a"

View File

@@ -130,7 +130,6 @@ function getEnv(name) {
return result; return result;
} }
async function main() { async function main() {
var _a;
const [, , product, os, arch, unprocessedType, fileName, filePath] = process.argv; const [, , product, os, arch, unprocessedType, fileName, filePath] = process.argv;
// getPlatform needs the unprocessedType // getPlatform needs the unprocessedType
const platform = getPlatform(product, os, arch, unprocessedType); const platform = getPlatform(product, os, arch, unprocessedType);
@@ -169,7 +168,7 @@ async function main() {
console.log('Blob successfully uploaded to Azure storage.'); console.log('Blob successfully uploaded to Azure storage.');
}) })
]; ];
const shouldUploadToMooncake = /true/i.test((_a = process.env['VSCODE_PUBLISH_TO_MOONCAKE']) !== null && _a !== void 0 ? _a : 'true'); const shouldUploadToMooncake = /true/i.test(process.env['VSCODE_PUBLISH_TO_MOONCAKE'] ?? 'true');
if (shouldUploadToMooncake) { if (shouldUploadToMooncake) {
const mooncakeCredential = new identity_1.ClientSecretCredential(process.env['AZURE_MOONCAKE_TENANT_ID'], process.env['AZURE_MOONCAKE_CLIENT_ID'], process.env['AZURE_MOONCAKE_CLIENT_SECRET']); const mooncakeCredential = new identity_1.ClientSecretCredential(process.env['AZURE_MOONCAKE_TENANT_ID'], process.env['AZURE_MOONCAKE_CLIENT_ID'], process.env['AZURE_MOONCAKE_CLIENT_SECRET']);
const mooncakeBlobServiceClient = new storage_blob_1.BlobServiceClient(`https://vscode.blob.core.chinacloudapi.cn`, mooncakeCredential, storagePipelineOptions); const mooncakeBlobServiceClient = new storage_blob_1.BlobServiceClient(`https://vscode.blob.core.chinacloudapi.cn`, mooncakeCredential, storagePipelineOptions);

View File

@@ -19,12 +19,11 @@ function getEnv(name) {
return result; return result;
} }
async function main() { async function main() {
var _a, _b, _c;
const [, , _version] = process.argv; const [, , _version] = process.argv;
const quality = getEnv('VSCODE_QUALITY'); const quality = getEnv('VSCODE_QUALITY');
const commit = ((_a = process.env['VSCODE_DISTRO_COMMIT']) === null || _a === void 0 ? void 0 : _a.trim()) || getEnv('BUILD_SOURCEVERSION'); const commit = process.env['VSCODE_DISTRO_COMMIT']?.trim() || getEnv('BUILD_SOURCEVERSION');
const queuedBy = getEnv('BUILD_QUEUEDBY'); const queuedBy = getEnv('BUILD_QUEUEDBY');
const sourceBranch = ((_b = process.env['VSCODE_DISTRO_REF']) === null || _b === void 0 ? void 0 : _b.trim()) || getEnv('BUILD_SOURCEBRANCH'); const sourceBranch = process.env['VSCODE_DISTRO_REF']?.trim() || getEnv('BUILD_SOURCEBRANCH');
const version = _version + (quality === 'stable' ? '' : `-${quality}`); const version = _version + (quality === 'stable' ? '' : `-${quality}`);
console.log('Creating build...'); console.log('Creating build...');
console.log('Quality:', quality); console.log('Quality:', quality);
@@ -35,7 +34,7 @@ async function main() {
timestamp: (new Date()).getTime(), timestamp: (new Date()).getTime(),
version, version,
isReleased: false, isReleased: false,
private: Boolean((_c = process.env['VSCODE_DISTRO_REF']) === null || _c === void 0 ? void 0 : _c.trim()), private: Boolean(process.env['VSCODE_DISTRO_REF']?.trim()),
sourceBranch, sourceBranch,
queuedBy, queuedBy,
assets: [], assets: [],
@@ -44,7 +43,7 @@ async function main() {
const aadCredentials = new identity_1.ClientSecretCredential(process.env['AZURE_TENANT_ID'], process.env['AZURE_CLIENT_ID'], process.env['AZURE_CLIENT_SECRET']); const aadCredentials = new identity_1.ClientSecretCredential(process.env['AZURE_TENANT_ID'], process.env['AZURE_CLIENT_ID'], process.env['AZURE_CLIENT_SECRET']);
const client = new cosmos_1.CosmosClient({ endpoint: process.env['AZURE_DOCUMENTDB_ENDPOINT'], aadCredentials }); const client = new cosmos_1.CosmosClient({ endpoint: process.env['AZURE_DOCUMENTDB_ENDPOINT'], aadCredentials });
const scripts = client.database('builds').container(quality).scripts; const scripts = client.database('builds').container(quality).scripts;
await (0, retry_1.retry)(() => scripts.storedProcedure('createBuild').execute('', [Object.assign(Object.assign({}, build), { _partitionKey: '' })])); await (0, retry_1.retry)(() => scripts.storedProcedure('createBuild').execute('', [{ ...build, _partitionKey: '' }]));
} }
main().then(() => { main().then(() => {
console.log('Build successfully created'); console.log('Build successfully created');

View File

@@ -109,7 +109,6 @@ async function assertContainer(containerClient) {
return containerResponse && !!containerResponse.errorCode; return containerResponse && !!containerResponse.errorCode;
} }
async function uploadBlob(blobClient, file) { async function uploadBlob(blobClient, file) {
var _a, _b;
const result = await blobClient.uploadFile(file, { const result = await blobClient.uploadFile(file, {
blobHTTPHeaders: { blobHTTPHeaders: {
blobContentType: mime.lookup(file), blobContentType: mime.lookup(file),
@@ -117,10 +116,10 @@ async function uploadBlob(blobClient, file) {
} }
}); });
if (result && !result.errorCode) { if (result && !result.errorCode) {
console.log(`Blobs uploaded successfully, response status: ${(_a = result === null || result === void 0 ? void 0 : result._response) === null || _a === void 0 ? void 0 : _a.status}`); console.log(`Blobs uploaded successfully, response status: ${result?._response?.status}`);
} }
else { else {
console.error(`Blobs failed to upload, response status: ${(_b = result === null || result === void 0 ? void 0 : result._response) === null || _b === void 0 ? void 0 : _b.status}, errorcode: ${result === null || result === void 0 ? void 0 : result.errorCode}`); console.error(`Blobs failed to upload, response status: ${result?._response?.status}, errorcode: ${result?.errorCode}`);
} }
} }
async function publish(commit, quality, platform, type, name, version, _isUpdate, file, opts) { async function publish(commit, quality, platform, type, name, version, _isUpdate, file, opts) {

View File

@@ -180,12 +180,11 @@ steps:
# continueOnError: true # continueOnError: true
# condition: and(succeeded(), eq(variables['RUN_TESTS'], 'true')) # condition: and(succeeded(), eq(variables['RUN_TESTS'], 'true'))
# {{SQL CARBON TODO}} - Reenable - script: |
# - script: | set -e
# set -e yarn gulp vscode-linux-x64-build-deb
# yarn gulp vscode-linux-x64-build-deb displayName: Build Deb
# displayName: Build Deb condition: and(succeeded(), ne(variables['EXTENSIONS_ONLY'], 'true'))
# condition: and(succeeded(), ne(variables['EXTENSIONS_ONLY'], 'true'))
- script: | - script: |
set -e set -e

View File

@@ -27,16 +27,16 @@ If (-NOT ($Quality -eq "stable")) {
node $sourcesDir\build\azure-pipelines\common\publish.js $Quality $PlatformLinux archive-unsigned "$TarballUploadName.tar.gz" $Version true $TarballPath $CommitId node $sourcesDir\build\azure-pipelines\common\publish.js $Quality $PlatformLinux archive-unsigned "$TarballUploadName.tar.gz" $Version true $TarballPath $CommitId
# Publish DEB # Publish DEB
# $PlatformDeb = "linux-deb-$Arch" $PlatformDeb = "linux-deb-$Arch"
# $DebFilename = "$(Get-ChildItem -File -Name $artifactsDir\linux\deb\amd64\deb\*.deb)" $DebFilename = "$(Get-ChildItem -File -Name $artifactsDir\linux\deb\amd64\deb\*.deb)"
# $DebPath = "$artifactsDir\linux\deb\amd64\deb\$DebFilename" $DebPath = "$artifactsDir\linux\deb\amd64\deb\$DebFilename"
# $DebUploadName = "azuredatastudio-linux-$Version" $DebUploadName = "azuredatastudio-linux-$Version"
# If (-NOT ($Quality -eq "stable")) { If (-NOT ($Quality -eq "stable")) {
# $DebUploadName = "$DebUploadName-$Quality" $DebUploadName = "$DebUploadName-$Quality"
# } }
# node $sourcesDir\build\azure-pipelines\common\publish.js $Quality $PlatformDeb package "$DebUploadName.deb" $Version true $DebPath $CommitId node $sourcesDir\build\azure-pipelines\common\publish.js $Quality $PlatformDeb package "$DebUploadName.deb" $Version true $DebPath $CommitId
# Publish RPM # Publish RPM
$PlatformRpm = "linux-rpm-$Arch" $PlatformRpm = "linux-rpm-$Arch"

View File

@@ -43,7 +43,7 @@ async function mixinClient(quality) {
else { else {
fancyLog(ansiColors.blue('[mixin]'), 'Inheriting OSS built-in extensions', builtInExtensions.map(e => e.name)); fancyLog(ansiColors.blue('[mixin]'), 'Inheriting OSS built-in extensions', builtInExtensions.map(e => e.name));
} }
return Object.assign(Object.assign({ webBuiltInExtensions: originalProduct.webBuiltInExtensions }, o), { builtInExtensions }); return { webBuiltInExtensions: originalProduct.webBuiltInExtensions, ...o, builtInExtensions };
})) }))
.pipe(productJsonFilter.restore) .pipe(productJsonFilter.restore)
.pipe(es.mapSync((f) => { .pipe(es.mapSync((f) => {
@@ -64,7 +64,7 @@ function mixinServer(quality) {
fancyLog(ansiColors.blue('[mixin]'), `Mixing in server:`); fancyLog(ansiColors.blue('[mixin]'), `Mixing in server:`);
const originalProduct = JSON.parse(fs.readFileSync(path.join(__dirname, '..', '..', 'product.json'), 'utf8')); const originalProduct = JSON.parse(fs.readFileSync(path.join(__dirname, '..', '..', 'product.json'), 'utf8'));
const serverProductJson = JSON.parse(fs.readFileSync(serverProductJsonPath, 'utf8')); const serverProductJson = JSON.parse(fs.readFileSync(serverProductJsonPath, 'utf8'));
fs.writeFileSync('product.json', JSON.stringify(Object.assign(Object.assign({}, originalProduct), serverProductJson), undefined, '\t')); fs.writeFileSync('product.json', JSON.stringify({ ...originalProduct, ...serverProductJson }, undefined, '\t'));
fancyLog(ansiColors.blue('[mixin]'), 'product.json', ansiColors.green('✔︎')); fancyLog(ansiColors.blue('[mixin]'), 'product.json', ansiColors.green('✔︎'));
} }
function main() { function main() {

View File

@@ -40,14 +40,26 @@ async function main() {
identity: '99FM488X57', identity: '99FM488X57',
'gatekeeper-assess': false 'gatekeeper-assess': false
}; };
const appOpts = Object.assign(Object.assign({}, defaultOpts), { const appOpts = {
...defaultOpts,
// TODO(deepak1556): Incorrectly declared type in electron-osx-sign // TODO(deepak1556): Incorrectly declared type in electron-osx-sign
ignore: (filePath) => { ignore: (filePath) => {
return filePath.includes(gpuHelperAppName) || return filePath.includes(gpuHelperAppName) ||
filePath.includes(rendererHelperAppName); filePath.includes(rendererHelperAppName);
} }); }
const gpuHelperOpts = Object.assign(Object.assign({}, defaultOpts), { app: path.join(appFrameworkPath, gpuHelperAppName), entitlements: path.join(baseDir, 'azure-pipelines', 'darwin', 'helper-gpu-entitlements.plist'), 'entitlements-inherit': path.join(baseDir, 'azure-pipelines', 'darwin', 'helper-gpu-entitlements.plist') }); };
const rendererHelperOpts = Object.assign(Object.assign({}, defaultOpts), { app: path.join(appFrameworkPath, rendererHelperAppName), entitlements: path.join(baseDir, 'azure-pipelines', 'darwin', 'helper-renderer-entitlements.plist'), 'entitlements-inherit': path.join(baseDir, 'azure-pipelines', 'darwin', 'helper-renderer-entitlements.plist') }); const gpuHelperOpts = {
...defaultOpts,
app: path.join(appFrameworkPath, gpuHelperAppName),
entitlements: path.join(baseDir, 'azure-pipelines', 'darwin', 'helper-gpu-entitlements.plist'),
'entitlements-inherit': path.join(baseDir, 'azure-pipelines', 'darwin', 'helper-gpu-entitlements.plist'),
};
const rendererHelperOpts = {
...defaultOpts,
app: path.join(appFrameworkPath, rendererHelperAppName),
entitlements: path.join(baseDir, 'azure-pipelines', 'darwin', 'helper-renderer-entitlements.plist'),
'entitlements-inherit': path.join(baseDir, 'azure-pipelines', 'darwin', 'helper-renderer-entitlements.plist'),
};
// Only overwrite plist entries for x64 and arm64 builds, // Only overwrite plist entries for x64 and arm64 builds,
// universal will get its copy from the x64 build. // universal will get its copy from the x64 build.
if (arch !== 'universal') { if (arch !== 'universal') {

View File

@@ -1,15 +0,0 @@
{
"compilerOptions": {
"module": "commonjs",
"target": "es2017",
"jsx": "preserve",
"checkJs": true
},
"include": [
"**/*.js"
],
"exclude": [
"node_modules",
"**/node_modules/*"
]
}

View File

@@ -45,8 +45,7 @@ function isUpToDate(extension) {
} }
} }
function syncMarketplaceExtension(extension) { function syncMarketplaceExtension(extension) {
var _a; const galleryServiceUrl = productjson.extensionsGallery?.serviceUrl;
const galleryServiceUrl = (_a = productjson.extensionsGallery) === null || _a === void 0 ? void 0 : _a.serviceUrl;
const source = ansiColors.blue(galleryServiceUrl ? '[marketplace]' : '[github]'); const source = ansiColors.blue(galleryServiceUrl ? '[marketplace]' : '[github]');
if (isUpToDate(extension)) { if (isUpToDate(extension)) {
log(source, `${extension.name}@${extension.version}`, ansiColors.green('✔︎')); log(source, `${extension.name}@${extension.version}`, ansiColors.green('✔︎'));

View File

@@ -18,7 +18,6 @@ const token = process.env['VSCODE_MIXIN_PASSWORD'] || process.env['GITHUB_TOKEN'
const contentBasePath = 'raw.githubusercontent.com'; const contentBasePath = 'raw.githubusercontent.com';
const contentFileNames = ['package.json', 'package-lock.json', 'yarn.lock']; const contentFileNames = ['package.json', 'package-lock.json', 'yarn.lock'];
async function downloadExtensionDetails(extension) { async function downloadExtensionDetails(extension) {
var _a, _b, _c;
const extensionLabel = `${extension.name}@${extension.version}`; const extensionLabel = `${extension.name}@${extension.version}`;
const repository = url.parse(extension.repo).path.substr(1); const repository = url.parse(extension.repo).path.substr(1);
const repositoryContentBaseUrl = `https://${token ? `${token}@` : ''}${contentBasePath}/${repository}/v${extension.version}`; const repositoryContentBaseUrl = `https://${token ? `${token}@` : ''}${contentBasePath}/${repository}/v${extension.version}`;
@@ -56,11 +55,11 @@ async function downloadExtensionDetails(extension) {
} }
} }
// Validation // Validation
if (!((_a = results.find(r => r.fileName === 'package.json')) === null || _a === void 0 ? void 0 : _a.body)) { if (!results.find(r => r.fileName === 'package.json')?.body) {
// throw new Error(`The "package.json" file could not be found for the built-in extension - ${extensionLabel}`); // throw new Error(`The "package.json" file could not be found for the built-in extension - ${extensionLabel}`);
} }
if (!((_b = results.find(r => r.fileName === 'package-lock.json')) === null || _b === void 0 ? void 0 : _b.body) && if (!results.find(r => r.fileName === 'package-lock.json')?.body &&
!((_c = results.find(r => r.fileName === 'yarn.lock')) === null || _c === void 0 ? void 0 : _c.body)) { !results.find(r => r.fileName === 'yarn.lock')?.body) {
// throw new Error(`The "package-lock.json"/"yarn.lock" could not be found for the built-in extension - ${extensionLabel}`); // throw new Error(`The "package-lock.json"/"yarn.lock" could not be found for the built-in extension - ${extensionLabel}`);
} }
} }

View File

@@ -21,12 +21,11 @@ function bundle(entryPoints, config, callback) {
}); });
const allMentionedModulesMap = {}; const allMentionedModulesMap = {};
entryPoints.forEach((module) => { entryPoints.forEach((module) => {
var _a, _b;
allMentionedModulesMap[module.name] = true; allMentionedModulesMap[module.name] = true;
(_a = module.include) === null || _a === void 0 ? void 0 : _a.forEach(function (includedModule) { module.include?.forEach(function (includedModule) {
allMentionedModulesMap[includedModule] = true; allMentionedModulesMap[includedModule] = true;
}); });
(_b = module.exclude) === null || _b === void 0 ? void 0 : _b.forEach(function (excludedModule) { module.exclude?.forEach(function (excludedModule) {
allMentionedModulesMap[excludedModule] = true; allMentionedModulesMap[excludedModule] = true;
}); });
}); });

View File

@@ -1,8 +1,8 @@
"use strict";
/*--------------------------------------------------------------------------------------------- /*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved. * Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information. * Licensed under the Source EULA. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/ *--------------------------------------------------------------------------------------------*/
'use strict';
Object.defineProperty(exports, "__esModule", { value: true }); Object.defineProperty(exports, "__esModule", { value: true });
exports.watchApiProposalNamesTask = exports.compileApiProposalNamesTask = exports.watchTask = exports.compileTask = exports.transpileTask = void 0; exports.watchApiProposalNamesTask = exports.compileApiProposalNamesTask = exports.watchTask = exports.compileTask = exports.transpileTask = void 0;
const es = require("event-stream"); const es = require("event-stream");
@@ -38,7 +38,7 @@ function createCompile(src, build, emitError, transpileOnly) {
const tsb = require('./tsb'); const tsb = require('./tsb');
const sourcemaps = require('gulp-sourcemaps'); const sourcemaps = require('gulp-sourcemaps');
const projectPath = path.join(__dirname, '../../', src, 'tsconfig.json'); const projectPath = path.join(__dirname, '../../', src, 'tsconfig.json');
const overrideOptions = Object.assign(Object.assign({}, getTypeScriptCompilerOptions(src)), { inlineSources: Boolean(build) }); const overrideOptions = { ...getTypeScriptCompilerOptions(src), inlineSources: Boolean(build) };
// {{SQL CARBON EDIT}} Add override for not inlining the sourcemap during build so we can get code coverage - it // {{SQL CARBON EDIT}} Add override for not inlining the sourcemap during build so we can get code coverage - it
// currently expects a *.map.js file to exist next to the source file for proper source mapping // currently expects a *.map.js file to exist next to the source file for proper source mapping
if (!build && !process.env['SQL_NO_INLINE_SOURCEMAP']) { if (!build && !process.env['SQL_NO_INLINE_SOURCEMAP']) {
@@ -52,7 +52,7 @@ function createCompile(src, build, emitError, transpileOnly) {
console.warn('* and re-run the build/watch task *'); console.warn('* and re-run the build/watch task *');
console.warn('********************************************************************************************'); console.warn('********************************************************************************************');
} }
const compilation = tsb.create(projectPath, overrideOptions, false, err => reporter(err)); const compilation = tsb.create(projectPath, overrideOptions, { verbose: false, transpileOnly }, err => reporter(err));
function pipeline(token) { function pipeline(token) {
const bom = require('gulp-bom'); const bom = require('gulp-bom');
const utf8Filter = util.filter(data => /(\/|\\)test(\/|\\).*utf8/.test(data.path)); const utf8Filter = util.filter(data => /(\/|\\)test(\/|\\).*utf8/.test(data.path));

View File

@@ -60,7 +60,7 @@ function createCompile(src: string, build: boolean, emitError: boolean, transpil
} }
const compilation = tsb.create(projectPath, overrideOptions, false, err => reporter(err)); const compilation = tsb.create(projectPath, overrideOptions, { verbose: false, transpileOnly }, err => reporter(err));
function pipeline(token?: util.ICancellationToken) { function pipeline(token?: util.ICancellationToken) {
const bom = require('gulp-bom') as typeof import('gulp-bom'); const bom = require('gulp-bom') as typeof import('gulp-bom');

View File

@@ -36,7 +36,7 @@ function asYarnDependency(prefix, tree) {
return { name, version, path: dependencyPath, children }; return { name, version, path: dependencyPath, children };
} }
function getYarnProductionDependencies(cwd) { function getYarnProductionDependencies(cwd) {
const raw = cp.execSync('yarn list --json', { cwd, encoding: 'utf8', env: Object.assign(Object.assign({}, process.env), { NODE_ENV: 'production' }), stdio: [null, null, 'inherit'] }); const raw = cp.execSync('yarn list --json', { cwd, encoding: 'utf8', env: { ...process.env, NODE_ENV: 'production' }, stdio: [null, null, 'inherit'] });
const match = /^{"type":"tree".*$/m.exec(raw); const match = /^{"type":"tree".*$/m.exec(raw);
if (!match || match.length !== 1) { if (!match || match.length !== 1) {
throw new Error('Could not parse result of `yarn list --json`'); throw new Error('Could not parse result of `yarn list --json`');

View File

@@ -40,7 +40,7 @@ const darwinCreditsTemplate = product.darwinCredits && _.template(fs.readFileSyn
function darwinBundleDocumentType(extensions, icon, nameOrSuffix, utis) { function darwinBundleDocumentType(extensions, icon, nameOrSuffix, utis) {
// If given a suffix, generate a name from it. If not given anything, default to 'document' // If given a suffix, generate a name from it. If not given anything, default to 'document'
if (isDocumentSuffix(nameOrSuffix) || !nameOrSuffix) { if (isDocumentSuffix(nameOrSuffix) || !nameOrSuffix) {
nameOrSuffix = icon.charAt(0).toUpperCase() + icon.slice(1) + ' ' + (nameOrSuffix !== null && nameOrSuffix !== void 0 ? nameOrSuffix : 'document'); nameOrSuffix = icon.charAt(0).toUpperCase() + icon.slice(1) + ' ' + (nameOrSuffix ?? 'document');
} }
return { return {
name: nameOrSuffix, name: nameOrSuffix,

View File

@@ -20,8 +20,7 @@ module.exports = {
return { return {
// /.../ // /.../
['Literal[regex]']: (node) => { ['Literal[regex]']: (node) => {
var _a; const pattern = node.regex?.pattern;
const pattern = (_a = node.regex) === null || _a === void 0 ? void 0 : _a.pattern;
if (_containsLookBehind(pattern)) { if (_containsLookBehind(pattern)) {
context.report({ context.report({
node, node,

View File

@@ -14,9 +14,8 @@ module.exports = new class ApiLiteralOrTypes {
create(context) { create(context) {
return { return {
['TSDeclareFunction Identifier[name=/create.*/]']: (node) => { ['TSDeclareFunction Identifier[name=/create.*/]']: (node) => {
var _a;
const decl = node.parent; const decl = node.parent;
if (((_a = decl.returnType) === null || _a === void 0 ? void 0 : _a.typeAnnotation.type) !== experimental_utils_1.AST_NODE_TYPES.TSTypeReference) { if (decl.returnType?.typeAnnotation.type !== experimental_utils_1.AST_NODE_TYPES.TSTypeReference) {
return; return;
} }
if (decl.returnType.typeAnnotation.typeName.type !== experimental_utils_1.AST_NODE_TYPES.Identifier) { if (decl.returnType.typeAnnotation.typeName.type !== experimental_utils_1.AST_NODE_TYPES.Identifier) {

View File

@@ -25,8 +25,7 @@ module.exports = new (_a = class ApiEventNaming {
const verbs = new Set(config.verbs); const verbs = new Set(config.verbs);
return { return {
['TSTypeAnnotation TSTypeReference Identifier[name="Event"]']: (node) => { ['TSTypeAnnotation TSTypeReference Identifier[name="Event"]']: (node) => {
var _a, _b; const def = node.parent?.parent?.parent;
const def = (_b = (_a = node.parent) === null || _a === void 0 ? void 0 : _a.parent) === null || _b === void 0 ? void 0 : _b.parent;
const ident = this.getIdent(def); const ident = this.getIdent(def);
if (!ident) { if (!ident) {
// event on unknown structure... // event on unknown structure...

View File

@@ -17,8 +17,7 @@ module.exports = new (_a = class ApiProviderNaming {
const allowed = new Set(config.allowed); const allowed = new Set(config.allowed);
return { return {
['TSInterfaceDeclaration[id.name=/.+Provider/] TSMethodSignature']: (node) => { ['TSInterfaceDeclaration[id.name=/.+Provider/] TSMethodSignature']: (node) => {
var _a; const interfaceName = (node.parent?.parent).id.name;
const interfaceName = ((_a = node.parent) === null || _a === void 0 ? void 0 : _a.parent).id.name;
if (allowed.has(interfaceName)) { if (allowed.has(interfaceName)) {
// allowed // allowed
return; return;

View File

@@ -34,14 +34,14 @@ function minifyExtensionResources(input) {
.pipe(jsonFilter) .pipe(jsonFilter)
.pipe(buffer()) .pipe(buffer())
.pipe(es.mapSync((f) => { .pipe(es.mapSync((f) => {
const errors = []; const errors = [];
const value = jsoncParser.parse(f.contents.toString('utf8'), errors); const value = jsoncParser.parse(f.contents.toString('utf8'), errors);
if (errors.length === 0) { if (errors.length === 0) {
// file parsed OK => just stringify to drop whitespace and comments // file parsed OK => just stringify to drop whitespace and comments
f.contents = Buffer.from(JSON.stringify(value)); f.contents = Buffer.from(JSON.stringify(value));
} }
return f; return f;
})) }))
.pipe(jsonFilter.restore); .pipe(jsonFilter.restore);
} }
function updateExtensionPackageJSON(input, update) { function updateExtensionPackageJSON(input, update) {
@@ -50,10 +50,10 @@ function updateExtensionPackageJSON(input, update) {
.pipe(packageJsonFilter) .pipe(packageJsonFilter)
.pipe(buffer()) .pipe(buffer())
.pipe(es.mapSync((f) => { .pipe(es.mapSync((f) => {
const data = JSON.parse(f.contents.toString('utf8')); const data = JSON.parse(f.contents.toString('utf8'));
f.contents = Buffer.from(JSON.stringify(update(data))); f.contents = Buffer.from(JSON.stringify(update(data)));
return f; return f;
})) }))
.pipe(packageJsonFilter.restore); .pipe(packageJsonFilter.restore);
} }
function fromLocal(extensionPath, forWeb) { function fromLocal(extensionPath, forWeb) {
@@ -95,11 +95,11 @@ function fromLocalWebpack(extensionPath, webpackConfigFileName) {
const files = fileNames const files = fileNames
.map(fileName => path.join(extensionPath, fileName)) .map(fileName => path.join(extensionPath, fileName))
.map(filePath => new File({ .map(filePath => new File({
path: filePath, path: filePath,
stat: fs.statSync(filePath), stat: fs.statSync(filePath),
base: extensionPath, base: extensionPath,
contents: fs.createReadStream(filePath) contents: fs.createReadStream(filePath)
})); }));
// check for a webpack configuration files, then invoke webpack // check for a webpack configuration files, then invoke webpack
// and merge its output with the files stream. // and merge its output with the files stream.
const webpackConfigLocations = glob.sync(path.join(extensionPath, '**', webpackConfigFileName), { ignore: ['**/node_modules'] }); const webpackConfigLocations = glob.sync(path.join(extensionPath, '**', webpackConfigFileName), { ignore: ['**/node_modules'] });
@@ -119,24 +119,27 @@ function fromLocalWebpack(extensionPath, webpackConfigFileName) {
}; };
const exportedConfig = require(webpackConfigPath); const exportedConfig = require(webpackConfigPath);
return (Array.isArray(exportedConfig) ? exportedConfig : [exportedConfig]).map(config => { return (Array.isArray(exportedConfig) ? exportedConfig : [exportedConfig]).map(config => {
const webpackConfig = Object.assign(Object.assign({}, config), { mode: 'production' }); const webpackConfig = {
...config,
...{ mode: 'production' }
};
const relativeOutputPath = path.relative(extensionPath, webpackConfig.output.path); const relativeOutputPath = path.relative(extensionPath, webpackConfig.output.path);
return webpackGulp(webpackConfig, webpack, webpackDone) return webpackGulp(webpackConfig, webpack, webpackDone)
.pipe(es.through(function (data) { .pipe(es.through(function (data) {
data.stat = data.stat || {}; data.stat = data.stat || {};
data.base = extensionPath; data.base = extensionPath;
this.emit('data', data); this.emit('data', data);
})) }))
.pipe(es.through(function (data) { .pipe(es.through(function (data) {
// source map handling: // source map handling:
// * rewrite sourceMappingURL // * rewrite sourceMappingURL
// * save to disk so that upload-task picks this up // * save to disk so that upload-task picks this up
const contents = data.contents.toString('utf8'); const contents = data.contents.toString('utf8');
data.contents = Buffer.from(contents.replace(/\n\/\/# sourceMappingURL=(.*)$/gm, function (_m, g1) { data.contents = Buffer.from(contents.replace(/\n\/\/# sourceMappingURL=(.*)$/gm, function (_m, g1) {
return `\n//# sourceMappingURL=${sourceMappingURLBase}/extensions/${path.basename(extensionPath)}/${relativeOutputPath}/${g1}`; return `\n//# sourceMappingURL=${sourceMappingURLBase}/extensions/${path.basename(extensionPath)}/${relativeOutputPath}/${g1}`;
}), 'utf8'); }), 'utf8');
this.emit('data', data); this.emit('data', data);
})); }));
}); });
}); });
es.merge(...webpackStreams, es.readArray(files)) es.merge(...webpackStreams, es.readArray(files))
@@ -158,16 +161,16 @@ function fromLocalNormal(extensionPath) {
const result = es.through(); const result = es.through();
vsce.listFiles({ cwd: extensionPath, packageManager: vsce.PackageManager.Yarn }) vsce.listFiles({ cwd: extensionPath, packageManager: vsce.PackageManager.Yarn })
.then(fileNames => { .then(fileNames => {
const files = fileNames const files = fileNames
.map(fileName => path.join(extensionPath, fileName)) .map(fileName => path.join(extensionPath, fileName))
.map(filePath => new File({ .map(filePath => new File({
path: filePath, path: filePath,
stat: fs.statSync(filePath), stat: fs.statSync(filePath),
base: extensionPath, base: extensionPath,
contents: fs.createReadStream(filePath) contents: fs.createReadStream(filePath)
})); }));
es.readArray(files).pipe(result); es.readArray(files).pipe(result);
}) })
.catch(err => result.emit('error', err)); .catch(err => result.emit('error', err));
return result.pipe((0, stats_1.createStatsStream)(path.basename(extensionPath))); return result.pipe((0, stats_1.createStatsStream)(path.basename(extensionPath)));
} }
@@ -209,7 +212,10 @@ const ghApiHeaders = {
if (process.env.GITHUB_TOKEN) { if (process.env.GITHUB_TOKEN) {
ghApiHeaders.Authorization = 'Basic ' + Buffer.from(process.env.GITHUB_TOKEN).toString('base64'); ghApiHeaders.Authorization = 'Basic ' + Buffer.from(process.env.GITHUB_TOKEN).toString('base64');
} }
const ghDownloadHeaders = Object.assign(Object.assign({}, ghApiHeaders), { Accept: 'application/octet-stream' }); const ghDownloadHeaders = {
...ghApiHeaders,
Accept: 'application/octet-stream',
};
function fromGithub({ name, version, repo, metadata }) { function fromGithub({ name, version, repo, metadata }) {
const remote = require('gulp-remote-retry-src'); const remote = require('gulp-remote-retry-src');
const json = require('gulp-json-editor'); const json = require('gulp-json-editor');
@@ -244,6 +250,7 @@ const excludedExtensions = [
'ms-vscode.node-debug', 'ms-vscode.node-debug',
'ms-vscode.node-debug2', 'ms-vscode.node-debug2',
'vscode-custom-editor-tests', 'vscode-custom-editor-tests',
'vscode-notebook-tests',
'integration-tests', // {{SQL CARBON EDIT}} 'integration-tests', // {{SQL CARBON EDIT}}
]; ];
// {{SQL CARBON EDIT}} // {{SQL CARBON EDIT}}
@@ -258,7 +265,6 @@ const externalExtensions = [
'arc', 'arc',
'asde-deployment', 'asde-deployment',
'azcli', 'azcli',
'azurehybridtoolkit',
'azuremonitor', 'azuremonitor',
'cms', 'cms',
'dacpac', 'dacpac',
@@ -324,11 +330,11 @@ function isWebExtension(manifest) {
function packageLocalExtensionsStream(forWeb) { function packageLocalExtensionsStream(forWeb) {
const localExtensionsDescriptions = (glob.sync('extensions/*/package.json') const localExtensionsDescriptions = (glob.sync('extensions/*/package.json')
.map(manifestPath => { .map(manifestPath => {
const absoluteManifestPath = path.join(root, manifestPath); const absoluteManifestPath = path.join(root, manifestPath);
const extensionPath = path.dirname(path.join(root, manifestPath)); const extensionPath = path.dirname(path.join(root, manifestPath));
const extensionName = path.basename(extensionPath); const extensionName = path.basename(extensionPath);
return { name: extensionName, path: extensionPath, manifestPath: absoluteManifestPath }; return { name: extensionName, path: extensionPath, manifestPath: absoluteManifestPath };
}) })
.filter(({ name }) => excludedExtensions.indexOf(name) === -1) .filter(({ name }) => excludedExtensions.indexOf(name) === -1)
.filter(({ name }) => builtInExtensions.every(b => b.name !== name)) .filter(({ name }) => builtInExtensions.every(b => b.name !== name))
.filter(({ name }) => externalExtensions.indexOf(name) === -1) // {{SQL CARBON EDIT}} Remove external Extensions with separate package .filter(({ name }) => externalExtensions.indexOf(name) === -1) // {{SQL CARBON EDIT}} Remove external Extensions with separate package
@@ -359,15 +365,15 @@ function packageMarketplaceExtensionsStream(forWeb, galleryServiceUrl) {
]; ];
const marketplaceExtensionsStream = minifyExtensionResources(es.merge(...marketplaceExtensionsDescriptions const marketplaceExtensionsStream = minifyExtensionResources(es.merge(...marketplaceExtensionsDescriptions
.map(extension => { .map(extension => {
const input = (galleryServiceUrl ? fromMarketplace(galleryServiceUrl, extension) : fromGithub(extension)) const input = (galleryServiceUrl ? fromMarketplace(galleryServiceUrl, extension) : fromGithub(extension))
.pipe(rename(p => p.dirname = `extensions/${extension.name}/${p.dirname}`)); .pipe(rename(p => p.dirname = `extensions/${extension.name}/${p.dirname}`));
return updateExtensionPackageJSON(input, (data) => { return updateExtensionPackageJSON(input, (data) => {
delete data.scripts; delete data.scripts;
delete data.dependencies; delete data.dependencies;
delete data.devDependencies; delete data.devDependencies;
return data; return data;
}); });
}))); })));
return (marketplaceExtensionsStream return (marketplaceExtensionsStream
.pipe(util2.setExecutableBit(['**/*.sh']))); .pipe(util2.setExecutableBit(['**/*.sh'])));
} }
@@ -412,10 +418,10 @@ exports.scanBuiltinExtensions = scanBuiltinExtensions;
function packageExternalExtensionsStream() { function packageExternalExtensionsStream() {
const extenalExtensionDescriptions = glob.sync('extensions/*/package.json') const extenalExtensionDescriptions = glob.sync('extensions/*/package.json')
.map(manifestPath => { .map(manifestPath => {
const extensionPath = path.dirname(path.join(root, manifestPath)); const extensionPath = path.dirname(path.join(root, manifestPath));
const extensionName = path.basename(extensionPath); const extensionName = path.basename(extensionPath);
return { name: extensionName, path: extensionPath }; return { name: extensionName, path: extensionPath };
}) })
.filter(({ name }) => externalExtensions.indexOf(name) >= 0 || exports.vscodeExternalExtensions.indexOf(name) >= 0); .filter(({ name }) => externalExtensions.indexOf(name) >= 0 || exports.vscodeExternalExtensions.indexOf(name) >= 0);
const builtExtensions = extenalExtensionDescriptions.map(extension => { const builtExtensions = extenalExtensionDescriptions.map(extension => {
return fromLocal(extension.path, false) return fromLocal(extension.path, false)
@@ -433,10 +439,10 @@ exports.cleanRebuildExtensions = cleanRebuildExtensions;
function packageRebuildExtensionsStream() { function packageRebuildExtensionsStream() {
const extenalExtensionDescriptions = glob.sync('extensions/*/package.json') const extenalExtensionDescriptions = glob.sync('extensions/*/package.json')
.map(manifestPath => { .map(manifestPath => {
const extensionPath = path.dirname(path.join(root, manifestPath)); const extensionPath = path.dirname(path.join(root, manifestPath));
const extensionName = path.basename(extensionPath); const extensionName = path.basename(extensionPath);
return { name: extensionName, path: extensionPath }; return { name: extensionName, path: extensionPath };
}) })
.filter(({ name }) => rebuildExtensions.indexOf(name) >= 0); .filter(({ name }) => rebuildExtensions.indexOf(name) >= 0);
const builtExtensions = extenalExtensionDescriptions.map(extension => { const builtExtensions = extenalExtensionDescriptions.map(extension => {
return fromLocal(extension.path, false) return fromLocal(extension.path, false)
@@ -530,7 +536,7 @@ async function webpackExtensions(taskName, isWatch, webpackConfigLocations) {
reject(); reject();
} }
else { else {
reporter(stats === null || stats === void 0 ? void 0 : stats.toJson()); reporter(stats?.toJson());
} }
}); });
} }
@@ -541,7 +547,7 @@ async function webpackExtensions(taskName, isWatch, webpackConfigLocations) {
reject(); reject();
} }
else { else {
reporter(stats === null || stats === void 0 ? void 0 : stats.toJson()); reporter(stats?.toJson());
resolve(); resolve();
} }
}); });

View File

@@ -1012,7 +1012,7 @@ function prepareI18nFiles() {
} }
exports.prepareI18nFiles = prepareI18nFiles; exports.prepareI18nFiles = prepareI18nFiles;
function createI18nFile(originalFilePath, messages) { function createI18nFile(originalFilePath, messages) {
const result = Object.create(null); let result = Object.create(null);
result[''] = [ result[''] = [
'--------------------------------------------------------------------------------------------', '--------------------------------------------------------------------------------------------',
'Copyright (c) Microsoft Corporation. All rights reserved.', 'Copyright (c) Microsoft Corporation. All rights reserved.',
@@ -1035,16 +1035,16 @@ function createI18nFile(originalFilePath, messages) {
exports.createI18nFile = createI18nFile; exports.createI18nFile = createI18nFile;
exports.i18nPackVersion = '1.0.0'; // {{SQL CARBON EDIT}} Needed in locfunc. exports.i18nPackVersion = '1.0.0'; // {{SQL CARBON EDIT}} Needed in locfunc.
function prepareI18nPackFiles(externalExtensions, resultingTranslationPaths, pseudo = false) { function prepareI18nPackFiles(externalExtensions, resultingTranslationPaths, pseudo = false) {
let parsePromises = []; const parsePromises = [];
let mainPack = { version: exports.i18nPackVersion, contents: {} }; const mainPack = { version: exports.i18nPackVersion, contents: {} };
let extensionsPacks = {}; const extensionsPacks = {};
let errors = []; const errors = [];
return (0, event_stream_1.through)(function (xlf) { return (0, event_stream_1.through)(function (xlf) {
let project = path.basename(path.dirname(path.dirname(xlf.relative))); const project = path.basename(path.dirname(path.dirname(xlf.relative)));
let resource = path.basename(xlf.relative, '.xlf'); const resource = path.basename(xlf.relative, '.xlf');
let contents = xlf.contents.toString(); const contents = xlf.contents.toString();
log(`Found ${project}: ${resource}`); log(`Found ${project}: ${resource}`);
let parsePromise = pseudo ? XLF.parsePseudo(contents) : XLF.parse(contents); const parsePromise = pseudo ? XLF.parsePseudo(contents) : XLF.parse(contents);
parsePromises.push(parsePromise); parsePromises.push(parsePromise);
parsePromise.then(resolvedFiles => { parsePromise.then(resolvedFiles => {
resolvedFiles.forEach(file => { resolvedFiles.forEach(file => {

View File

@@ -113,7 +113,7 @@ const RULES = [
}, },
// Common: vs/platform/native/common/native.ts // Common: vs/platform/native/common/native.ts
{ {
target: '**/vs/platform/native/common/native.ts', target: '**/{vs,sql}/platform/native/common/native.ts',
allowedTypes: CORE_TYPES, allowedTypes: CORE_TYPES,
disallowedTypes: [ /* Ignore native types that are defined from here */], disallowedTypes: [ /* Ignore native types that are defined from here */],
disallowedDefinitions: [ disallowedDefinitions: [
@@ -209,7 +209,6 @@ let hasErrors = false;
function checkFile(program, sourceFile, rule) { function checkFile(program, sourceFile, rule) {
checkNode(sourceFile); checkNode(sourceFile);
function checkNode(node) { function checkNode(node) {
var _a, _b;
if (node.kind !== ts.SyntaxKind.Identifier) { if (node.kind !== ts.SyntaxKind.Identifier) {
return ts.forEachChild(node, checkNode); // recurse down return ts.forEachChild(node, checkNode); // recurse down
} }
@@ -224,10 +223,10 @@ function checkFile(program, sourceFile, rule) {
} }
const parentSymbol = _parentSymbol; const parentSymbol = _parentSymbol;
const text = parentSymbol.getName(); const text = parentSymbol.getName();
if ((_a = rule.allowedTypes) === null || _a === void 0 ? void 0 : _a.some(allowed => allowed === text)) { if (rule.allowedTypes?.some(allowed => allowed === text)) {
return; // override return; // override
} }
if ((_b = rule.disallowedTypes) === null || _b === void 0 ? void 0 : _b.some(disallowed => disallowed === text)) { if (rule.disallowedTypes?.some(disallowed => disallowed === text)) {
const { line, character } = sourceFile.getLineAndCharacterOfPosition(node.getStart()); const { line, character } = sourceFile.getLineAndCharacterOfPosition(node.getStart());
console.log(`[build/lib/layersChecker.ts]: Reference to type '${text}' violates layer '${rule.target}' (${sourceFile.fileName} (${line + 1},${character + 1})`); console.log(`[build/lib/layersChecker.ts]: Reference to type '${text}' violates layer '${rule.target}' (${sourceFile.fileName} (${line + 1},${character + 1})`);
hasErrors = true; hasErrors = true;

View File

@@ -77,6 +77,12 @@ const RULES: IRule[] = [
skip: true // -> skip all test files skip: true // -> skip all test files
}, },
// TODO@bpasero remove me once electron utility process has landed
{
target: '**/vs/workbench/services/extensions/electron-sandbox/nativeLocalProcessExtensionHost.ts',
skip: true
},
// Common: vs/base/common/platform.ts // Common: vs/base/common/platform.ts
{ {
target: '**/{vs,sql}/base/common/platform.ts', target: '**/{vs,sql}/base/common/platform.ts',
@@ -117,7 +123,7 @@ const RULES: IRule[] = [
// Common: vs/platform/native/common/native.ts // Common: vs/platform/native/common/native.ts
{ {
target: '**/vs/platform/native/common/native.ts', target: '**/{vs,sql}/platform/native/common/native.ts',
allowedTypes: CORE_TYPES, allowedTypes: CORE_TYPES,
disallowedTypes: [/* Ignore native types that are defined from here */], disallowedTypes: [/* Ignore native types that are defined from here */],
disallowedDefinitions: [ disallowedDefinitions: [

View File

@@ -71,7 +71,7 @@ function updateMainI18nFile(existingTranslationFilePath, originalFilePath, messa
delete objectContents[`${contentKey}`]; delete objectContents[`${contentKey}`];
} }
} }
messages.contents = Object.assign(Object.assign({}, objectContents), messages.contents); messages.contents = { ...objectContents, ...messages.contents };
result[''] = [ result[''] = [
'--------------------------------------------------------------------------------------------', '--------------------------------------------------------------------------------------------',
'Copyright (c) Microsoft Corporation. All rights reserved.', 'Copyright (c) Microsoft Corporation. All rights reserved.',
@@ -141,9 +141,7 @@ function modifyI18nPackFiles(existingTranslationFolder, resultingTranslationPath
this.queue(translatedExtFile); this.queue(translatedExtFile);
// exclude altered vscode extensions from having a new path even if we provide a new I18n file. // exclude altered vscode extensions from having a new path even if we provide a new I18n file.
if (alteredVSCodeExtensions.indexOf(extension) === -1) { if (alteredVSCodeExtensions.indexOf(extension) === -1) {
//handle edge case for 'Microsoft.sqlservernotebook' where extension name is the same as extension ID. let adsExtensionId = 'Microsoft.' + extension;
//(Other extensions need to have publisher appended in front as their ID.)
let adsExtensionId = (extension === 'Microsoft.sqlservernotebook') ? extension : 'Microsoft.' + extension;
resultingTranslationPaths.push({ id: adsExtensionId, resourceName: `extensions/${extension}.i18n.json` }); resultingTranslationPaths.push({ id: adsExtensionId, resourceName: `extensions/${extension}.i18n.json` });
} }
} }
@@ -248,7 +246,7 @@ function refreshLangpacks() {
try { try {
fs.statSync(locExtFolder); fs.statSync(locExtFolder);
} }
catch (_a) { catch {
console.log('Language is not included in ADS yet: ' + langId); console.log('Language is not included in ADS yet: ' + langId);
continue; continue;
} }
@@ -311,7 +309,7 @@ function refreshLangpacks() {
} }
fs.statSync(path.join(translationDataFolder, curr.path.replace('./translations', ''))); fs.statSync(path.join(translationDataFolder, curr.path.replace('./translations', '')));
} }
catch (_a) { catch {
nonExistantExtensions.push(curr); nonExistantExtensions.push(curr);
} }
} }
@@ -365,7 +363,7 @@ function renameVscodeLangpacks() {
try { try {
fs.statSync(locVSCODEFolder); fs.statSync(locVSCODEFolder);
} }
catch (_a) { catch {
console.log('vscode pack is not in ADS yet: ' + langId); console.log('vscode pack is not in ADS yet: ' + langId);
continue; continue;
} }

View File

@@ -1,7 +1,7 @@
"use strict"; "use strict";
/*--------------------------------------------------------------------------------------------- /*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved. * Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information. * Licensed under the Source EULA. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/ *--------------------------------------------------------------------------------------------*/
Object.defineProperty(exports, "__esModule", { value: true }); Object.defineProperty(exports, "__esModule", { value: true });
const child_process_1 = require("child_process"); const child_process_1 = require("child_process");
@@ -95,10 +95,6 @@ class BooleanPolicy extends BasePolicy {
} }
} }
class IntPolicy extends BasePolicy { class IntPolicy extends BasePolicy {
constructor(name, category, minimumVersion, description, moduleName, defaultValue) {
super(PolicyType.StringEnum, name, category, minimumVersion, description, moduleName);
this.defaultValue = defaultValue;
}
static from(name, category, minimumVersion, description, moduleName, settingNode) { static from(name, category, minimumVersion, description, moduleName, settingNode) {
const type = getStringProperty(settingNode, 'type'); const type = getStringProperty(settingNode, 'type');
if (type !== 'number') { if (type !== 'number') {
@@ -110,6 +106,10 @@ class IntPolicy extends BasePolicy {
} }
return new IntPolicy(name, category, minimumVersion, description, moduleName, defaultValue); return new IntPolicy(name, category, minimumVersion, description, moduleName, defaultValue);
} }
constructor(name, category, minimumVersion, description, moduleName, defaultValue) {
super(PolicyType.StringEnum, name, category, minimumVersion, description, moduleName);
this.defaultValue = defaultValue;
}
renderADMXElements() { renderADMXElements() {
return [ return [
`<decimal id="${this.name}" valueName="${this.name}" />` `<decimal id="${this.name}" valueName="${this.name}" />`
@@ -139,11 +139,6 @@ class StringPolicy extends BasePolicy {
} }
} }
class StringEnumPolicy extends BasePolicy { class StringEnumPolicy extends BasePolicy {
constructor(name, category, minimumVersion, description, moduleName, enum_, enumDescriptions) {
super(PolicyType.StringEnum, name, category, minimumVersion, description, moduleName);
this.enum_ = enum_;
this.enumDescriptions = enumDescriptions;
}
static from(name, category, minimumVersion, description, moduleName, settingNode) { static from(name, category, minimumVersion, description, moduleName, settingNode) {
const type = getStringProperty(settingNode, 'type'); const type = getStringProperty(settingNode, 'type');
if (type !== 'string') { if (type !== 'string') {
@@ -165,6 +160,11 @@ class StringEnumPolicy extends BasePolicy {
} }
return new StringEnumPolicy(name, category, minimumVersion, description, moduleName, enum_, enumDescriptions); return new StringEnumPolicy(name, category, minimumVersion, description, moduleName, enum_, enumDescriptions);
} }
constructor(name, category, minimumVersion, description, moduleName, enum_, enumDescriptions) {
super(PolicyType.StringEnum, name, category, minimumVersion, description, moduleName);
this.enum_ = enum_;
this.enumDescriptions = enumDescriptions;
}
renderADMXElements() { renderADMXElements() {
return [ return [
`<enum id="${this.name}" valueName="${this.name}">`, `<enum id="${this.name}" valueName="${this.name}">`,

View File

@@ -13,7 +13,7 @@ const rootDir = path.resolve(__dirname, '..', '..');
function runProcess(command, args = []) { function runProcess(command, args = []) {
return new Promise((resolve, reject) => { return new Promise((resolve, reject) => {
const child = (0, child_process_1.spawn)(command, args, { cwd: rootDir, stdio: 'inherit', env: process.env }); const child = (0, child_process_1.spawn)(command, args, { cwd: rootDir, stdio: 'inherit', env: process.env });
child.on('exit', err => !err ? resolve() : process.exit(err !== null && err !== void 0 ? err : 1)); child.on('exit', err => !err ? resolve() : process.exit(err ?? 1));
child.on('error', reject); child.on('error', reject);
}); });
} }
@@ -22,7 +22,7 @@ async function exists(subdir) {
await fs_1.promises.stat(path.join(rootDir, subdir)); await fs_1.promises.stat(path.join(rootDir, subdir));
return true; return true;
} }
catch (_a) { catch {
return false; return false;
} }
} }

View File

@@ -27,7 +27,6 @@ function writeFile(filePath, contents) {
fs.writeFileSync(filePath, contents); fs.writeFileSync(filePath, contents);
} }
function extractEditor(options) { function extractEditor(options) {
var _a;
const ts = require('typescript'); const ts = require('typescript');
const tsConfig = JSON.parse(fs.readFileSync(path.join(options.sourcesRoot, 'tsconfig.monaco.json')).toString()); const tsConfig = JSON.parse(fs.readFileSync(path.join(options.sourcesRoot, 'tsconfig.monaco.json')).toString());
let compilerOptions; let compilerOptions;
@@ -49,7 +48,7 @@ function extractEditor(options) {
// Take the extra included .d.ts files from `tsconfig.monaco.json` // Take the extra included .d.ts files from `tsconfig.monaco.json`
options.typings = tsConfig.include.filter(includedFile => /\.d\.ts$/.test(includedFile)); options.typings = tsConfig.include.filter(includedFile => /\.d\.ts$/.test(includedFile));
// Add extra .d.ts files from `node_modules/@types/` // Add extra .d.ts files from `node_modules/@types/`
if (Array.isArray((_a = options.compilerOptions) === null || _a === void 0 ? void 0 : _a.types)) { if (Array.isArray(options.compilerOptions?.types)) {
options.compilerOptions.types.forEach((type) => { options.compilerOptions.types.forEach((type) => {
options.typings.push(`../node_modules/@types/${type}/index.d.ts`); options.typings.push(`../node_modules/@types/${type}/index.d.ts`);
}); });

View File

@@ -16,11 +16,11 @@ var ShakeLevel;
})(ShakeLevel = exports.ShakeLevel || (exports.ShakeLevel = {})); })(ShakeLevel = exports.ShakeLevel || (exports.ShakeLevel = {}));
function toStringShakeLevel(shakeLevel) { function toStringShakeLevel(shakeLevel) {
switch (shakeLevel) { switch (shakeLevel) {
case 0 /* Files */: case 0 /* ShakeLevel.Files */:
return 'Files (0)'; return 'Files (0)';
case 1 /* InnerFile */: case 1 /* ShakeLevel.InnerFile */:
return 'InnerFile (1)'; return 'InnerFile (1)';
case 2 /* ClassMembers */: case 2 /* ShakeLevel.ClassMembers */:
return 'ClassMembers (2)'; return 'ClassMembers (2)';
} }
} }
@@ -223,7 +223,7 @@ var NodeColor;
NodeColor[NodeColor["Black"] = 2] = "Black"; NodeColor[NodeColor["Black"] = 2] = "Black";
})(NodeColor || (NodeColor = {})); })(NodeColor || (NodeColor = {}));
function getColor(node) { function getColor(node) {
return node.$$$color || 0 /* White */; return node.$$$color || 0 /* NodeColor.White */;
} }
function setColor(node, color) { function setColor(node, color) {
node.$$$color = color; node.$$$color = color;
@@ -237,7 +237,7 @@ function isNeededSourceFile(node) {
function nodeOrParentIsBlack(node) { function nodeOrParentIsBlack(node) {
while (node) { while (node) {
const color = getColor(node); const color = getColor(node);
if (color === 2 /* Black */) { if (color === 2 /* NodeColor.Black */) {
return true; return true;
} }
node = node.parent; node = node.parent;
@@ -245,7 +245,7 @@ function nodeOrParentIsBlack(node) {
return false; return false;
} }
function nodeOrChildIsBlack(node) { function nodeOrChildIsBlack(node) {
if (getColor(node) === 2 /* Black */) { if (getColor(node) === 2 /* NodeColor.Black */) {
return true; return true;
} }
for (const child of node.getChildren()) { for (const child of node.getChildren()) {
@@ -309,10 +309,10 @@ function markNodes(ts, languageService, options) {
if (!program) { if (!program) {
throw new Error('Could not get program from language service'); throw new Error('Could not get program from language service');
} }
if (options.shakeLevel === 0 /* Files */) { if (options.shakeLevel === 0 /* ShakeLevel.Files */) {
// Mark all source files Black // Mark all source files Black
program.getSourceFiles().forEach((sourceFile) => { program.getSourceFiles().forEach((sourceFile) => {
setColor(sourceFile, 2 /* Black */); setColor(sourceFile, 2 /* NodeColor.Black */);
}); });
return; return;
} }
@@ -324,7 +324,7 @@ function markNodes(ts, languageService, options) {
sourceFile.forEachChild((node) => { sourceFile.forEachChild((node) => {
if (ts.isImportDeclaration(node)) { if (ts.isImportDeclaration(node)) {
if (!node.importClause && ts.isStringLiteral(node.moduleSpecifier)) { if (!node.importClause && ts.isStringLiteral(node.moduleSpecifier)) {
setColor(node, 2 /* Black */); setColor(node, 2 /* NodeColor.Black */);
enqueueImport(node, node.moduleSpecifier.text); enqueueImport(node, node.moduleSpecifier.text);
} }
return; return;
@@ -332,7 +332,7 @@ function markNodes(ts, languageService, options) {
if (ts.isExportDeclaration(node)) { if (ts.isExportDeclaration(node)) {
if (!node.exportClause && node.moduleSpecifier && ts.isStringLiteral(node.moduleSpecifier)) { if (!node.exportClause && node.moduleSpecifier && ts.isStringLiteral(node.moduleSpecifier)) {
// export * from "foo"; // export * from "foo";
setColor(node, 2 /* Black */); setColor(node, 2 /* NodeColor.Black */);
enqueueImport(node, node.moduleSpecifier.text); enqueueImport(node, node.moduleSpecifier.text);
} }
if (node.exportClause && ts.isNamedExports(node.exportClause)) { if (node.exportClause && ts.isNamedExports(node.exportClause)) {
@@ -373,21 +373,21 @@ function markNodes(ts, languageService, options) {
return null; return null;
} }
function enqueue_gray(node) { function enqueue_gray(node) {
if (nodeOrParentIsBlack(node) || getColor(node) === 1 /* Gray */) { if (nodeOrParentIsBlack(node) || getColor(node) === 1 /* NodeColor.Gray */) {
return; return;
} }
setColor(node, 1 /* Gray */); setColor(node, 1 /* NodeColor.Gray */);
gray_queue.push(node); gray_queue.push(node);
} }
function enqueue_black(node) { function enqueue_black(node) {
const previousColor = getColor(node); const previousColor = getColor(node);
if (previousColor === 2 /* Black */) { if (previousColor === 2 /* NodeColor.Black */) {
return; return;
} }
if (previousColor === 1 /* Gray */) { if (previousColor === 1 /* NodeColor.Gray */) {
// remove from gray queue // remove from gray queue
gray_queue.splice(gray_queue.indexOf(node), 1); gray_queue.splice(gray_queue.indexOf(node), 1);
setColor(node, 0 /* White */); setColor(node, 0 /* NodeColor.White */);
// add to black queue // add to black queue
enqueue_black(node); enqueue_black(node);
// move from one queue to the other // move from one queue to the other
@@ -400,7 +400,7 @@ function markNodes(ts, languageService, options) {
} }
const fileName = node.getSourceFile().fileName; const fileName = node.getSourceFile().fileName;
if (/^defaultLib:/.test(fileName) || /\.d\.ts$/.test(fileName)) { if (/^defaultLib:/.test(fileName) || /\.d\.ts$/.test(fileName)) {
setColor(node, 2 /* Black */); setColor(node, 2 /* NodeColor.Black */);
return; return;
} }
const sourceFile = node.getSourceFile(); const sourceFile = node.getSourceFile();
@@ -411,9 +411,9 @@ function markNodes(ts, languageService, options) {
if (ts.isSourceFile(node)) { if (ts.isSourceFile(node)) {
return; return;
} }
setColor(node, 2 /* Black */); setColor(node, 2 /* NodeColor.Black */);
black_queue.push(node); black_queue.push(node);
if (options.shakeLevel === 2 /* ClassMembers */ && (ts.isMethodDeclaration(node) || ts.isMethodSignature(node) || ts.isPropertySignature(node) || ts.isPropertyDeclaration(node) || ts.isGetAccessor(node) || ts.isSetAccessor(node))) { if (options.shakeLevel === 2 /* ShakeLevel.ClassMembers */ && (ts.isMethodDeclaration(node) || ts.isMethodSignature(node) || ts.isPropertySignature(node) || ts.isPropertyDeclaration(node) || ts.isGetAccessor(node) || ts.isSetAccessor(node))) {
const references = languageService.getReferencesAtPosition(node.getSourceFile().fileName, node.name.pos + node.name.getLeadingTriviaWidth()); const references = languageService.getReferencesAtPosition(node.getSourceFile().fileName, node.name.pos + node.name.getLeadingTriviaWidth());
if (references) { if (references) {
for (let i = 0, len = references.length; i < len; i++) { for (let i = 0, len = references.length; i < len; i++) {
@@ -476,7 +476,7 @@ function markNodes(ts, languageService, options) {
if ((ts.isClassDeclaration(nodeParent) || ts.isInterfaceDeclaration(nodeParent)) && nodeOrChildIsBlack(nodeParent)) { if ((ts.isClassDeclaration(nodeParent) || ts.isInterfaceDeclaration(nodeParent)) && nodeOrChildIsBlack(nodeParent)) {
gray_queue.splice(i, 1); gray_queue.splice(i, 1);
black_queue.push(node); black_queue.push(node);
setColor(node, 2 /* Black */); setColor(node, 2 /* NodeColor.Black */);
i--; i--;
} }
} }
@@ -506,7 +506,7 @@ function markNodes(ts, languageService, options) {
// (they can be the declaration of a module import) // (they can be the declaration of a module import)
continue; continue;
} }
if (options.shakeLevel === 2 /* ClassMembers */ && (ts.isClassDeclaration(declaration) || ts.isInterfaceDeclaration(declaration)) && !isLocalCodeExtendingOrInheritingFromDefaultLibSymbol(ts, program, checker, declaration)) { if (options.shakeLevel === 2 /* ShakeLevel.ClassMembers */ && (ts.isClassDeclaration(declaration) || ts.isInterfaceDeclaration(declaration)) && !isLocalCodeExtendingOrInheritingFromDefaultLibSymbol(ts, program, checker, declaration)) {
enqueue_black(declaration.name); enqueue_black(declaration.name);
for (let j = 0; j < declaration.members.length; j++) { for (let j = 0; j < declaration.members.length; j++) {
const member = declaration.members[j]; const member = declaration.members[j];
@@ -556,7 +556,7 @@ function markNodes(ts, languageService, options) {
const aliased = checker.getAliasedSymbol(symbol); const aliased = checker.getAliasedSymbol(symbol);
if (aliased.declarations && aliased.declarations.length > 0) { if (aliased.declarations && aliased.declarations.length > 0) {
if (nodeOrParentIsBlack(aliased.declarations[0]) || nodeOrChildIsBlack(aliased.declarations[0])) { if (nodeOrParentIsBlack(aliased.declarations[0]) || nodeOrChildIsBlack(aliased.declarations[0])) {
setColor(node, 2 /* Black */); setColor(node, 2 /* NodeColor.Black */);
} }
} }
} }
@@ -603,7 +603,7 @@ function generateResult(ts, languageService, shakeLevel) {
result += data; result += data;
} }
function writeMarkedNodes(node) { function writeMarkedNodes(node) {
if (getColor(node) === 2 /* Black */) { if (getColor(node) === 2 /* NodeColor.Black */) {
return keep(node); return keep(node);
} }
// Always keep certain top-level statements // Always keep certain top-level statements
@@ -619,34 +619,34 @@ function generateResult(ts, languageService, shakeLevel) {
if (ts.isImportDeclaration(node)) { if (ts.isImportDeclaration(node)) {
if (node.importClause && node.importClause.namedBindings) { if (node.importClause && node.importClause.namedBindings) {
if (ts.isNamespaceImport(node.importClause.namedBindings)) { if (ts.isNamespaceImport(node.importClause.namedBindings)) {
if (getColor(node.importClause.namedBindings) === 2 /* Black */) { if (getColor(node.importClause.namedBindings) === 2 /* NodeColor.Black */) {
return keep(node); return keep(node);
} }
} }
else { else {
const survivingImports = []; const survivingImports = [];
for (const importNode of node.importClause.namedBindings.elements) { for (const importNode of node.importClause.namedBindings.elements) {
if (getColor(importNode) === 2 /* Black */) { if (getColor(importNode) === 2 /* NodeColor.Black */) {
survivingImports.push(importNode.getFullText(sourceFile)); survivingImports.push(importNode.getFullText(sourceFile));
} }
} }
const leadingTriviaWidth = node.getLeadingTriviaWidth(); const leadingTriviaWidth = node.getLeadingTriviaWidth();
const leadingTrivia = sourceFile.text.substr(node.pos, leadingTriviaWidth); const leadingTrivia = sourceFile.text.substr(node.pos, leadingTriviaWidth);
if (survivingImports.length > 0) { if (survivingImports.length > 0) {
if (node.importClause && node.importClause.name && getColor(node.importClause) === 2 /* Black */) { if (node.importClause && node.importClause.name && getColor(node.importClause) === 2 /* NodeColor.Black */) {
return write(`${leadingTrivia}import ${node.importClause.name.text}, {${survivingImports.join(',')} } from${node.moduleSpecifier.getFullText(sourceFile)};`); return write(`${leadingTrivia}import ${node.importClause.name.text}, {${survivingImports.join(',')} } from${node.moduleSpecifier.getFullText(sourceFile)};`);
} }
return write(`${leadingTrivia}import {${survivingImports.join(',')} } from${node.moduleSpecifier.getFullText(sourceFile)};`); return write(`${leadingTrivia}import {${survivingImports.join(',')} } from${node.moduleSpecifier.getFullText(sourceFile)};`);
} }
else { else {
if (node.importClause && node.importClause.name && getColor(node.importClause) === 2 /* Black */) { if (node.importClause && node.importClause.name && getColor(node.importClause) === 2 /* NodeColor.Black */) {
return write(`${leadingTrivia}import ${node.importClause.name.text} from${node.moduleSpecifier.getFullText(sourceFile)};`); return write(`${leadingTrivia}import ${node.importClause.name.text} from${node.moduleSpecifier.getFullText(sourceFile)};`);
} }
} }
} }
} }
else { else {
if (node.importClause && getColor(node.importClause) === 2 /* Black */) { if (node.importClause && getColor(node.importClause) === 2 /* NodeColor.Black */) {
return keep(node); return keep(node);
} }
} }
@@ -655,7 +655,7 @@ function generateResult(ts, languageService, shakeLevel) {
if (node.exportClause && node.moduleSpecifier && ts.isNamedExports(node.exportClause)) { if (node.exportClause && node.moduleSpecifier && ts.isNamedExports(node.exportClause)) {
const survivingExports = []; const survivingExports = [];
for (const exportSpecifier of node.exportClause.elements) { for (const exportSpecifier of node.exportClause.elements) {
if (getColor(exportSpecifier) === 2 /* Black */) { if (getColor(exportSpecifier) === 2 /* NodeColor.Black */) {
survivingExports.push(exportSpecifier.getFullText(sourceFile)); survivingExports.push(exportSpecifier.getFullText(sourceFile));
} }
} }
@@ -666,11 +666,11 @@ function generateResult(ts, languageService, shakeLevel) {
} }
} }
} }
if (shakeLevel === 2 /* ClassMembers */ && (ts.isClassDeclaration(node) || ts.isInterfaceDeclaration(node)) && nodeOrChildIsBlack(node)) { if (shakeLevel === 2 /* ShakeLevel.ClassMembers */ && (ts.isClassDeclaration(node) || ts.isInterfaceDeclaration(node)) && nodeOrChildIsBlack(node)) {
let toWrite = node.getFullText(); let toWrite = node.getFullText();
for (let i = node.members.length - 1; i >= 0; i--) { for (let i = node.members.length - 1; i >= 0; i--) {
const member = node.members[i]; const member = node.members[i];
if (getColor(member) === 2 /* Black */ || !member.name) { if (getColor(member) === 2 /* NodeColor.Black */ || !member.name) {
// keep method // keep method
continue; continue;
} }
@@ -686,7 +686,7 @@ function generateResult(ts, languageService, shakeLevel) {
} }
node.forEachChild(writeMarkedNodes); node.forEachChild(writeMarkedNodes);
} }
if (getColor(sourceFile) !== 2 /* Black */) { if (getColor(sourceFile) !== 2 /* NodeColor.Black */) {
if (!nodeOrChildIsBlack(sourceFile)) { if (!nodeOrChildIsBlack(sourceFile)) {
// none of the elements are reachable // none of the elements are reachable
if (isNeededSourceFile(sourceFile)) { if (isNeededSourceFile(sourceFile)) {

View File

@@ -1,7 +1,7 @@
"use strict"; "use strict";
/*--------------------------------------------------------------------------------------------- /*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved. * Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information. * Licensed under the Source EULA. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/ *--------------------------------------------------------------------------------------------*/
Object.defineProperty(exports, "__esModule", { value: true }); Object.defineProperty(exports, "__esModule", { value: true });
exports.createTypeScriptBuilder = exports.CancellationToken = void 0; exports.createTypeScriptBuilder = exports.CancellationToken = void 0;

View File

@@ -1,7 +1,7 @@
"use strict"; "use strict";
/*--------------------------------------------------------------------------------------------- /*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved. * Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information. * Licensed under the Source EULA. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/ *--------------------------------------------------------------------------------------------*/
Object.defineProperty(exports, "__esModule", { value: true }); Object.defineProperty(exports, "__esModule", { value: true });
exports.create = void 0; exports.create = void 0;

View File

@@ -1,7 +1,7 @@
"use strict"; "use strict";
/*--------------------------------------------------------------------------------------------- /*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved. * Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information. * Licensed under the Source EULA. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/ *--------------------------------------------------------------------------------------------*/
Object.defineProperty(exports, "__esModule", { value: true }); Object.defineProperty(exports, "__esModule", { value: true });
exports.Transpiler = void 0; exports.Transpiler = void 0;

View File

@@ -1,7 +1,7 @@
"use strict"; "use strict";
/*--------------------------------------------------------------------------------------------- /*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved. * Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information. * Licensed under the Source EULA. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/ *--------------------------------------------------------------------------------------------*/
Object.defineProperty(exports, "__esModule", { value: true }); Object.defineProperty(exports, "__esModule", { value: true });
exports.graph = exports.strings = exports.collections = void 0; exports.graph = exports.strings = exports.collections = void 0;

View File

@@ -304,7 +304,6 @@ function getElectronVersion() {
} }
exports.getElectronVersion = getElectronVersion; exports.getElectronVersion = getElectronVersion;
function acquireWebNodePaths() { function acquireWebNodePaths() {
var _a;
const root = path.join(__dirname, '..', '..'); const root = path.join(__dirname, '..', '..');
const webPackageJSON = path.join(root, '/remote/web', 'package.json'); const webPackageJSON = path.join(root, '/remote/web', 'package.json');
const webPackages = JSON.parse(fs.readFileSync(webPackageJSON, 'utf8')).dependencies; const webPackages = JSON.parse(fs.readFileSync(webPackageJSON, 'utf8')).dependencies;
@@ -312,7 +311,7 @@ function acquireWebNodePaths() {
for (const key of Object.keys(webPackages)) { for (const key of Object.keys(webPackages)) {
const packageJSON = path.join(root, 'node_modules', key, 'package.json'); const packageJSON = path.join(root, 'node_modules', key, 'package.json');
const packageData = JSON.parse(fs.readFileSync(packageJSON, 'utf8')); const packageData = JSON.parse(fs.readFileSync(packageJSON, 'utf8'));
let entryPoint = typeof packageData.browser === 'string' ? packageData.browser : (_a = packageData.main) !== null && _a !== void 0 ? _a : packageData.main; // {{SQL CARBON EDIT}} Some packages (like Turndown) have objects in this field instead of the entry point, fall back to main in that case let entryPoint = typeof packageData.browser === 'string' ? packageData.browser : packageData.main ?? packageData.main; // {{SQL CARBON EDIT}} Some packages (like Turndown) have objects in this field instead of the entry point, fall back to main in that case
// On rare cases a package doesn't have an entrypoint so we assume it has a dist folder with a min.js // On rare cases a package doesn't have an entrypoint so we assume it has a dist folder with a min.js
if (!entryPoint) { if (!entryPoint) {
// TODO @lramos15 remove this when jschardet adds an entrypoint so we can warn on all packages w/out entrypoint // TODO @lramos15 remove this when jschardet adds an entrypoint so we can warn on all packages w/out entrypoint

View File

@@ -1,7 +1,7 @@
"use strict"; "use strict";
/*--------------------------------------------------------------------------------------------- /*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved. * Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information. * Licensed under the Source EULA. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/ *--------------------------------------------------------------------------------------------*/
Object.defineProperty(exports, "__esModule", { value: true }); Object.defineProperty(exports, "__esModule", { value: true });
exports.referenceGeneratedDepsByArch = exports.bundledDeps = exports.recommendedDeps = exports.additionalDeps = void 0; exports.referenceGeneratedDepsByArch = exports.bundledDeps = exports.recommendedDeps = exports.additionalDeps = void 0;

View File

@@ -1,6 +1,6 @@
/*--------------------------------------------------------------------------------------------- /*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved. * Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information. * Licensed under the Source EULA. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/ *--------------------------------------------------------------------------------------------*/
'use strict'; 'use strict';
Object.defineProperty(exports, "__esModule", { value: true }); Object.defineProperty(exports, "__esModule", { value: true });
@@ -9,7 +9,7 @@ const child_process_1 = require("child_process");
const fs_1 = require("fs"); const fs_1 = require("fs");
const os_1 = require("os"); const os_1 = require("os");
const path = require("path"); const path = require("path");
const dep_lists_1 = require("./dep-lists"); const dep_lists_1 = require("./dep-lists"); // {{SQL CARBON EDIT}} Not needed
// A flag that can easily be toggled. // A flag that can easily be toggled.
// Make sure to compile the build directory after toggling the value. // Make sure to compile the build directory after toggling the value.
// If false, we warn about new dependencies if they show up // If false, we warn about new dependencies if they show up
@@ -17,7 +17,7 @@ const dep_lists_1 = require("./dep-lists");
// If true, we fail the build if there are new dependencies found during that task. // If true, we fail the build if there are new dependencies found during that task.
// The reference dependencies, which one has to update when the new dependencies // The reference dependencies, which one has to update when the new dependencies
// are valid, are in dep-lists.ts // are valid, are in dep-lists.ts
const FAIL_BUILD_FOR_NEW_DEPENDENCIES = true; // const FAIL_BUILD_FOR_NEW_DEPENDENCIES: boolean = true; {{ SQL CARBON EDIT}} Not needed
function getDependencies(buildDir, applicationName, arch, sysroot) { function getDependencies(buildDir, applicationName, arch, sysroot) {
// Get the files for which we want to find dependencies. // Get the files for which we want to find dependencies.
const nativeModulesPath = path.join(buildDir, 'resources', 'app', 'node_modules.asar.unpacked'); const nativeModulesPath = path.join(buildDir, 'resources', 'app', 'node_modules.asar.unpacked');
@@ -49,18 +49,19 @@ function getDependencies(buildDir, applicationName, arch, sysroot) {
sortedDependencies = sortedDependencies.filter(dependency => { sortedDependencies = sortedDependencies.filter(dependency => {
return !dep_lists_1.bundledDeps.some(bundledDep => dependency.startsWith(bundledDep)); return !dep_lists_1.bundledDeps.some(bundledDep => dependency.startsWith(bundledDep));
}); });
const referenceGeneratedDeps = dep_lists_1.referenceGeneratedDepsByArch[arch]; /* {{SQL CARBON EDIT}} Not needed
const referenceGeneratedDeps = referenceGeneratedDepsByArch[arch];
if (JSON.stringify(sortedDependencies) !== JSON.stringify(referenceGeneratedDeps)) { if (JSON.stringify(sortedDependencies) !== JSON.stringify(referenceGeneratedDeps)) {
const failMessage = 'The dependencies list has changed.' const failMessage = 'The dependencies list has changed.'
+ '\nOld:\n' + referenceGeneratedDeps.join('\n') + '\nOld:\n' + referenceGeneratedDeps.join('\n')
+ '\nNew:\n' + sortedDependencies.join('\n'); + '\nNew:\n' + sortedDependencies.join('\n');
if (FAIL_BUILD_FOR_NEW_DEPENDENCIES) { if (FAIL_BUILD_FOR_NEW_DEPENDENCIES) {
throw new Error(failMessage); throw new Error(failMessage);
} } else {
else {
console.warn(failMessage); console.warn(failMessage);
} }
} }
*/
return sortedDependencies; return sortedDependencies;
} }
exports.getDependencies = getDependencies; exports.getDependencies = getDependencies;

View File

@@ -9,7 +9,7 @@ import { spawnSync } from 'child_process';
import { constants, statSync } from 'fs'; import { constants, statSync } from 'fs';
import { tmpdir } from 'os'; import { tmpdir } from 'os';
import path = require('path'); import path = require('path');
import { additionalDeps, bundledDeps, referenceGeneratedDepsByArch } from './dep-lists'; import { additionalDeps, bundledDeps/*, referenceGeneratedDepsByArch*/ } from './dep-lists'; // {{SQL CARBON EDIT}} Not needed
import { ArchString } from './types'; import { ArchString } from './types';
// A flag that can easily be toggled. // A flag that can easily be toggled.
@@ -19,7 +19,7 @@ import { ArchString } from './types';
// If true, we fail the build if there are new dependencies found during that task. // If true, we fail the build if there are new dependencies found during that task.
// The reference dependencies, which one has to update when the new dependencies // The reference dependencies, which one has to update when the new dependencies
// are valid, are in dep-lists.ts // are valid, are in dep-lists.ts
const FAIL_BUILD_FOR_NEW_DEPENDENCIES: boolean = true; // const FAIL_BUILD_FOR_NEW_DEPENDENCIES: boolean = true; {{ SQL CARBON EDIT}} Not needed
export function getDependencies(buildDir: string, applicationName: string, arch: ArchString, sysroot: string): string[] { export function getDependencies(buildDir: string, applicationName: string, arch: ArchString, sysroot: string): string[] {
// Get the files for which we want to find dependencies. // Get the files for which we want to find dependencies.
@@ -59,6 +59,7 @@ export function getDependencies(buildDir: string, applicationName: string, arch:
return !bundledDeps.some(bundledDep => dependency.startsWith(bundledDep)); return !bundledDeps.some(bundledDep => dependency.startsWith(bundledDep));
}); });
/* {{SQL CARBON EDIT}} Not needed
const referenceGeneratedDeps = referenceGeneratedDepsByArch[arch]; const referenceGeneratedDeps = referenceGeneratedDepsByArch[arch];
if (JSON.stringify(sortedDependencies) !== JSON.stringify(referenceGeneratedDeps)) { if (JSON.stringify(sortedDependencies) !== JSON.stringify(referenceGeneratedDeps)) {
const failMessage = 'The dependencies list has changed.' const failMessage = 'The dependencies list has changed.'
@@ -70,6 +71,7 @@ export function getDependencies(buildDir: string, applicationName: string, arch:
console.warn(failMessage); console.warn(failMessage);
} }
} }
*/
return sortedDependencies; return sortedDependencies;
} }

View File

@@ -1,7 +1,7 @@
"use strict"; "use strict";
/*--------------------------------------------------------------------------------------------- /*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved. * Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information. * Licensed under the Source EULA. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/ *--------------------------------------------------------------------------------------------*/
Object.defineProperty(exports, "__esModule", { value: true }); Object.defineProperty(exports, "__esModule", { value: true });
exports.getSysroot = void 0; exports.getSysroot = void 0;

View File

@@ -1,7 +1,7 @@
"use strict"; "use strict";
/*--------------------------------------------------------------------------------------------- /*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved. * Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information. * Licensed under the Source EULA. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/ *--------------------------------------------------------------------------------------------*/
Object.defineProperty(exports, "__esModule", { value: true }); Object.defineProperty(exports, "__esModule", { value: true });
exports.sysrootInfo = void 0; exports.sysrootInfo = void 0;

View File

@@ -1,6 +1,6 @@
"use strict"; "use strict";
/*--------------------------------------------------------------------------------------------- /*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved. * Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information. * Licensed under the Source EULA. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/ *--------------------------------------------------------------------------------------------*/
Object.defineProperty(exports, "__esModule", { value: true }); Object.defineProperty(exports, "__esModule", { value: true });

View File

@@ -8,7 +8,7 @@ exports.getDependencies = void 0;
const child_process_1 = require("child_process"); const child_process_1 = require("child_process");
const fs_1 = require("fs"); const fs_1 = require("fs");
const path = require("path"); const path = require("path");
const dep_lists_1 = require("./dep-lists"); const dep_lists_1 = require("./dep-lists"); // {{SQL CARBON EDIT}} Not needed
// A flag that can easily be toggled. // A flag that can easily be toggled.
// Make sure to compile the build directory after toggling the value. // Make sure to compile the build directory after toggling the value.
// If false, we warn about new dependencies if they show up // If false, we warn about new dependencies if they show up
@@ -16,13 +16,13 @@ const dep_lists_1 = require("./dep-lists");
// If true, we fail the build if there are new dependencies found during that task. // If true, we fail the build if there are new dependencies found during that task.
// The reference dependencies, which one has to update when the new dependencies // The reference dependencies, which one has to update when the new dependencies
// are valid, are in dep-lists.ts // are valid, are in dep-lists.ts
const FAIL_BUILD_FOR_NEW_DEPENDENCIES = false; // const FAIL_BUILD_FOR_NEW_DEPENDENCIES: boolean = false; // {{SQL CARBON EDIT}} Not needed
function getDependencies(buildDir, applicationName, arch) { function getDependencies(buildDir, applicationName, arch) {
// Get the files for which we want to find dependencies. // Get the files for which we want to find dependencies.
const nativeModulesPath = path.join(buildDir, 'resources', 'app', 'node_modules.asar.unpacked'); const nativeModulesPath = path.join(buildDir, 'resources', 'app', 'node_modules.asar.unpacked');
const findResult = (0, child_process_1.spawnSync)('find', [nativeModulesPath, '-name', '*.node']); const findResult = (0, child_process_1.spawnSync)('find', [nativeModulesPath, '-name', '*.node']);
if (findResult.status) { if (findResult.status) {
console.error('Error finding files:'); console.error(`Error finding files for ${arch}:`);
console.error(findResult.stderr.toString()); console.error(findResult.stderr.toString());
return []; return [];
} }
@@ -48,18 +48,19 @@ function getDependencies(buildDir, applicationName, arch) {
sortedDependencies = sortedDependencies.filter(dependency => { sortedDependencies = sortedDependencies.filter(dependency => {
return !dep_lists_1.bundledDeps.some(bundledDep => dependency.startsWith(bundledDep)); return !dep_lists_1.bundledDeps.some(bundledDep => dependency.startsWith(bundledDep));
}); });
const referenceGeneratedDeps = dep_lists_1.referenceGeneratedDepsByArch[arch]; /* {{SQL CARBON EDIT}} Not needed
const referenceGeneratedDeps = referenceGeneratedDepsByArch[arch];
if (JSON.stringify(sortedDependencies) !== JSON.stringify(referenceGeneratedDeps)) { if (JSON.stringify(sortedDependencies) !== JSON.stringify(referenceGeneratedDeps)) {
const failMessage = 'The dependencies list has changed. ' const failMessage = 'The dependencies list has changed. '
+ 'Printing newer dependencies list that one can use to compare against referenceGeneratedDeps:\n' + 'Printing newer dependencies list that one can use to compare against referenceGeneratedDeps:\n'
+ sortedDependencies.join('\n'); + sortedDependencies.join('\n');
if (FAIL_BUILD_FOR_NEW_DEPENDENCIES) { if (FAIL_BUILD_FOR_NEW_DEPENDENCIES) {
throw new Error(failMessage); throw new Error(failMessage);
} } else {
else {
console.warn(failMessage); console.warn(failMessage);
} }
} }
*/
return sortedDependencies; return sortedDependencies;
} }
exports.getDependencies = getDependencies; exports.getDependencies = getDependencies;

View File

@@ -6,7 +6,7 @@
import { spawnSync } from 'child_process'; import { spawnSync } from 'child_process';
import { constants, statSync } from 'fs'; import { constants, statSync } from 'fs';
import path = require('path'); import path = require('path');
import { additionalDeps, bundledDeps, referenceGeneratedDepsByArch } from './dep-lists'; import { additionalDeps, bundledDeps/*, referenceGeneratedDepsByArch*/ } from './dep-lists'; // {{SQL CARBON EDIT}} Not needed
import { ArchString } from './types'; import { ArchString } from './types';
// A flag that can easily be toggled. // A flag that can easily be toggled.
@@ -16,14 +16,14 @@ import { ArchString } from './types';
// If true, we fail the build if there are new dependencies found during that task. // If true, we fail the build if there are new dependencies found during that task.
// The reference dependencies, which one has to update when the new dependencies // The reference dependencies, which one has to update when the new dependencies
// are valid, are in dep-lists.ts // are valid, are in dep-lists.ts
const FAIL_BUILD_FOR_NEW_DEPENDENCIES: boolean = false; // const FAIL_BUILD_FOR_NEW_DEPENDENCIES: boolean = false; // {{SQL CARBON EDIT}} Not needed
export function getDependencies(buildDir: string, applicationName: string, arch: ArchString): string[] { export function getDependencies(buildDir: string, applicationName: string, arch: ArchString): string[] {
// Get the files for which we want to find dependencies. // Get the files for which we want to find dependencies.
const nativeModulesPath = path.join(buildDir, 'resources', 'app', 'node_modules.asar.unpacked'); const nativeModulesPath = path.join(buildDir, 'resources', 'app', 'node_modules.asar.unpacked');
const findResult = spawnSync('find', [nativeModulesPath, '-name', '*.node']); const findResult = spawnSync('find', [nativeModulesPath, '-name', '*.node']);
if (findResult.status) { if (findResult.status) {
console.error('Error finding files:'); console.error(`Error finding files for ${arch}:`);
console.error(findResult.stderr.toString()); console.error(findResult.stderr.toString());
return []; return [];
} }
@@ -57,6 +57,7 @@ export function getDependencies(buildDir: string, applicationName: string, arch:
return !bundledDeps.some(bundledDep => dependency.startsWith(bundledDep)); return !bundledDeps.some(bundledDep => dependency.startsWith(bundledDep));
}); });
/* {{SQL CARBON EDIT}} Not needed
const referenceGeneratedDeps = referenceGeneratedDepsByArch[arch]; const referenceGeneratedDeps = referenceGeneratedDepsByArch[arch];
if (JSON.stringify(sortedDependencies) !== JSON.stringify(referenceGeneratedDeps)) { if (JSON.stringify(sortedDependencies) !== JSON.stringify(referenceGeneratedDeps)) {
const failMessage = 'The dependencies list has changed. ' const failMessage = 'The dependencies list has changed. '
@@ -68,6 +69,7 @@ export function getDependencies(buildDir: string, applicationName: string, arch:
console.warn(failMessage); console.warn(failMessage);
} }
} }
*/
return sortedDependencies; return sortedDependencies;
} }

View File

@@ -1,634 +0,0 @@
"use strict";
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the Source EULA. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
Object.defineProperty(exports, "__esModule", { value: true });
exports.execute = exports.run3 = exports.DeclarationResolver = exports.FSProvider = exports.RECIPE_PATH = void 0;
const fs = require("fs");
const ts = require("typescript");
const path = require("path");
const fancyLog = require("fancy-log");
const ansiColors = require("ansi-colors");
const dtsv = '3';
const tsfmt = require('../../tsfmt.json');
const SRC = path.join(__dirname, '../../src');
exports.RECIPE_PATH = path.join(__dirname, './monaco.d.ts.recipe');
const DECLARATION_PATH = path.join(__dirname, '../../src/vs/monaco.d.ts');
function logErr(message, ...rest) {
fancyLog(ansiColors.yellow(`[monaco.d.ts]`), message, ...rest);
}
function isDeclaration(a) {
return (a.kind === ts.SyntaxKind.InterfaceDeclaration
|| a.kind === ts.SyntaxKind.EnumDeclaration
|| a.kind === ts.SyntaxKind.ClassDeclaration
|| a.kind === ts.SyntaxKind.TypeAliasDeclaration
|| a.kind === ts.SyntaxKind.FunctionDeclaration
|| a.kind === ts.SyntaxKind.ModuleDeclaration);
}
function visitTopLevelDeclarations(sourceFile, visitor) {
let stop = false;
let visit = (node) => {
if (stop) {
return;
}
switch (node.kind) {
case ts.SyntaxKind.InterfaceDeclaration:
case ts.SyntaxKind.EnumDeclaration:
case ts.SyntaxKind.ClassDeclaration:
case ts.SyntaxKind.VariableStatement:
case ts.SyntaxKind.TypeAliasDeclaration:
case ts.SyntaxKind.FunctionDeclaration:
case ts.SyntaxKind.ModuleDeclaration:
stop = visitor(node);
}
if (stop) {
return;
}
ts.forEachChild(node, visit);
};
visit(sourceFile);
}
function getAllTopLevelDeclarations(sourceFile) {
let all = [];
visitTopLevelDeclarations(sourceFile, (node) => {
if (node.kind === ts.SyntaxKind.InterfaceDeclaration || node.kind === ts.SyntaxKind.ClassDeclaration || node.kind === ts.SyntaxKind.ModuleDeclaration) {
let interfaceDeclaration = node;
let triviaStart = interfaceDeclaration.pos;
let triviaEnd = interfaceDeclaration.name.pos;
let triviaText = getNodeText(sourceFile, { pos: triviaStart, end: triviaEnd });
if (triviaText.indexOf('@internal') === -1) {
all.push(node);
}
}
else {
let nodeText = getNodeText(sourceFile, node);
if (nodeText.indexOf('@internal') === -1) {
all.push(node);
}
}
return false /*continue*/;
});
return all;
}
function getTopLevelDeclaration(sourceFile, typeName) {
let result = null;
visitTopLevelDeclarations(sourceFile, (node) => {
if (isDeclaration(node) && node.name) {
if (node.name.text === typeName) {
result = node;
return true /*stop*/;
}
return false /*continue*/;
}
// node is ts.VariableStatement
if (getNodeText(sourceFile, node).indexOf(typeName) >= 0) {
result = node;
return true /*stop*/;
}
return false /*continue*/;
});
return result;
}
function getNodeText(sourceFile, node) {
return sourceFile.getFullText().substring(node.pos, node.end);
}
function hasModifier(modifiers, kind) {
if (modifiers) {
for (let i = 0; i < modifiers.length; i++) {
let mod = modifiers[i];
if (mod.kind === kind) {
return true;
}
}
}
return false;
}
function isStatic(member) {
return hasModifier(member.modifiers, ts.SyntaxKind.StaticKeyword);
}
function isDefaultExport(declaration) {
return (hasModifier(declaration.modifiers, ts.SyntaxKind.DefaultKeyword)
&& hasModifier(declaration.modifiers, ts.SyntaxKind.ExportKeyword));
}
function getMassagedTopLevelDeclarationText(sourceFile, declaration, importName, usage, enums) {
let result = getNodeText(sourceFile, declaration);
if (declaration.kind === ts.SyntaxKind.InterfaceDeclaration || declaration.kind === ts.SyntaxKind.ClassDeclaration) {
let interfaceDeclaration = declaration;
const staticTypeName = (isDefaultExport(interfaceDeclaration)
? `${importName}.default`
: `${importName}.${declaration.name.text}`);
let instanceTypeName = staticTypeName;
const typeParametersCnt = (interfaceDeclaration.typeParameters ? interfaceDeclaration.typeParameters.length : 0);
if (typeParametersCnt > 0) {
let arr = [];
for (let i = 0; i < typeParametersCnt; i++) {
arr.push('any');
}
instanceTypeName = `${instanceTypeName}<${arr.join(',')}>`;
}
const members = interfaceDeclaration.members;
members.forEach((member) => {
try {
let memberText = getNodeText(sourceFile, member);
if (memberText.indexOf('@internal') >= 0 || memberText.indexOf('private') >= 0) {
result = result.replace(memberText, '');
}
else {
const memberName = member.name.text;
const memberAccess = (memberName.indexOf('.') >= 0 ? `['${memberName}']` : `.${memberName}`);
if (isStatic(member)) {
usage.push(`a = ${staticTypeName}${memberAccess};`);
}
else {
usage.push(`a = (<${instanceTypeName}>b)${memberAccess};`);
}
}
}
catch (err) {
// life..
}
});
}
else if (declaration.kind === ts.SyntaxKind.VariableStatement) {
const jsDoc = result.substr(0, declaration.getLeadingTriviaWidth(sourceFile));
if (jsDoc.indexOf('@monacodtsreplace') >= 0) {
const jsDocLines = jsDoc.split(/\r\n|\r|\n/);
let directives = [];
for (const jsDocLine of jsDocLines) {
const m = jsDocLine.match(/^\s*\* \/([^/]+)\/([^/]+)\/$/);
if (m) {
directives.push([new RegExp(m[1], 'g'), m[2]]);
}
}
// remove the jsdoc
result = result.substr(jsDoc.length);
if (directives.length > 0) {
// apply replace directives
const replacer = createReplacerFromDirectives(directives);
result = replacer(result);
}
}
}
result = result.replace(/export default /g, 'export ');
result = result.replace(/export declare /g, 'export ');
result = result.replace(/declare /g, '');
let lines = result.split(/\r\n|\r|\n/);
for (let i = 0; i < lines.length; i++) {
if (/\s*\*/.test(lines[i])) {
// very likely a comment
continue;
}
lines[i] = lines[i].replace(/"/g, '\'');
}
result = lines.join('\n');
if (declaration.kind === ts.SyntaxKind.EnumDeclaration) {
result = result.replace(/const enum/, 'enum');
enums.push({
enumName: declaration.name.getText(sourceFile),
text: result
});
}
return result;
}
function format(text, endl) {
const REALLY_FORMAT = false;
text = preformat(text, endl);
if (!REALLY_FORMAT) {
return text;
}
// Parse the source text
let sourceFile = ts.createSourceFile('file.ts', text, ts.ScriptTarget.Latest, /*setParentPointers*/ true);
// Get the formatting edits on the input sources
let edits = ts.formatting.formatDocument(sourceFile, getRuleProvider(tsfmt), tsfmt);
// Apply the edits on the input code
return applyEdits(text, edits);
function countParensCurly(text) {
let cnt = 0;
for (let i = 0; i < text.length; i++) {
if (text.charAt(i) === '(' || text.charAt(i) === '{') {
cnt++;
}
if (text.charAt(i) === ')' || text.charAt(i) === '}') {
cnt--;
}
}
return cnt;
}
function repeatStr(s, cnt) {
let r = '';
for (let i = 0; i < cnt; i++) {
r += s;
}
return r;
}
function preformat(text, endl) {
let lines = text.split(endl);
let inComment = false;
let inCommentDeltaIndent = 0;
let indent = 0;
for (let i = 0; i < lines.length; i++) {
let line = lines[i].replace(/\s$/, '');
let repeat = false;
let lineIndent = 0;
do {
repeat = false;
if (line.substring(0, 4) === ' ') {
line = line.substring(4);
lineIndent++;
repeat = true;
}
if (line.charAt(0) === '\t') {
line = line.substring(1);
lineIndent++;
repeat = true;
}
} while (repeat);
if (line.length === 0) {
continue;
}
if (inComment) {
if (/\*\//.test(line)) {
inComment = false;
}
lines[i] = repeatStr('\t', lineIndent + inCommentDeltaIndent) + line;
continue;
}
if (/\/\*/.test(line)) {
inComment = true;
inCommentDeltaIndent = indent - lineIndent;
lines[i] = repeatStr('\t', indent) + line;
continue;
}
const cnt = countParensCurly(line);
let shouldUnindentAfter = false;
let shouldUnindentBefore = false;
if (cnt < 0) {
if (/[({]/.test(line)) {
shouldUnindentAfter = true;
}
else {
shouldUnindentBefore = true;
}
}
else if (cnt === 0) {
shouldUnindentBefore = /^\}/.test(line);
}
let shouldIndentAfter = false;
if (cnt > 0) {
shouldIndentAfter = true;
}
else if (cnt === 0) {
shouldIndentAfter = /{$/.test(line);
}
if (shouldUnindentBefore) {
indent--;
}
lines[i] = repeatStr('\t', indent) + line;
if (shouldUnindentAfter) {
indent--;
}
if (shouldIndentAfter) {
indent++;
}
}
return lines.join(endl);
}
function getRuleProvider(options) {
// Share this between multiple formatters using the same options.
// This represents the bulk of the space the formatter uses.
return ts.formatting.getFormatContext(options);
}
function applyEdits(text, edits) {
// Apply edits in reverse on the existing text
let result = text;
for (let i = edits.length - 1; i >= 0; i--) {
let change = edits[i];
let head = result.slice(0, change.span.start);
let tail = result.slice(change.span.start + change.span.length);
result = head + change.newText + tail;
}
return result;
}
}
function createReplacerFromDirectives(directives) {
return (str) => {
for (let i = 0; i < directives.length; i++) {
str = str.replace(directives[i][0], directives[i][1]);
}
return str;
};
}
function createReplacer(data) {
data = data || '';
let rawDirectives = data.split(';');
let directives = [];
rawDirectives.forEach((rawDirective) => {
if (rawDirective.length === 0) {
return;
}
let pieces = rawDirective.split('=>');
let findStr = pieces[0];
let replaceStr = pieces[1];
findStr = findStr.replace(/[\-\\\{\}\*\+\?\|\^\$\.\,\[\]\(\)\#\s]/g, '\\$&');
findStr = '\\b' + findStr + '\\b';
directives.push([new RegExp(findStr, 'g'), replaceStr]);
});
return createReplacerFromDirectives(directives);
}
function generateDeclarationFile(recipe, sourceFileGetter) {
const endl = /\r\n/.test(recipe) ? '\r\n' : '\n';
let lines = recipe.split(endl);
let result = [];
let usageCounter = 0;
let usageImports = [];
let usage = [];
let failed = false;
usage.push(`var a: any;`);
usage.push(`var b: any;`);
const generateUsageImport = (moduleId) => {
let importName = 'm' + (++usageCounter);
usageImports.push(`import * as ${importName} from './${moduleId.replace(/\.d\.ts$/, '')}';`);
return importName;
};
let enums = [];
let version = null;
lines.forEach(line => {
if (failed) {
return;
}
let m0 = line.match(/^\/\/dtsv=(\d+)$/);
if (m0) {
version = m0[1];
}
let m1 = line.match(/^\s*#include\(([^;)]*)(;[^)]*)?\)\:(.*)$/);
if (m1) {
let moduleId = m1[1];
const sourceFile = sourceFileGetter(moduleId);
if (!sourceFile) {
logErr(`While handling ${line}`);
logErr(`Cannot find ${moduleId}`);
failed = true;
return;
}
const importName = generateUsageImport(moduleId);
let replacer = createReplacer(m1[2]);
let typeNames = m1[3].split(/,/);
typeNames.forEach((typeName) => {
typeName = typeName.trim();
if (typeName.length === 0) {
return;
}
let declaration = getTopLevelDeclaration(sourceFile, typeName);
if (!declaration) {
logErr(`While handling ${line}`);
logErr(`Cannot find ${typeName}`);
failed = true;
return;
}
result.push(replacer(getMassagedTopLevelDeclarationText(sourceFile, declaration, importName, usage, enums)));
});
return;
}
let m2 = line.match(/^\s*#includeAll\(([^;)]*)(;[^)]*)?\)\:(.*)$/);
if (m2) {
let moduleId = m2[1];
const sourceFile = sourceFileGetter(moduleId);
if (!sourceFile) {
logErr(`While handling ${line}`);
logErr(`Cannot find ${moduleId}`);
failed = true;
return;
}
const importName = generateUsageImport(moduleId);
let replacer = createReplacer(m2[2]);
let typeNames = m2[3].split(/,/);
let typesToExcludeMap = {};
let typesToExcludeArr = [];
typeNames.forEach((typeName) => {
typeName = typeName.trim();
if (typeName.length === 0) {
return;
}
typesToExcludeMap[typeName] = true;
typesToExcludeArr.push(typeName);
});
getAllTopLevelDeclarations(sourceFile).forEach((declaration) => {
if (isDeclaration(declaration) && declaration.name) {
if (typesToExcludeMap[declaration.name.text]) {
return;
}
}
else {
// node is ts.VariableStatement
let nodeText = getNodeText(sourceFile, declaration);
for (let i = 0; i < typesToExcludeArr.length; i++) {
if (nodeText.indexOf(typesToExcludeArr[i]) >= 0) {
return;
}
}
}
result.push(replacer(getMassagedTopLevelDeclarationText(sourceFile, declaration, importName, usage, enums)));
});
return;
}
result.push(line);
});
if (failed) {
return null;
}
if (version !== dtsv) {
if (!version) {
logErr(`gulp watch restart required. 'monaco.d.ts.recipe' is written before versioning was introduced.`);
}
else {
logErr(`gulp watch restart required. 'monaco.d.ts.recipe' v${version} does not match runtime v${dtsv}.`);
}
return null;
}
let resultTxt = result.join(endl);
resultTxt = resultTxt.replace(/\bURI\b/g, 'Uri');
resultTxt = resultTxt.replace(/\bEvent</g, 'IEvent<');
resultTxt = resultTxt.split(/\r\n|\n|\r/).join(endl);
resultTxt = format(resultTxt, endl);
resultTxt = resultTxt.split(/\r\n|\n|\r/).join(endl);
enums.sort((e1, e2) => {
if (e1.enumName < e2.enumName) {
return -1;
}
if (e1.enumName > e2.enumName) {
return 1;
}
return 0;
});
let resultEnums = [
'/*---------------------------------------------------------------------------------------------',
' * Copyright (c) Microsoft Corporation. All rights reserved.',
' * Licensed under the Source EULA. See License.txt in the project root for license information.',
' *--------------------------------------------------------------------------------------------*/',
'',
'// THIS IS A GENERATED FILE. DO NOT EDIT DIRECTLY.',
''
].concat(enums.map(e => e.text)).join(endl);
resultEnums = resultEnums.split(/\r\n|\n|\r/).join(endl);
resultEnums = format(resultEnums, endl);
resultEnums = resultEnums.split(/\r\n|\n|\r/).join(endl);
return {
result: resultTxt,
usageContent: `${usageImports.join('\n')}\n\n${usage.join('\n')}`,
enums: resultEnums
};
}
function _run(sourceFileGetter) {
const recipe = fs.readFileSync(exports.RECIPE_PATH).toString();
const t = generateDeclarationFile(recipe, sourceFileGetter);
if (!t) {
return null;
}
const result = t.result;
const usageContent = t.usageContent;
const enums = t.enums;
const currentContent = fs.readFileSync(DECLARATION_PATH).toString();
const one = currentContent.replace(/\r\n/gm, '\n');
const other = result.replace(/\r\n/gm, '\n');
const isTheSame = (one === other);
return {
content: result,
usageContent: usageContent,
enums: enums,
filePath: DECLARATION_PATH,
isTheSame
};
}
class FSProvider {
existsSync(filePath) {
return fs.existsSync(filePath);
}
statSync(filePath) {
return fs.statSync(filePath);
}
readFileSync(_moduleId, filePath) {
return fs.readFileSync(filePath);
}
}
exports.FSProvider = FSProvider;
class CacheEntry {
constructor(sourceFile, mtime) {
this.sourceFile = sourceFile;
this.mtime = mtime;
}
}
class DeclarationResolver {
constructor(_fsProvider) {
this._fsProvider = _fsProvider;
this._sourceFileCache = Object.create(null);
}
invalidateCache(moduleId) {
this._sourceFileCache[moduleId] = null;
}
getDeclarationSourceFile(moduleId) {
if (this._sourceFileCache[moduleId]) {
// Since we cannot trust file watching to invalidate the cache, check also the mtime
const fileName = this._getFileName(moduleId);
const mtime = this._fsProvider.statSync(fileName).mtime.getTime();
if (this._sourceFileCache[moduleId].mtime !== mtime) {
this._sourceFileCache[moduleId] = null;
}
}
if (!this._sourceFileCache[moduleId]) {
this._sourceFileCache[moduleId] = this._getDeclarationSourceFile(moduleId);
}
return this._sourceFileCache[moduleId] ? this._sourceFileCache[moduleId].sourceFile : null;
}
_getFileName(moduleId) {
if (/\.d\.ts$/.test(moduleId)) {
return path.join(SRC, moduleId);
}
return path.join(SRC, `${moduleId}.ts`);
}
_getDeclarationSourceFile(moduleId) {
const fileName = this._getFileName(moduleId);
if (!this._fsProvider.existsSync(fileName)) {
return null;
}
const mtime = this._fsProvider.statSync(fileName).mtime.getTime();
if (/\.d\.ts$/.test(moduleId)) {
// const mtime = this._fsProvider.statFileSync()
const fileContents = this._fsProvider.readFileSync(moduleId, fileName).toString();
return new CacheEntry(ts.createSourceFile(fileName, fileContents, ts.ScriptTarget.ES5), mtime);
}
const fileContents = this._fsProvider.readFileSync(moduleId, fileName).toString();
const fileMap = {
'file.ts': fileContents
};
const service = ts.createLanguageService(new TypeScriptLanguageServiceHost({}, fileMap, {}));
const text = service.getEmitOutput('file.ts', true, true).outputFiles[0].text;
return new CacheEntry(ts.createSourceFile(fileName, text, ts.ScriptTarget.ES5), mtime);
}
}
exports.DeclarationResolver = DeclarationResolver;
function run3(resolver) {
const sourceFileGetter = (moduleId) => resolver.getDeclarationSourceFile(moduleId);
return _run(sourceFileGetter);
}
exports.run3 = run3;
class TypeScriptLanguageServiceHost {
constructor(libs, files, compilerOptions) {
this._libs = libs;
this._files = files;
this._compilerOptions = compilerOptions;
}
// {{SQL CARBON EDIT}} - provide missing methods
readFile() {
return undefined;
}
fileExists() {
return false;
}
// --- language service host ---------------
getCompilationSettings() {
return this._compilerOptions;
}
getScriptFileNames() {
return ([]
.concat(Object.keys(this._libs))
.concat(Object.keys(this._files)));
}
getScriptVersion(_fileName) {
return '1';
}
getProjectVersion() {
return '1';
}
getScriptSnapshot(fileName) {
if (this._files.hasOwnProperty(fileName)) {
return ts.ScriptSnapshot.fromString(this._files[fileName]);
}
else if (this._libs.hasOwnProperty(fileName)) {
return ts.ScriptSnapshot.fromString(this._libs[fileName]);
}
else {
return ts.ScriptSnapshot.fromString('');
}
}
getScriptKind(_fileName) {
return ts.ScriptKind.TS;
}
getCurrentDirectory() {
return '';
}
getDefaultLibFileName(_options) {
return 'defaultLib:es5';
}
isDefaultLibFileName(fileName) {
return fileName === this.getDefaultLibFileName(this._compilerOptions);
}
}
function execute() {
let r = run3(new DeclarationResolver(new FSProvider()));
if (!r) {
throw new Error(`monaco.d.ts generation error - Cannot continue`);
}
return r;
}
exports.execute = execute;

View File

@@ -1,757 +0,0 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the Source EULA. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import * as fs from 'fs';
import * as ts from 'typescript';
import * as path from 'path';
import * as fancyLog from 'fancy-log';
import * as ansiColors from 'ansi-colors';
const dtsv = '3';
const tsfmt = require('../../tsfmt.json');
const SRC = path.join(__dirname, '../../src');
export const RECIPE_PATH = path.join(__dirname, './monaco.d.ts.recipe');
const DECLARATION_PATH = path.join(__dirname, '../../src/vs/monaco.d.ts');
function logErr(message: any, ...rest: any[]): void {
fancyLog(ansiColors.yellow(`[monaco.d.ts]`), message, ...rest);
}
type SourceFileGetter = (moduleId: string) => ts.SourceFile | null;
type TSTopLevelDeclaration = ts.InterfaceDeclaration | ts.EnumDeclaration | ts.ClassDeclaration | ts.TypeAliasDeclaration | ts.FunctionDeclaration | ts.ModuleDeclaration;
type TSTopLevelDeclare = TSTopLevelDeclaration | ts.VariableStatement;
function isDeclaration(a: TSTopLevelDeclare): a is TSTopLevelDeclaration {
return (
a.kind === ts.SyntaxKind.InterfaceDeclaration
|| a.kind === ts.SyntaxKind.EnumDeclaration
|| a.kind === ts.SyntaxKind.ClassDeclaration
|| a.kind === ts.SyntaxKind.TypeAliasDeclaration
|| a.kind === ts.SyntaxKind.FunctionDeclaration
|| a.kind === ts.SyntaxKind.ModuleDeclaration
);
}
function visitTopLevelDeclarations(sourceFile: ts.SourceFile, visitor: (node: TSTopLevelDeclare) => boolean): void {
let stop = false;
let visit = (node: ts.Node): void => {
if (stop) {
return;
}
switch (node.kind) {
case ts.SyntaxKind.InterfaceDeclaration:
case ts.SyntaxKind.EnumDeclaration:
case ts.SyntaxKind.ClassDeclaration:
case ts.SyntaxKind.VariableStatement:
case ts.SyntaxKind.TypeAliasDeclaration:
case ts.SyntaxKind.FunctionDeclaration:
case ts.SyntaxKind.ModuleDeclaration:
stop = visitor(<TSTopLevelDeclare>node);
}
if (stop) {
return;
}
ts.forEachChild(node, visit);
};
visit(sourceFile);
}
function getAllTopLevelDeclarations(sourceFile: ts.SourceFile): TSTopLevelDeclare[] {
let all: TSTopLevelDeclare[] = [];
visitTopLevelDeclarations(sourceFile, (node) => {
if (node.kind === ts.SyntaxKind.InterfaceDeclaration || node.kind === ts.SyntaxKind.ClassDeclaration || node.kind === ts.SyntaxKind.ModuleDeclaration) {
let interfaceDeclaration = <ts.InterfaceDeclaration>node;
let triviaStart = interfaceDeclaration.pos;
let triviaEnd = interfaceDeclaration.name.pos;
let triviaText = getNodeText(sourceFile, { pos: triviaStart, end: triviaEnd });
if (triviaText.indexOf('@internal') === -1) {
all.push(node);
}
} else {
let nodeText = getNodeText(sourceFile, node);
if (nodeText.indexOf('@internal') === -1) {
all.push(node);
}
}
return false /*continue*/;
});
return all;
}
function getTopLevelDeclaration(sourceFile: ts.SourceFile, typeName: string): TSTopLevelDeclare | null {
let result: TSTopLevelDeclare | null = null;
visitTopLevelDeclarations(sourceFile, (node) => {
if (isDeclaration(node) && node.name) {
if (node.name.text === typeName) {
result = node;
return true /*stop*/;
}
return false /*continue*/;
}
// node is ts.VariableStatement
if (getNodeText(sourceFile, node).indexOf(typeName) >= 0) {
result = node;
return true /*stop*/;
}
return false /*continue*/;
});
return result;
}
function getNodeText(sourceFile: ts.SourceFile, node: { pos: number; end: number; }): string {
return sourceFile.getFullText().substring(node.pos, node.end);
}
function hasModifier(modifiers: ts.NodeArray<ts.Modifier> | undefined, kind: ts.SyntaxKind): boolean {
if (modifiers) {
for (let i = 0; i < modifiers.length; i++) {
let mod = modifiers[i];
if (mod.kind === kind) {
return true;
}
}
}
return false;
}
function isStatic(member: ts.ClassElement | ts.TypeElement): boolean {
return hasModifier(member.modifiers, ts.SyntaxKind.StaticKeyword);
}
function isDefaultExport(declaration: ts.InterfaceDeclaration | ts.ClassDeclaration): boolean {
return (
hasModifier(declaration.modifiers, ts.SyntaxKind.DefaultKeyword)
&& hasModifier(declaration.modifiers, ts.SyntaxKind.ExportKeyword)
);
}
function getMassagedTopLevelDeclarationText(sourceFile: ts.SourceFile, declaration: TSTopLevelDeclare, importName: string, usage: string[], enums: IEnumEntry[]): string {
let result = getNodeText(sourceFile, declaration);
if (declaration.kind === ts.SyntaxKind.InterfaceDeclaration || declaration.kind === ts.SyntaxKind.ClassDeclaration) {
let interfaceDeclaration = <ts.InterfaceDeclaration | ts.ClassDeclaration>declaration;
const staticTypeName = (
isDefaultExport(interfaceDeclaration)
? `${importName}.default`
: `${importName}.${declaration.name!.text}`
);
let instanceTypeName = staticTypeName;
const typeParametersCnt = (interfaceDeclaration.typeParameters ? interfaceDeclaration.typeParameters.length : 0);
if (typeParametersCnt > 0) {
let arr: string[] = [];
for (let i = 0; i < typeParametersCnt; i++) {
arr.push('any');
}
instanceTypeName = `${instanceTypeName}<${arr.join(',')}>`;
}
const members: ts.NodeArray<ts.ClassElement | ts.TypeElement> = interfaceDeclaration.members;
members.forEach((member) => {
try {
let memberText = getNodeText(sourceFile, member);
if (memberText.indexOf('@internal') >= 0 || memberText.indexOf('private') >= 0) {
result = result.replace(memberText, '');
} else {
const memberName = (<ts.Identifier | ts.StringLiteral>member.name).text;
const memberAccess = (memberName.indexOf('.') >= 0 ? `['${memberName}']` : `.${memberName}`);
if (isStatic(member)) {
usage.push(`a = ${staticTypeName}${memberAccess};`);
} else {
usage.push(`a = (<${instanceTypeName}>b)${memberAccess};`);
}
}
} catch (err) {
// life..
}
});
} else if (declaration.kind === ts.SyntaxKind.VariableStatement) {
const jsDoc = result.substr(0, declaration.getLeadingTriviaWidth(sourceFile));
if (jsDoc.indexOf('@monacodtsreplace') >= 0) {
const jsDocLines = jsDoc.split(/\r\n|\r|\n/);
let directives: [RegExp, string][] = [];
for (const jsDocLine of jsDocLines) {
const m = jsDocLine.match(/^\s*\* \/([^/]+)\/([^/]+)\/$/);
if (m) {
directives.push([new RegExp(m[1], 'g'), m[2]]);
}
}
// remove the jsdoc
result = result.substr(jsDoc.length);
if (directives.length > 0) {
// apply replace directives
const replacer = createReplacerFromDirectives(directives);
result = replacer(result);
}
}
}
result = result.replace(/export default /g, 'export ');
result = result.replace(/export declare /g, 'export ');
result = result.replace(/declare /g, '');
let lines = result.split(/\r\n|\r|\n/);
for (let i = 0; i < lines.length; i++) {
if (/\s*\*/.test(lines[i])) {
// very likely a comment
continue;
}
lines[i] = lines[i].replace(/"/g, '\'');
}
result = lines.join('\n');
if (declaration.kind === ts.SyntaxKind.EnumDeclaration) {
result = result.replace(/const enum/, 'enum');
enums.push({
enumName: declaration.name.getText(sourceFile),
text: result
});
}
return result;
}
function format(text: string, endl: string): string {
const REALLY_FORMAT = false;
text = preformat(text, endl);
if (!REALLY_FORMAT) {
return text;
}
// Parse the source text
let sourceFile = ts.createSourceFile('file.ts', text, ts.ScriptTarget.Latest, /*setParentPointers*/ true);
// Get the formatting edits on the input sources
let edits = (<any>ts).formatting.formatDocument(sourceFile, getRuleProvider(tsfmt), tsfmt);
// Apply the edits on the input code
return applyEdits(text, edits);
function countParensCurly(text: string): number {
let cnt = 0;
for (let i = 0; i < text.length; i++) {
if (text.charAt(i) === '(' || text.charAt(i) === '{') {
cnt++;
}
if (text.charAt(i) === ')' || text.charAt(i) === '}') {
cnt--;
}
}
return cnt;
}
function repeatStr(s: string, cnt: number): string {
let r = '';
for (let i = 0; i < cnt; i++) {
r += s;
}
return r;
}
function preformat(text: string, endl: string): string {
let lines = text.split(endl);
let inComment = false;
let inCommentDeltaIndent = 0;
let indent = 0;
for (let i = 0; i < lines.length; i++) {
let line = lines[i].replace(/\s$/, '');
let repeat = false;
let lineIndent = 0;
do {
repeat = false;
if (line.substring(0, 4) === ' ') {
line = line.substring(4);
lineIndent++;
repeat = true;
}
if (line.charAt(0) === '\t') {
line = line.substring(1);
lineIndent++;
repeat = true;
}
} while (repeat);
if (line.length === 0) {
continue;
}
if (inComment) {
if (/\*\//.test(line)) {
inComment = false;
}
lines[i] = repeatStr('\t', lineIndent + inCommentDeltaIndent) + line;
continue;
}
if (/\/\*/.test(line)) {
inComment = true;
inCommentDeltaIndent = indent - lineIndent;
lines[i] = repeatStr('\t', indent) + line;
continue;
}
const cnt = countParensCurly(line);
let shouldUnindentAfter = false;
let shouldUnindentBefore = false;
if (cnt < 0) {
if (/[({]/.test(line)) {
shouldUnindentAfter = true;
} else {
shouldUnindentBefore = true;
}
} else if (cnt === 0) {
shouldUnindentBefore = /^\}/.test(line);
}
let shouldIndentAfter = false;
if (cnt > 0) {
shouldIndentAfter = true;
} else if (cnt === 0) {
shouldIndentAfter = /{$/.test(line);
}
if (shouldUnindentBefore) {
indent--;
}
lines[i] = repeatStr('\t', indent) + line;
if (shouldUnindentAfter) {
indent--;
}
if (shouldIndentAfter) {
indent++;
}
}
return lines.join(endl);
}
function getRuleProvider(options: ts.FormatCodeSettings) {
// Share this between multiple formatters using the same options.
// This represents the bulk of the space the formatter uses.
return (ts as any).formatting.getFormatContext(options);
}
function applyEdits(text: string, edits: ts.TextChange[]): string {
// Apply edits in reverse on the existing text
let result = text;
for (let i = edits.length - 1; i >= 0; i--) {
let change = edits[i];
let head = result.slice(0, change.span.start);
let tail = result.slice(change.span.start + change.span.length);
result = head + change.newText + tail;
}
return result;
}
}
function createReplacerFromDirectives(directives: [RegExp, string][]): (str: string) => string {
return (str: string) => {
for (let i = 0; i < directives.length; i++) {
str = str.replace(directives[i][0], directives[i][1]);
}
return str;
};
}
function createReplacer(data: string): (str: string) => string {
data = data || '';
let rawDirectives = data.split(';');
let directives: [RegExp, string][] = [];
rawDirectives.forEach((rawDirective) => {
if (rawDirective.length === 0) {
return;
}
let pieces = rawDirective.split('=>');
let findStr = pieces[0];
let replaceStr = pieces[1];
findStr = findStr.replace(/[\-\\\{\}\*\+\?\|\^\$\.\,\[\]\(\)\#\s]/g, '\\$&');
findStr = '\\b' + findStr + '\\b';
directives.push([new RegExp(findStr, 'g'), replaceStr]);
});
return createReplacerFromDirectives(directives);
}
interface ITempResult {
result: string;
usageContent: string;
enums: string;
}
interface IEnumEntry {
enumName: string;
text: string;
}
function generateDeclarationFile(recipe: string, sourceFileGetter: SourceFileGetter): ITempResult | null {
const endl = /\r\n/.test(recipe) ? '\r\n' : '\n';
let lines = recipe.split(endl);
let result: string[] = [];
let usageCounter = 0;
let usageImports: string[] = [];
let usage: string[] = [];
let failed = false;
usage.push(`var a: any;`);
usage.push(`var b: any;`);
const generateUsageImport = (moduleId: string) => {
let importName = 'm' + (++usageCounter);
usageImports.push(`import * as ${importName} from './${moduleId.replace(/\.d\.ts$/, '')}';`);
return importName;
};
let enums: IEnumEntry[] = [];
let version: string | null = null;
lines.forEach(line => {
if (failed) {
return;
}
let m0 = line.match(/^\/\/dtsv=(\d+)$/);
if (m0) {
version = m0[1];
}
let m1 = line.match(/^\s*#include\(([^;)]*)(;[^)]*)?\)\:(.*)$/);
if (m1) {
let moduleId = m1[1];
const sourceFile = sourceFileGetter(moduleId);
if (!sourceFile) {
logErr(`While handling ${line}`);
logErr(`Cannot find ${moduleId}`);
failed = true;
return;
}
const importName = generateUsageImport(moduleId);
let replacer = createReplacer(m1[2]);
let typeNames = m1[3].split(/,/);
typeNames.forEach((typeName) => {
typeName = typeName.trim();
if (typeName.length === 0) {
return;
}
let declaration = getTopLevelDeclaration(sourceFile, typeName);
if (!declaration) {
logErr(`While handling ${line}`);
logErr(`Cannot find ${typeName}`);
failed = true;
return;
}
result.push(replacer(getMassagedTopLevelDeclarationText(sourceFile, declaration, importName, usage, enums)));
});
return;
}
let m2 = line.match(/^\s*#includeAll\(([^;)]*)(;[^)]*)?\)\:(.*)$/);
if (m2) {
let moduleId = m2[1];
const sourceFile = sourceFileGetter(moduleId);
if (!sourceFile) {
logErr(`While handling ${line}`);
logErr(`Cannot find ${moduleId}`);
failed = true;
return;
}
const importName = generateUsageImport(moduleId);
let replacer = createReplacer(m2[2]);
let typeNames = m2[3].split(/,/);
let typesToExcludeMap: { [typeName: string]: boolean; } = {};
let typesToExcludeArr: string[] = [];
typeNames.forEach((typeName) => {
typeName = typeName.trim();
if (typeName.length === 0) {
return;
}
typesToExcludeMap[typeName] = true;
typesToExcludeArr.push(typeName);
});
getAllTopLevelDeclarations(sourceFile).forEach((declaration) => {
if (isDeclaration(declaration) && declaration.name) {
if (typesToExcludeMap[declaration.name.text]) {
return;
}
} else {
// node is ts.VariableStatement
let nodeText = getNodeText(sourceFile, declaration);
for (let i = 0; i < typesToExcludeArr.length; i++) {
if (nodeText.indexOf(typesToExcludeArr[i]) >= 0) {
return;
}
}
}
result.push(replacer(getMassagedTopLevelDeclarationText(sourceFile, declaration, importName, usage, enums)));
});
return;
}
result.push(line);
});
if (failed) {
return null;
}
if (version !== dtsv) {
if (!version) {
logErr(`gulp watch restart required. 'monaco.d.ts.recipe' is written before versioning was introduced.`);
} else {
logErr(`gulp watch restart required. 'monaco.d.ts.recipe' v${version} does not match runtime v${dtsv}.`);
}
return null;
}
let resultTxt = result.join(endl);
resultTxt = resultTxt.replace(/\bURI\b/g, 'Uri');
resultTxt = resultTxt.replace(/\bEvent</g, 'IEvent<');
resultTxt = resultTxt.split(/\r\n|\n|\r/).join(endl);
resultTxt = format(resultTxt, endl);
resultTxt = resultTxt.split(/\r\n|\n|\r/).join(endl);
enums.sort((e1, e2) => {
if (e1.enumName < e2.enumName) {
return -1;
}
if (e1.enumName > e2.enumName) {
return 1;
}
return 0;
});
let resultEnums = [
'/*---------------------------------------------------------------------------------------------',
' * Copyright (c) Microsoft Corporation. All rights reserved.',
' * Licensed under the Source EULA. See License.txt in the project root for license information.',
' *--------------------------------------------------------------------------------------------*/',
'',
'// THIS IS A GENERATED FILE. DO NOT EDIT DIRECTLY.',
''
].concat(enums.map(e => e.text)).join(endl);
resultEnums = resultEnums.split(/\r\n|\n|\r/).join(endl);
resultEnums = format(resultEnums, endl);
resultEnums = resultEnums.split(/\r\n|\n|\r/).join(endl);
return {
result: resultTxt,
usageContent: `${usageImports.join('\n')}\n\n${usage.join('\n')}`,
enums: resultEnums
};
}
export interface IMonacoDeclarationResult {
content: string;
usageContent: string;
enums: string;
filePath: string;
isTheSame: boolean;
}
function _run(sourceFileGetter: SourceFileGetter): IMonacoDeclarationResult | null {
const recipe = fs.readFileSync(RECIPE_PATH).toString();
const t = generateDeclarationFile(recipe, sourceFileGetter);
if (!t) {
return null;
}
const result = t.result;
const usageContent = t.usageContent;
const enums = t.enums;
const currentContent = fs.readFileSync(DECLARATION_PATH).toString();
const one = currentContent.replace(/\r\n/gm, '\n');
const other = result.replace(/\r\n/gm, '\n');
const isTheSame = (one === other);
return {
content: result,
usageContent: usageContent,
enums: enums,
filePath: DECLARATION_PATH,
isTheSame
};
}
export class FSProvider {
public existsSync(filePath: string): boolean {
return fs.existsSync(filePath);
}
public statSync(filePath: string): fs.Stats {
return fs.statSync(filePath);
}
public readFileSync(_moduleId: string, filePath: string): Buffer {
return fs.readFileSync(filePath);
}
}
class CacheEntry {
constructor(
public readonly sourceFile: ts.SourceFile,
public readonly mtime: number
) {}
}
export class DeclarationResolver {
private _sourceFileCache: { [moduleId: string]: CacheEntry | null; };
constructor(private readonly _fsProvider: FSProvider) {
this._sourceFileCache = Object.create(null);
}
public invalidateCache(moduleId: string): void {
this._sourceFileCache[moduleId] = null;
}
public getDeclarationSourceFile(moduleId: string): ts.SourceFile | null {
if (this._sourceFileCache[moduleId]) {
// Since we cannot trust file watching to invalidate the cache, check also the mtime
const fileName = this._getFileName(moduleId);
const mtime = this._fsProvider.statSync(fileName).mtime.getTime();
if (this._sourceFileCache[moduleId]!.mtime !== mtime) {
this._sourceFileCache[moduleId] = null;
}
}
if (!this._sourceFileCache[moduleId]) {
this._sourceFileCache[moduleId] = this._getDeclarationSourceFile(moduleId);
}
return this._sourceFileCache[moduleId] ? this._sourceFileCache[moduleId]!.sourceFile : null;
}
private _getFileName(moduleId: string): string {
if (/\.d\.ts$/.test(moduleId)) {
return path.join(SRC, moduleId);
}
return path.join(SRC, `${moduleId}.ts`);
}
private _getDeclarationSourceFile(moduleId: string): CacheEntry | null {
const fileName = this._getFileName(moduleId);
if (!this._fsProvider.existsSync(fileName)) {
return null;
}
const mtime = this._fsProvider.statSync(fileName).mtime.getTime();
if (/\.d\.ts$/.test(moduleId)) {
// const mtime = this._fsProvider.statFileSync()
const fileContents = this._fsProvider.readFileSync(moduleId, fileName).toString();
return new CacheEntry(
ts.createSourceFile(fileName, fileContents, ts.ScriptTarget.ES5),
mtime
);
}
const fileContents = this._fsProvider.readFileSync(moduleId, fileName).toString();
const fileMap: IFileMap = {
'file.ts': fileContents
};
const service = ts.createLanguageService(new TypeScriptLanguageServiceHost({}, fileMap, {}));
const text = service.getEmitOutput('file.ts', true, true).outputFiles[0].text;
return new CacheEntry(
ts.createSourceFile(fileName, text, ts.ScriptTarget.ES5),
mtime
);
}
}
export function run3(resolver: DeclarationResolver): IMonacoDeclarationResult | null {
const sourceFileGetter = (moduleId: string) => resolver.getDeclarationSourceFile(moduleId);
return _run(sourceFileGetter);
}
interface ILibMap { [libName: string]: string; }
interface IFileMap { [fileName: string]: string; }
class TypeScriptLanguageServiceHost implements ts.LanguageServiceHost {
private readonly _libs: ILibMap;
private readonly _files: IFileMap;
private readonly _compilerOptions: ts.CompilerOptions;
constructor(libs: ILibMap, files: IFileMap, compilerOptions: ts.CompilerOptions) {
this._libs = libs;
this._files = files;
this._compilerOptions = compilerOptions;
}
// {{SQL CARBON EDIT}} - provide missing methods
readFile(): string | undefined {
return undefined;
}
fileExists(): boolean {
return false;
}
// --- language service host ---------------
getCompilationSettings(): ts.CompilerOptions {
return this._compilerOptions;
}
getScriptFileNames(): string[] {
return (
([] as string[])
.concat(Object.keys(this._libs))
.concat(Object.keys(this._files))
);
}
getScriptVersion(_fileName: string): string {
return '1';
}
getProjectVersion(): string {
return '1';
}
getScriptSnapshot(fileName: string): ts.IScriptSnapshot {
if (this._files.hasOwnProperty(fileName)) {
return ts.ScriptSnapshot.fromString(this._files[fileName]);
} else if (this._libs.hasOwnProperty(fileName)) {
return ts.ScriptSnapshot.fromString(this._libs[fileName]);
} else {
return ts.ScriptSnapshot.fromString('');
}
}
getScriptKind(_fileName: string): ts.ScriptKind {
return ts.ScriptKind.TS;
}
getCurrentDirectory(): string {
return '';
}
getDefaultLibFileName(_options: ts.CompilerOptions): string {
return 'defaultLib:es5';
}
isDefaultLibFileName(fileName: string): boolean {
return fileName === this.getDefaultLibFileName(this._compilerOptions);
}
}
export function execute(): IMonacoDeclarationResult {
let r = run3(new DeclarationResolver(new FSProvider()));
if (!r) {
throw new Error(`monaco.d.ts generation error - Cannot continue`);
}
return r;
}

View File

@@ -3,10 +3,11 @@
"version": "1.0.0", "version": "1.0.0",
"license": "MIT", "license": "MIT",
"devDependencies": { "devDependencies": {
"@actions/core": "1.2.6",
"@actions/github": "2.1.1",
"@azure/cosmos": "^3.14.1", "@azure/cosmos": "^3.14.1",
"@azure/identity": "^2.1.0", "@azure/identity": "^3.1.4",
"@azure/storage-blob": "^12.13.0", "@azure/storage-blob": "^12.13.0",
"@vscode/vsce": "2.16.0",
"@electron/get": "^1.12.4", "@electron/get": "^1.12.4",
"@types/ansi-colors": "^3.2.0", "@types/ansi-colors": "^3.2.0",
"@types/azure": "0.9.19", "@types/azure": "0.9.19",
@@ -17,12 +18,12 @@
"@types/documentdb": "^1.10.5", "@types/documentdb": "^1.10.5",
"@types/eslint": "4.16.1", "@types/eslint": "4.16.1",
"@types/eslint-visitor-keys": "^1.0.0", "@types/eslint-visitor-keys": "^1.0.0",
"@types/fancy-log": "^1.3.1", "@types/fancy-log": "^1.3.0",
"@types/fs-extra": "^9.0.12", "@types/fs-extra": "^9.0.12",
"@types/glob": "^7.1.1", "@types/glob": "^7.1.1",
"@types/gulp": "^4.0.10", "@types/gulp": "^4.0.5",
"@types/gulp-concat": "^0.0.32", "@types/gulp-concat": "^0.0.32",
"@types/gulp-filter": "^3.0.35", "@types/gulp-filter": "^3.0.32",
"@types/gulp-gzip": "^0.0.31", "@types/gulp-gzip": "^0.0.31",
"@types/gulp-json-editor": "^2.2.31", "@types/gulp-json-editor": "^2.2.31",
"@types/gulp-postcss": "^8.0.0", "@types/gulp-postcss": "^8.0.0",
@@ -40,27 +41,29 @@
"@types/request": "^2.47.0", "@types/request": "^2.47.0",
"@types/rimraf": "^2.0.4", "@types/rimraf": "^2.0.4",
"@types/through": "^0.0.29", "@types/through": "^0.0.29",
"@types/through2": "^2.0.34", "@types/through2": "^2.0.36",
"@types/tmp": "^0.2.1", "@types/tmp": "^0.2.1",
"@types/underscore": "^1.8.9", "@types/underscore": "^1.8.9",
"@types/webpack": "^4.41.25", "@types/webpack": "^4.41.25",
"@types/xml2js": "0.4.11", "@types/xml2js": "0.4.11",
"@typescript-eslint/experimental-utils": "~2.13.0", "@typescript-eslint/experimental-utils": "~5.10.0",
"@typescript-eslint/parser": "^5.10.0", "@typescript-eslint/parser": "^5.10.0",
"@vscode/iconv-lite-umd": "0.7.0", "@vscode/iconv-lite-umd": "0.7.0",
"@vscode/vsce": "2.16.0",
"applicationinsights": "1.0.8", "applicationinsights": "1.0.8",
"axios": "0.21.4",
"byline": "^5.0.0", "byline": "^5.0.0",
"colors": "^1.4.0", "colors": "^1.4.0",
"commander": "^7.0.0", "commander": "^7.0.0",
"debug": "^4.3.2", "debug": "^4.3.2",
"documentdb": "1.13.0", "documentdb": "1.13.0",
"electron-osx-sign": "^0.4.16", "electron-osx-sign": "^0.4.16",
"esbuild": "^0.12.6", "esbuild": "^0.14.2",
"extract-zip": "^2.0.1", "extract-zip": "^2.0.1",
"fs-extra": "^9.1.0", "fs-extra": "^9.1.0",
"got": "11.8.5", "got": "11.8.5",
"gulp-merge-json": "^2.1.1", "gulp-merge-json": "^2.1.1",
"iconv-lite-umd": "0.6.8", "gulp-shell": "^0.8.0",
"jsonc-parser": "^2.3.0", "jsonc-parser": "^2.3.0",
"mime": "^1.4.1", "mime": "^1.4.1",
"mkdirp": "^1.0.4", "mkdirp": "^1.0.4",
@@ -71,23 +74,18 @@
"rollup-plugin-commonjs": "^10.1.0", "rollup-plugin-commonjs": "^10.1.0",
"rollup-plugin-node-resolve": "^5.2.0", "rollup-plugin-node-resolve": "^5.2.0",
"source-map": "0.6.1", "source-map": "0.6.1",
"through2": "^4.0.2",
"tmp": "^0.2.1", "tmp": "^0.2.1",
"typescript": "^4.8.0-dev.20220518",
"vsce": "2.8.0",
"vscode-universal-bundler": "^0.0.2" "vscode-universal-bundler": "^0.0.2"
}, },
"scripts": { "scripts": {
"compile": "tsc -p tsconfig.build.json", "compile": "../node_modules/.bin/tsc -p tsconfig.build.json",
"watch": "tsc -p tsconfig.build.json --watch", "watch": "../node_modules/.bin/tsc -p tsconfig.build.json --watch",
"npmCheckJs": "tsc --noEmit" "npmCheckJs": "../node_modules/.bin/tsc --noEmit"
}, },
"optionalDependencies": { "optionalDependencies": {
"tree-sitter": "https://github.com/joaomoreno/node-tree-sitter/releases/download/v0.20.0/tree-sitter-0.20.0.tgz", "tree-sitter": "https://github.com/joaomoreno/node-tree-sitter/releases/download/v0.20.0/tree-sitter-0.20.0.tgz",
"tree-sitter-typescript": "^0.20.1", "tree-sitter-typescript": "^0.20.1",
"vscode-gulp-watch": "^5.0.3" "vscode-gulp-watch": "^5.0.3"
},
"resolutions": {
"json-schema": "0.4.0",
"jsonwebtoken": "9.0.0"
} }
} }

View File

@@ -2,6 +2,10 @@
"extends": "./tsconfig.json", "extends": "./tsconfig.json",
"compilerOptions": { "compilerOptions": {
"allowJs": false, "allowJs": false,
"checkJs": false "checkJs": false,
} "noEmit": false
} },
"include": [
"**/*.ts"
]
}

View File

@@ -1,6 +1,7 @@
{ {
"compilerOptions": { "compilerOptions": {
"target": "es2017", "target": "es2020",
"lib": ["ES2020"],
"module": "commonjs", "module": "commonjs",
"alwaysStrict": true, "alwaysStrict": true,
"removeComments": false, "removeComments": false,
@@ -12,19 +13,19 @@
// use the tsconfig.build.json for compiling which disable JavaScript // use the tsconfig.build.json for compiling which disable JavaScript
// type checking so that JavaScript file are not transpiled // type checking so that JavaScript file are not transpiled
"allowJs": true, "allowJs": true,
"checkJs": true,
"strict": true, "strict": true,
"exactOptionalPropertyTypes": false, "exactOptionalPropertyTypes": false,
"useUnknownInCatchVariables": false, "useUnknownInCatchVariables": false,
"noUnusedLocals": true, "noUnusedLocals": true,
"noUnusedParameters": true, "noUnusedParameters": true,
"newLine": "lf" "newLine": "lf",
"noEmit": true
}, },
"include": [ "include": [
"**/*.ts" "**/*.ts",
"**/*.js"
], ],
"exclude": [ "exclude": [
"node_modules/**", "node_modules/**"
"actions/**" // {{SQL CARBON EDIT}}
] ]
} }

File diff suppressed because it is too large Load Diff

View File

@@ -199,7 +199,8 @@ export function createViewContext(): ViewTestContext {
data: [] as any[][], data: [] as any[][],
columns: [] as string[], columns: [] as string[],
onRowSelected: onClick.event, onRowSelected: onClick.event,
appendData: (data: any[][]) => undefined, appendData: (_data: any[][]) => undefined,
setActiveCell: (_row: number, _column: number) => undefined
}); });
let loadingComponent: () => azdata.LoadingComponent = () => Object.assign({}, componentBase, { let loadingComponent: () => azdata.LoadingComponent = () => Object.assign({}, componentBase, {

View File

@@ -301,6 +301,9 @@ export class MockTableComponent extends MockUIComponent implements azdata.TableC
appendData(data: any[][]): Thenable<void> { appendData(data: any[][]): Thenable<void> {
throw new Error('Method not implemented.'); throw new Error('Method not implemented.');
} }
setActiveCell(row: number, column: number): void {
throw new Error('Method not implemented.');
}
} }
export class MockDeclarativeTableComponent extends MockUIComponent implements azdata.DeclarativeTableComponent { export class MockDeclarativeTableComponent extends MockUIComponent implements azdata.DeclarativeTableComponent {

View File

@@ -0,0 +1,52 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the Source EULA. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import * as vscode from 'vscode';
const mssqlExtensionConfigName = 'mssql';
const enableSqlAuthenticationProviderConfig = 'enableSqlAuthenticationProvider';
const azureExtensionConfigName = 'azure';
const azureAuthenticationLibraryConfig = 'authenticationLibrary';
const MSAL = 'MSAL';
/**
* @returns 'True' if MSAL auth library is in use and SQL Auth provider is enabled.
*/
export function isMssqlAuthProviderEnabled(): boolean {
return getAzureAuthenticationLibraryConfig() === MSAL && getEnableSqlAuthenticationProviderConfig();
}
export function getConfiguration(config: string): vscode.WorkspaceConfiguration {
return vscode.workspace.getConfiguration(config);
}
/**
* Reads setting 'azure.AuthenticationLibrary' and returns the library name enabled.
* @returns MSAL | ADAL
*/
export function getAzureAuthenticationLibraryConfig(): string {
const config = getConfiguration(azureExtensionConfigName);
if (config) {
return config.get<string>(azureAuthenticationLibraryConfig, MSAL); // default Auth library
}
else {
return MSAL; // default Auth library
}
}
/**
* Reads setting 'mssql.enableSqlAuthenticationProvider' and returns true if it's enabled.
* @returns True Sql Auth provider is enabled for MSSQL provider.
*/
export function getEnableSqlAuthenticationProviderConfig(): boolean {
const config = getConfiguration(mssqlExtensionConfigName);
if (config) {
return config.get<boolean>(enableSqlAuthenticationProviderConfig, true); // enabled by default
}
else {
return true; // enabled by default
}
}

View File

@@ -9,6 +9,7 @@ import { ImportPage } from '../api/importPage';
import { InsertDataResponse } from '../../services/contracts'; import { InsertDataResponse } from '../../services/contracts';
import * as constants from '../../common/constants'; import * as constants from '../../common/constants';
import { EOL } from 'os'; import { EOL } from 'os';
import { isMssqlAuthProviderEnabled } from '../../common/utils';
export class SummaryPage extends ImportPage { export class SummaryPage extends ImportPage {
private _table: azdata.TableComponent; private _table: azdata.TableComponent;
@@ -137,10 +138,14 @@ export class SummaryPage extends ImportPage {
const currentServer = this.model.server; const currentServer = this.model.server;
const includePasswordInConnectionString = (currentServer.options.authenticationType === azdata.connection.AuthenticationType.Integrated) ? false : true; const includePasswordInConnectionString = (currentServer.options.authenticationType === azdata.connection.AuthenticationType.Integrated) ? false : true;
const connectionString = await azdata.connection.getConnectionString(currentServer.connectionId, includePasswordInConnectionString); let connectionString = await azdata.connection.getConnectionString(currentServer.connectionId, includePasswordInConnectionString);
let accessToken = undefined; let accessToken = undefined;
if (currentServer.options.authenticationType === azdata.connection.AuthenticationType.AzureMFA) { if (currentServer.options.authenticationType === azdata.connection.AuthenticationType.AzureMFA) {
// Remove authentication properties from connection string if SQL Authentication Provider is enabled
if (isMssqlAuthProviderEnabled()) {
connectionString = this.updateConnectionStringForAccessToken(connectionString);
}
const azureAccount = (await azdata.accounts.getAllAccounts()).filter(v => v.key.accountId === currentServer.options.azureAccount)[0]; const azureAccount = (await azdata.accounts.getAllAccounts()).filter(v => v.key.accountId === currentServer.options.azureAccount)[0];
accessToken = (await azdata.accounts.getAccountSecurityToken(azureAccount, currentServer.options.azureTenantId, azdata.AzureResource.Sql)).token; accessToken = (await azdata.accounts.getAccountSecurityToken(azureAccount, currentServer.options.azureTenantId, azdata.AzureResource.Sql)).token;
} }
@@ -178,6 +183,21 @@ export class SummaryPage extends ImportPage {
}); });
} }
/**
* Removes authentication related properties from connection string as SQL Tools Service now supports
* 'EnableSqlAuthenticationProvider' which sets the below properties on connection string that conflict with access token:
* 1. User Id
* 2. Authentication
* Since we need to set access token, we cannot use the same connection string as is.
* @param connString Connection string to fix
* @returns Updated connection string
*/
private updateConnectionStringForAccessToken(connString: string): string {
return connString ? connString.split(';').filter(prop =>
!['user', 'uid', 'password', 'pwd', 'authentication'].some(prefix => prop.toLocaleLowerCase().startsWith(prefix))
).join(';') : connString;
}
// private async getCountRowsInserted(): Promise<Number> { // private async getCountRowsInserted(): Promise<Number> {
// let connectionUri = await azdata.connection.getUriForConnection(this.model.server.connectionId); // let connectionUri = await azdata.connection.getUriForConnection(this.model.server.connectionId);
// let queryProvider = azdata.dataprotocol.getProvider<azdata.QueryProvider>(this.model.server.providerName, azdata.DataProviderType.QueryProvider); // let queryProvider = azdata.dataprotocol.getProvider<azdata.QueryProvider>(this.model.server.providerName, azdata.DataProviderType.QueryProvider);

View File

@@ -16,7 +16,8 @@
"Programming Languages" "Programming Languages"
], ],
"enabledApiProposals": [ "enabledApiProposals": [
"documentPaste" "documentPaste",
"notebookEditor"
], ],
"activationEvents": [ "activationEvents": [
"onLanguage:markdown", "onLanguage:markdown",

View File

@@ -1,6 +1,6 @@
{ {
"downloadUrl": "https://github.com/Microsoft/sqltoolsservice/releases/download/{#version#}/microsoft.sqltools.servicelayer-{#fileName#}", "downloadUrl": "https://github.com/Microsoft/sqltoolsservice/releases/download/{#version#}/microsoft.sqltools.servicelayer-{#fileName#}",
"version": "4.7.0.29", "version": "4.7.1.4",
"downloadFileNames": { "downloadFileNames": {
"Windows_86": "win-x86-net7.0.zip", "Windows_86": "win-x86-net7.0.zip",
"Windows_64": "win-x64-net7.0.zip", "Windows_64": "win-x64-net7.0.zip",

View File

@@ -515,7 +515,7 @@ export interface DeployParams {
packageFilePath: string; packageFilePath: string;
databaseName: string; databaseName: string;
upgradeExisting: boolean; upgradeExisting: boolean;
sqlCommandVariableValues?: Map<string, string>; sqlCommandVariableValues?: Record<string, string>;
deploymentOptions?: mssql.DeploymentOptions; deploymentOptions?: mssql.DeploymentOptions;
ownerUri: string; ownerUri: string;
taskExecutionMode: TaskExecutionMode; taskExecutionMode: TaskExecutionMode;
@@ -524,7 +524,7 @@ export interface DeployParams {
export interface GenerateDeployScriptParams { export interface GenerateDeployScriptParams {
packageFilePath: string; packageFilePath: string;
databaseName: string; databaseName: string;
sqlCommandVariableValues?: Map<string, string>; sqlCommandVariableValues?: Record<string, string>;
deploymentOptions?: mssql.DeploymentOptions deploymentOptions?: mssql.DeploymentOptions
ownerUri: string; ownerUri: string;
taskExecutionMode: TaskExecutionMode; taskExecutionMode: TaskExecutionMode;
@@ -555,7 +555,7 @@ export interface SavePublishProfileParams {
profilePath: string; profilePath: string;
databaseName: string; databaseName: string;
connectionString: string; connectionString: string;
sqlCommandVariableValues?: Map<string, string>; sqlCommandVariableValues?: Record<string, string>;
deploymentOptions?: mssql.DeploymentOptions; deploymentOptions?: mssql.DeploymentOptions;
} }

View File

@@ -55,12 +55,12 @@ export class DacFxService extends BaseService implements mssql.IDacFxService {
} }
public async deployDacpac(packageFilePath: string, targetDatabaseName: string, upgradeExisting: boolean, ownerUri: string, taskExecutionMode: azdata.TaskExecutionMode, sqlCommandVariableValues?: Map<string, string>, deploymentOptions?: mssql.DeploymentOptions): Promise<mssql.DacFxResult> { public async deployDacpac(packageFilePath: string, targetDatabaseName: string, upgradeExisting: boolean, ownerUri: string, taskExecutionMode: azdata.TaskExecutionMode, sqlCommandVariableValues?: Map<string, string>, deploymentOptions?: mssql.DeploymentOptions): Promise<mssql.DacFxResult> {
const params: contracts.DeployParams = { packageFilePath: packageFilePath, databaseName: targetDatabaseName, upgradeExisting: upgradeExisting, sqlCommandVariableValues: sqlCommandVariableValues, deploymentOptions: deploymentOptions, ownerUri: ownerUri, taskExecutionMode: taskExecutionMode }; const params: contracts.DeployParams = { packageFilePath: packageFilePath, databaseName: targetDatabaseName, upgradeExisting: upgradeExisting, sqlCommandVariableValues: sqlCommandVariableValues ? Object.fromEntries(sqlCommandVariableValues) : undefined, deploymentOptions: deploymentOptions, ownerUri: ownerUri, taskExecutionMode: taskExecutionMode };
return this.runWithErrorHandling(contracts.DeployRequest.type, params); return this.runWithErrorHandling(contracts.DeployRequest.type, params);
} }
public async generateDeployScript(packageFilePath: string, targetDatabaseName: string, ownerUri: string, taskExecutionMode: azdata.TaskExecutionMode, sqlCommandVariableValues?: Map<string, string>, deploymentOptions?: mssql.DeploymentOptions): Promise<mssql.DacFxResult> { public async generateDeployScript(packageFilePath: string, targetDatabaseName: string, ownerUri: string, taskExecutionMode: azdata.TaskExecutionMode, sqlCommandVariableValues?: Map<string, string>, deploymentOptions?: mssql.DeploymentOptions): Promise<mssql.DacFxResult> {
const params: contracts.GenerateDeployScriptParams = { packageFilePath: packageFilePath, databaseName: targetDatabaseName, sqlCommandVariableValues: sqlCommandVariableValues, deploymentOptions: deploymentOptions, ownerUri: ownerUri, taskExecutionMode: taskExecutionMode }; const params: contracts.GenerateDeployScriptParams = { packageFilePath: packageFilePath, databaseName: targetDatabaseName, sqlCommandVariableValues: sqlCommandVariableValues ? Object.fromEntries(sqlCommandVariableValues) : undefined, deploymentOptions: deploymentOptions, ownerUri: ownerUri, taskExecutionMode: taskExecutionMode };
return this.runWithErrorHandling(contracts.GenerateDeployScriptRequest.type, params); return this.runWithErrorHandling(contracts.GenerateDeployScriptRequest.type, params);
} }
@@ -85,7 +85,7 @@ export class DacFxService extends BaseService implements mssql.IDacFxService {
} }
public async savePublishProfile(profilePath: string, databaseName: string, connectionString: string, sqlCommandVariableValues?: Map<string, string>, deploymentOptions?: mssql.DeploymentOptions): Promise<azdata.ResultStatus> { public async savePublishProfile(profilePath: string, databaseName: string, connectionString: string, sqlCommandVariableValues?: Map<string, string>, deploymentOptions?: mssql.DeploymentOptions): Promise<azdata.ResultStatus> {
const params: contracts.SavePublishProfileParams = { profilePath, databaseName, connectionString, sqlCommandVariableValues, deploymentOptions }; const params: contracts.SavePublishProfileParams = { profilePath, databaseName, connectionString, sqlCommandVariableValues: sqlCommandVariableValues ? Object.fromEntries(sqlCommandVariableValues) : undefined, deploymentOptions };
return this.runWithErrorHandling(contracts.SavePublishProfileRequest.type, params); return this.runWithErrorHandling(contracts.SavePublishProfileRequest.type, params);
} }
} }

View File

@@ -917,7 +917,14 @@ declare module 'mssql' {
} }
/** /**
* Base interface for the object view information * Base interface for all the security principal objects. e.g. Login, Server Role, Database Role...
*/
export interface SecurityPrincipalObject extends SqlObject {
securablePermissions: SecurablePermissions[];
}
/**
* Base interface for the object view information.
*/ */
export interface ObjectViewInfo<T extends SqlObject> { export interface ObjectViewInfo<T extends SqlObject> {
/** /**
@@ -926,10 +933,52 @@ declare module 'mssql' {
objectInfo: T; objectInfo: T;
} }
/**
* Securable type metadata.
*/
export interface SecurableTypeMetadata {
/**
* Name of the securable type.
*/
name: string;
/**
* Display name of the securable type.
*/
displayName: string;
/**
* Permissions supported by the securable type.
*/
permissions: PermissionMetadata[];
}
/**
* Permission metadata.
*/
export interface PermissionMetadata {
/**
* Name of the permission.
*/
name: string;
/**
* Display name of the permission.
*/
displayName: string;
}
/**
* Base interface for security principal object's view information.
*/
export interface SecurityPrincipalViewInfo<T extends SecurityPrincipalObject> extends ObjectViewInfo<T> {
/**
* The securable types that the security principal object can be granted permissions on.
*/
supportedSecurableTypes: SecurableTypeMetadata[];
}
/** /**
* Server level login. * Server level login.
*/ */
export interface Login extends SqlObject { export interface Login extends SecurityPrincipalObject {
/** /**
* Authentication type. * Authentication type.
*/ */
@@ -1025,7 +1074,7 @@ declare module 'mssql' {
/** /**
* The information required to render the login view. * The information required to render the login view.
*/ */
export interface LoginViewInfo extends ObjectViewInfo<Login> { export interface LoginViewInfo extends SecurityPrincipalViewInfo<Login> {
/** /**
* The authentication types supported by the server. * The authentication types supported by the server.
*/ */
@@ -1062,20 +1111,24 @@ declare module 'mssql' {
/** /**
* The permission information a principal has on a securable. * The permission information a principal has on a securable.
*/ */
export interface Permission { export interface SecurablePermissionItem {
/** /**
* Name of the permission. * name of the permission.
*/ */
name: string; permission: string;
/** /**
* Whether the permission is granted or denied. * Name of the grantor.
*/ */
grant: boolean; grantor: string;
/**
* Whether the permission is granted or denied. Undefined means not specified.
*/
grant?: boolean;
/** /**
* Whether the pincipal can grant this permission to other principals. * Whether the pincipal can grant this permission to other principals.
* The value will be ignored if the grant property is set to false. * The value will be ignored if the grant property is set to false.
*/ */
withGrant: boolean; withGrant?: boolean;
} }
/** /**
@@ -1083,13 +1136,25 @@ declare module 'mssql' {
*/ */
export interface SecurablePermissions { export interface SecurablePermissions {
/** /**
* The securable. * The securable name.
*/ */
securable: SqlObject; name: string;
/** /**
* The Permissions. * The securable type.
*/ */
permissions: Permission[]; type: string;
/**
* The schema name of the object if applicable.
*/
schema?: string;
/**
* The permissions.
*/
permissions: SecurablePermissionItem[];
/**
* The effective permissions. Includes all permissions granted to the principal, including those granted through role memberships.
*/
effectivePermissions: string[];
} }
/** /**
@@ -1135,7 +1200,7 @@ declare module 'mssql' {
/** /**
* Database user. * Database user.
*/ */
export interface User extends SqlObject { export interface User extends SecurityPrincipalObject {
/** /**
* Type of the user. * Type of the user.
*/ */
@@ -1172,7 +1237,7 @@ declare module 'mssql' {
/** /**
* The information required to render the user view. * The information required to render the user view.
*/ */
export interface UserViewInfo extends ObjectViewInfo<User> { export interface UserViewInfo extends SecurityPrincipalViewInfo<User> {
/** /**
* All user types supported by the database. * All user types supported by the database.
*/ */
@@ -1198,7 +1263,7 @@ declare module 'mssql' {
/** /**
* Interface representing the server role object. * Interface representing the server role object.
*/ */
export interface ServerRoleInfo extends SqlObject { export interface ServerRoleInfo extends SecurityPrincipalObject {
/** /**
* Name of the server principal that owns the server role. * Name of the server principal that owns the server role.
*/ */
@@ -1216,7 +1281,7 @@ declare module 'mssql' {
/** /**
* Interface representing the information required to render the server role view. * Interface representing the information required to render the server role view.
*/ */
export interface ServerRoleViewInfo extends ObjectViewInfo<ServerRoleInfo> { export interface ServerRoleViewInfo extends SecurityPrincipalViewInfo<ServerRoleInfo> {
/** /**
* Whether the server role is a fixed role. * Whether the server role is a fixed role.
*/ */
@@ -1230,7 +1295,7 @@ declare module 'mssql' {
/** /**
* Interface representing the application role object. * Interface representing the application role object.
*/ */
export interface ApplicationRoleInfo extends SqlObject { export interface ApplicationRoleInfo extends SecurityPrincipalObject {
/** /**
* Default schema of the application role. * Default schema of the application role.
*/ */
@@ -1248,7 +1313,7 @@ declare module 'mssql' {
/** /**
* Interface representing the information required to render the application role view. * Interface representing the information required to render the application role view.
*/ */
export interface ApplicationRoleViewInfo extends ObjectViewInfo<ApplicationRoleInfo> { export interface ApplicationRoleViewInfo extends SecurityPrincipalViewInfo<ApplicationRoleInfo> {
/** /**
* List of all the schemas in the database. * List of all the schemas in the database.
*/ */
@@ -1258,7 +1323,7 @@ declare module 'mssql' {
/** /**
* Interface representing the database role object. * Interface representing the database role object.
*/ */
export interface DatabaseRoleInfo extends SqlObject { export interface DatabaseRoleInfo extends SecurityPrincipalObject {
/** /**
* Name of the database principal that owns the database role. * Name of the database principal that owns the database role.
*/ */
@@ -1276,7 +1341,7 @@ declare module 'mssql' {
/** /**
* Interface representing the information required to render the database role view. * Interface representing the information required to render the database role view.
*/ */
export interface DatabaseRoleViewInfo extends ObjectViewInfo<DatabaseRoleInfo> { export interface DatabaseRoleViewInfo extends SecurityPrincipalViewInfo<DatabaseRoleInfo> {
/** /**
* List of all the schemas in the database. * List of all the schemas in the database.
*/ */
@@ -1294,7 +1359,7 @@ declare module 'mssql' {
/** /**
* type of the object. * type of the object.
*/ */
type: NodeType; type: string;
/** /**
* schema of the object. * schema of the object.
*/ */
@@ -1369,7 +1434,7 @@ declare module 'mssql' {
* @param searchText Search text. * @param searchText Search text.
* @param schema Schema to search in. * @param schema Schema to search in.
*/ */
search(contextId: string, objectTypes: ObjectManagement.NodeType[], searchText?: string, schema?: string): Thenable<ObjectManagement.SearchResultItem[]>; search(contextId: string, objectTypes: string[], searchText?: string, schema?: string): Thenable<ObjectManagement.SearchResultItem[]>;
} }
// Object Management - End. // Object Management - End.
} }

View File

@@ -30,9 +30,22 @@ export const RenameObjectDialogTitle: string = localize('objectManagement.rename
export const OwnerText: string = localize('objectManagement.ownerText', "Owner"); export const OwnerText: string = localize('objectManagement.ownerText', "Owner");
export const BrowseText = localize('objectManagement.browseText', "Browse…"); export const BrowseText = localize('objectManagement.browseText', "Browse…");
export const BrowseOwnerButtonAriaLabel = localize('objectManagement.browseForOwnerText', "Browse for an owner"); export const BrowseOwnerButtonAriaLabel = localize('objectManagement.browseForOwnerText', "Browse for an owner");
export const AddMemberAriaLabel = localize('objectManagement.addMemberText', "Add a member"); export const AddMemberAriaLabel = localize('objectManagement.addMembersText', "Add members");
export const RemoveMemberAriaLabel = localize('objectManagement.removeMemberText', "Remove selected member"); export const RemoveMemberAriaLabel = localize('objectManagement.removeMemberText', "Remove selected member");
export const AddSecurableAriaLabel = localize('objectManagement.addSecurablesText', "Add securables");
export const RemoveSecurableAriaLabel = localize('objectManagement.removeSecurablesText', "Remove selected securable");
export const SecurablesText = localize('objectManagement.securablesText', "Securables");
export const ExplicitPermissionsTableLabel = localize('objectManagement.explicitPermissionsTableLabel', "Explicit permissions for selected securable");
export const EffectivePermissionsTableLabel = localize('objectManagement.effectivePermissionsTableLabel', "Effective permissions for selected securable");
export const PermissionColumnHeader = localize('objectManagement.permissionColumnHeader', "Permission");
export const GrantorColumnHeader = localize('objectManagement.grantorColumnHeader', "Grantor");
export const GrantColumnHeader = localize('objectManagement.grantColumnHeader', "Grant");
export const WithGrantColumnHeader = localize('objectManagement.withGrantColumnHeader', "With Grant");
export const DenyColumnHeader = localize('objectManagement.denyColumnHeader', "Deny");
export const SelectSecurablesDialogTitle = localize('objectManagement.selectSecurablesDialogTitle', "Select Securables");
export function ExplicitPermissionsTableLabelSelected(name: string): string { return localize('objectManagement.explicitPermissionsTableLabelSelected', "Explicit permissions for: {0}", name); }
export function EffectivePermissionsTableLabelSelected(name: string): string { return localize('objectManagement.effectivePermissionsTableLabelSelected', "Effective permissions for: {0}", name); }
export function RefreshObjectExplorerError(error: string): string { export function RefreshObjectExplorerError(error: string): string {
return localize({ return localize({
@@ -133,12 +146,15 @@ export const LoginNotSelectedError = localize('objectManagement.loginNotSelected
export const MembershipSectionHeader = localize('objectManagement.membershipLabel', "Membership"); export const MembershipSectionHeader = localize('objectManagement.membershipLabel', "Membership");
export const MemberSectionHeader = localize('objectManagement.membersLabel', "Members"); export const MemberSectionHeader = localize('objectManagement.membersLabel', "Members");
export const SchemaText = localize('objectManagement.schemaLabel', "Schema"); export const SchemaText = localize('objectManagement.schemaLabel', "Schema");
// Database
export const DatabaseExistsError = (dbName: string) => localize('objectManagement.databaseExistsError', "Database '{0}' already exists. Choose a different database name.", dbName); export const DatabaseExistsError = (dbName: string) => localize('objectManagement.databaseExistsError', "Database '{0}' already exists. Choose a different database name.", dbName);
export const CollationText = localize('objectManagement.collationLabel', "Collation"); export const CollationText = localize('objectManagement.collationLabel', "Collation");
export const RecoveryModelText = localize('objectManagement.recoveryModelLabel', "Recovery Model"); export const RecoveryModelText = localize('objectManagement.recoveryModelLabel', "Recovery Model");
export const CompatibilityLevelText = localize('objectManagement.compatibilityLevelLabel', "Compatibility Level"); export const CompatibilityLevelText = localize('objectManagement.compatibilityLevelLabel', "Compatibility Level");
export const ContainmentTypeText = localize('objectManagement.containmentTypeLabel', "Containment Type"); export const ContainmentTypeText = localize('objectManagement.containmentTypeLabel', "Containment Type");
// Login // Login
export const BlankPasswordConfirmationText: string = localize('objectManagement.blankPasswordConfirmation', "Creating a login with a blank password is a security risk. Are you sure you want to continue?"); export const BlankPasswordConfirmationText: string = localize('objectManagement.blankPasswordConfirmation', "Creating a login with a blank password is a security risk. Are you sure you want to continue?");
export const DeleteLoginConfirmationText: string = localize('objectManagement.deleteLoginConfirmation', "Deleting server logins does not delete the database users associated with the logins. To complete the process, delete the users in each database. It may be necessary to first transfer the ownership of schemas to new users."); export const DeleteLoginConfirmationText: string = localize('objectManagement.deleteLoginConfirmation', "Deleting server logins does not delete the database users associated with the logins. To complete the process, delete the users in each database. It may be necessary to first transfer the ownership of schemas to new users.");

View File

@@ -67,6 +67,126 @@ export class ObjectManagementService extends BaseService implements IObjectManag
} }
} }
const ServerLevelSecurableTypes: ObjectManagement.SecurableTypeMetadata[] = [
{
name: 'Server',
displayName: 'Server',
permissions: [{
name: 'CONNECT SQL',
displayName: 'CONNECT SQL'
}, {
name: 'VIEW ANY DATABASE',
displayName: 'VIEW ANY DATABASE'
}]
}, {
name: 'ServerRole',
displayName: 'Server Role',
permissions: [{
name: 'ALTER',
displayName: 'ALTER'
}, {
name: 'CONTROL',
displayName: 'CONTROL'
}, {
name: 'TAKE OWNERSHIP',
displayName: 'TAKE OWNERSHIP'
}]
}
];
const DatabaseLevelSecurableTypes: ObjectManagement.SecurableTypeMetadata[] = [
{
name: 'AggregateFunction',
displayName: 'Aggregate Function',
permissions: [{
name: 'EXECUTE',
displayName: 'EXECUTE'
}, {
name: 'ALTER',
displayName: 'ALTER'
}]
}, {
name: 'Table',
displayName: 'Table',
permissions: [{
name: 'SELECT',
displayName: 'SELECT'
}, {
name: 'ALTER',
displayName: 'ALTER'
}, {
name: 'CONTROL',
displayName: 'CONTROL'
}, {
name: 'TAKE OWNERSHIP',
displayName: 'TAKE OWNERSHIP'
}]
}, {
name: 'View',
displayName: 'View',
permissions: [{
name: 'ALTER',
displayName: 'ALTER'
}, {
name: 'CONTROL',
displayName: 'CONTROL'
}, {
name: 'TAKE OWNERSHIP',
displayName: 'TAKE OWNERSHIP'
}]
}
]
const ServerLevelPermissions: ObjectManagement.SecurablePermissions[] = [
{
name: 'Server',
type: 'Server',
permissions: [
{
permission: 'CONNECT SQL',
grant: true,
grantor: 'sa',
withGrant: undefined
}, {
permission: 'VIEW ANY DATABASE',
grant: false,
grantor: 'sa',
withGrant: undefined
}
],
effectivePermissions: ['CONNECT SQL', 'VIEW ANY DATABASE']
}
];
const DatabaseLevelPermissions: ObjectManagement.SecurablePermissions[] = [
{
name: 'table1',
type: 'Table',
schema: 'dbo',
permissions: [
{
permission: 'SELECT',
grant: true,
grantor: '',
withGrant: undefined
}
],
effectivePermissions: ['SELECT']
}, {
name: 'view1',
type: 'View',
schema: 'Sales',
permissions: [
{
permission: 'ALTER',
grant: true,
grantor: '',
withGrant: undefined
}
],
effectivePermissions: ['ALTER']
}
];
export class TestObjectManagementService implements IObjectManagementService { export class TestObjectManagementService implements IObjectManagementService {
initializeView(contextId: string, objectType: ObjectManagement.NodeType, connectionUri: string, database: string, isNewObject: boolean, parentUrn: string, objectUrn: string): Thenable<ObjectManagement.ObjectViewInfo<ObjectManagement.SqlObject>> { initializeView(contextId: string, objectType: ObjectManagement.NodeType, connectionUri: string, database: string, isNewObject: boolean, parentUrn: string, objectUrn: string): Thenable<ObjectManagement.ObjectViewInfo<ObjectManagement.SqlObject>> {
let obj; let obj;
@@ -102,18 +222,18 @@ export class TestObjectManagementService implements IObjectManagementService {
return this.delayAndResolve(); return this.delayAndResolve();
} }
async search(contextId: string, objectTypes: ObjectManagement.NodeType[], searchText: string, schema: string): Promise<ObjectManagement.SearchResultItem[]> { async search(contextId: string, objectTypes: ObjectManagement.NodeType[], searchText?: string, schema?: string): Promise<ObjectManagement.SearchResultItem[]> {
const items: ObjectManagement.SearchResultItem[] = []; const items: ObjectManagement.SearchResultItem[] = [];
objectTypes.forEach(type => { objectTypes.forEach(type => {
items.push(...this.generateSearchResult(type, 15)); items.push(...this.generateSearchResult(type, schema, 15));
}); });
return this.delayAndResolve(items); return this.delayAndResolve(items);
} }
private generateSearchResult(objectType: ObjectManagement.NodeType, count: number): ObjectManagement.SearchResultItem[] { private generateSearchResult(objectType: ObjectManagement.NodeType, schema: string | undefined, count: number): ObjectManagement.SearchResultItem[] {
let items: ObjectManagement.SearchResultItem[] = []; let items: ObjectManagement.SearchResultItem[] = [];
for (let i = 0; i < count; i++) { for (let i = 0; i < count; i++) {
items.push(<ObjectManagement.SearchResultItem>{ name: `${objectType} ${i}`, type: objectType }); items.push(<ObjectManagement.SearchResultItem>{ name: `${objectType} ${i}`, schema: schema, type: objectType });
} }
return items; return items;
} }
@@ -136,7 +256,8 @@ export class TestObjectManagementService implements IObjectManagementService {
serverRoles: ['public', 'bulkadmin'], serverRoles: ['public', 'bulkadmin'],
connectPermission: true, connectPermission: true,
isEnabled: true, isEnabled: true,
isLockedOut: false isLockedOut: false,
securablePermissions: []
}, },
authenticationTypes: [ObjectManagement.AuthenticationType.Sql, ObjectManagement.AuthenticationType.Windows], authenticationTypes: [ObjectManagement.AuthenticationType.Sql, ObjectManagement.AuthenticationType.Windows],
supportAdvancedOptions: true, supportAdvancedOptions: true,
@@ -144,7 +265,8 @@ export class TestObjectManagementService implements IObjectManagementService {
canEditLockedOutState: false, canEditLockedOutState: false,
languages: languages, languages: languages,
databases: databases, databases: databases,
serverRoles: serverRoles serverRoles: serverRoles,
supportedSecurableTypes: ServerLevelSecurableTypes
}; };
} else { } else {
login = <ObjectManagement.LoginViewInfo>{ login = <ObjectManagement.LoginViewInfo>{
@@ -160,7 +282,8 @@ export class TestObjectManagementService implements IObjectManagementService {
connectPermission: true, connectPermission: true,
isEnabled: true, isEnabled: true,
isLockedOut: false, isLockedOut: false,
password: '******************' password: '******************',
securablePermissions: ServerLevelPermissions
}, },
authenticationTypes: [ObjectManagement.AuthenticationType.Sql, ObjectManagement.AuthenticationType.Windows], authenticationTypes: [ObjectManagement.AuthenticationType.Sql, ObjectManagement.AuthenticationType.Windows],
supportAdvancedOptions: true, supportAdvancedOptions: true,
@@ -168,7 +291,8 @@ export class TestObjectManagementService implements IObjectManagementService {
canEditLockedOutState: false, canEditLockedOutState: false,
languages: languages, languages: languages,
databases: databases, databases: databases,
serverRoles: serverRoles serverRoles: serverRoles,
supportedSecurableTypes: ServerLevelSecurableTypes
}; };
} }
return login; return login;
@@ -192,7 +316,8 @@ export class TestObjectManagementService implements IObjectManagementService {
loginName: 'sa', loginName: 'sa',
ownedSchemas: [], ownedSchemas: [],
databaseRoles: [], databaseRoles: [],
password: '' password: '',
securablePermissions: []
}, },
languages: languages, languages: languages,
schemas: schemas, schemas: schemas,
@@ -203,7 +328,8 @@ export class TestObjectManagementService implements IObjectManagementService {
ObjectManagement.UserType.AADAuthentication, ObjectManagement.UserType.AADAuthentication,
ObjectManagement.UserType.SqlAuthentication, ObjectManagement.UserType.SqlAuthentication,
ObjectManagement.UserType.NoLoginAccess ObjectManagement.UserType.NoLoginAccess
] ],
supportedSecurableTypes: DatabaseLevelSecurableTypes
}; };
} else { } else {
viewInfo = { viewInfo = {
@@ -214,7 +340,8 @@ export class TestObjectManagementService implements IObjectManagementService {
defaultLanguage: '<default>', defaultLanguage: '<default>',
loginName: 'sa', loginName: 'sa',
ownedSchemas: ['dbo'], ownedSchemas: ['dbo'],
databaseRoles: ['dbmanager', 'bulkadmin'] databaseRoles: ['dbmanager', 'bulkadmin'],
securablePermissions: DatabaseLevelPermissions
}, },
languages: languages, languages: languages,
schemas: schemas, schemas: schemas,
@@ -225,7 +352,8 @@ export class TestObjectManagementService implements IObjectManagementService {
ObjectManagement.UserType.AADAuthentication, ObjectManagement.UserType.AADAuthentication,
ObjectManagement.UserType.SqlAuthentication, ObjectManagement.UserType.SqlAuthentication,
ObjectManagement.UserType.NoLoginAccess ObjectManagement.UserType.NoLoginAccess
] ],
supportedSecurableTypes: DatabaseLevelSecurableTypes
}; };
} }
return viewInfo; return viewInfo;
@@ -237,19 +365,23 @@ export class TestObjectManagementService implements IObjectManagementService {
name: '', name: '',
members: [], members: [],
owner: '', owner: '',
memberships: [] memberships: [],
securablePermissions: []
}, },
isFixedRole: false, isFixedRole: false,
serverRoles: ['ServerLevelServerRole 1', 'ServerLevelServerRole 2', 'ServerLevelServerRole 3', 'ServerLevelServerRole 4'], serverRoles: ['ServerLevelServerRole 1', 'ServerLevelServerRole 2', 'ServerLevelServerRole 3', 'ServerLevelServerRole 4'],
supportedSecurableTypes: ServerLevelSecurableTypes
} : <ObjectManagement.ServerRoleViewInfo>{ } : <ObjectManagement.ServerRoleViewInfo>{
objectInfo: { objectInfo: {
name: 'ServerLevelServerRole 1', name: 'ServerLevelServerRole 1',
members: ['ServerLevelLogin 1', 'ServerLevelServerRole 2'], members: ['ServerLevelLogin 1', 'ServerLevelServerRole 2'],
owner: 'ServerLevelLogin 2', owner: 'ServerLevelLogin 2',
memberships: ['ServerLevelServerRole 3', 'ServerLevelServerRole 4'] memberships: ['ServerLevelServerRole 3', 'ServerLevelServerRole 4'],
securablePermissions: ServerLevelPermissions
}, },
isFixedRole: false, isFixedRole: false,
serverRoles: ['ServerLevelServerRole 2', 'ServerLevelServerRole 3', 'ServerLevelServerRole 4'] serverRoles: ['ServerLevelServerRole 2', 'ServerLevelServerRole 3', 'ServerLevelServerRole 4'],
supportedSecurableTypes: ServerLevelSecurableTypes
}; };
} }
@@ -259,16 +391,20 @@ export class TestObjectManagementService implements IObjectManagementService {
name: '', name: '',
defaultSchema: 'dbo', defaultSchema: 'dbo',
ownedSchemas: [], ownedSchemas: [],
securablePermissions: []
}, },
schemas: ['dbo', 'sys', 'admin'] schemas: ['dbo', 'sys', 'admin'],
supportedSecurableTypes: []
} : <ObjectManagement.ApplicationRoleViewInfo>{ } : <ObjectManagement.ApplicationRoleViewInfo>{
objectInfo: { objectInfo: {
name: 'app role1', name: 'app role1',
password: '******************', password: '******************',
defaultSchema: 'dbo', defaultSchema: 'dbo',
ownedSchemas: ['dbo'], ownedSchemas: ['dbo'],
securablePermissions: DatabaseLevelPermissions
}, },
schemas: ['dbo', 'sys', 'admin'] schemas: ['dbo', 'sys', 'admin'],
supportedSecurableTypes: DatabaseLevelSecurableTypes
}; };
} }
@@ -278,17 +414,21 @@ export class TestObjectManagementService implements IObjectManagementService {
name: '', name: '',
owner: '', owner: '',
members: [], members: [],
ownedSchemas: [] ownedSchemas: [],
securablePermissions: []
}, },
schemas: ['dbo', 'sys', 'admin'] schemas: ['dbo', 'sys', 'admin'],
supportedSecurableTypes: DatabaseLevelSecurableTypes
} : <ObjectManagement.DatabaseRoleViewInfo>{ } : <ObjectManagement.DatabaseRoleViewInfo>{
objectInfo: { objectInfo: {
name: 'db role1', name: 'db role1',
owner: '', owner: '',
members: [], members: [],
ownedSchemas: ['dbo'] ownedSchemas: ['dbo'],
securablePermissions: DatabaseLevelPermissions
}, },
schemas: ['dbo', 'sys', 'admin'] schemas: ['dbo', 'sys', 'admin'],
supportedSecurableTypes: DatabaseLevelSecurableTypes
}; };
} }

View File

@@ -3,14 +3,15 @@
* Licensed under the Source EULA. See License.txt in the project root for license information. * Licensed under the Source EULA. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/ *--------------------------------------------------------------------------------------------*/
import * as azdata from 'azdata'; import * as azdata from 'azdata';
import { ObjectManagementDialogBase, ObjectManagementDialogOptions } from './objectManagementDialogBase'; import { ObjectManagementDialogOptions } from './objectManagementDialogBase';
import { IObjectManagementService, ObjectManagement } from 'mssql'; import { IObjectManagementService, ObjectManagement } from 'mssql';
import * as localizedConstants from '../localizedConstants'; import * as localizedConstants from '../localizedConstants';
import { AlterApplicationRoleDocUrl, CreateApplicationRoleDocUrl } from '../constants'; import { AlterApplicationRoleDocUrl, CreateApplicationRoleDocUrl } from '../constants';
import { isValidSQLPassword } from '../utils'; import { isValidSQLPassword } from '../utils';
import { DefaultMaxTableHeight } from '../../ui/dialogBase'; import { DefaultMaxTableRowCount } from '../../ui/dialogBase';
import { PrincipalDialogBase } from './principalDialogBase';
export class ApplicationRoleDialog extends ObjectManagementDialogBase<ObjectManagement.ApplicationRoleInfo, ObjectManagement.ApplicationRoleViewInfo> { export class ApplicationRoleDialog extends PrincipalDialogBase<ObjectManagement.ApplicationRoleInfo, ObjectManagement.ApplicationRoleViewInfo> {
// Sections // Sections
private generalSection: azdata.GroupContainer; private generalSection: azdata.GroupContainer;
private ownedSchemasSection: azdata.GroupContainer; private ownedSchemasSection: azdata.GroupContainer;
@@ -25,7 +26,7 @@ export class ApplicationRoleDialog extends ObjectManagementDialogBase<ObjectMana
private ownedSchemaTable: azdata.TableComponent; private ownedSchemaTable: azdata.TableComponent;
constructor(objectManagementService: IObjectManagementService, options: ObjectManagementDialogOptions) { constructor(objectManagementService: IObjectManagementService, options: ObjectManagementDialogOptions) {
super(objectManagementService, options); super(objectManagementService, options, true, false);
} }
protected override postInitializeData(): void { protected override postInitializeData(): void {
@@ -51,10 +52,11 @@ export class ApplicationRoleDialog extends ObjectManagementDialogBase<ObjectMana
return errors; return errors;
} }
protected async initializeUI(): Promise<void> { protected override async initializeUI(): Promise<void> {
await super.initializeUI();
this.initializeGeneralSection(); this.initializeGeneralSection();
this.initializeOwnedSchemasSection(); this.initializeOwnedSchemasSection();
this.formContainer.addItems([this.generalSection, this.ownedSchemasSection]); this.formContainer.addItems([this.generalSection, this.ownedSchemasSection, this.securableSection], this.getSectionItemLayout());
} }
private initializeGeneralSection(): void { private initializeGeneralSection(): void {
@@ -84,7 +86,7 @@ export class ApplicationRoleDialog extends ObjectManagementDialogBase<ObjectMana
[localizedConstants.SchemaText], [localizedConstants.SchemaText],
this.viewInfo.schemas, this.viewInfo.schemas,
this.objectInfo.ownedSchemas, this.objectInfo.ownedSchemas,
DefaultMaxTableHeight, DefaultMaxTableRowCount,
(item) => { (item) => {
// It is not allowed to have unassigned schema. // It is not allowed to have unassigned schema.
return this.objectInfo.ownedSchemas.indexOf(item) === -1; return this.objectInfo.ownedSchemas.indexOf(item) === -1;

View File

@@ -3,14 +3,15 @@
* Licensed under the Source EULA. See License.txt in the project root for license information. * Licensed under the Source EULA. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/ *--------------------------------------------------------------------------------------------*/
import * as azdata from 'azdata'; import * as azdata from 'azdata';
import { ObjectManagementDialogBase, ObjectManagementDialogOptions } from './objectManagementDialogBase'; import { ObjectManagementDialogOptions } from './objectManagementDialogBase';
import { IObjectManagementService, ObjectManagement } from 'mssql'; import { IObjectManagementService, ObjectManagement } from 'mssql';
import * as localizedConstants from '../localizedConstants'; import * as localizedConstants from '../localizedConstants';
import { AlterDatabaseRoleDocUrl, CreateDatabaseRoleDocUrl } from '../constants'; import { AlterDatabaseRoleDocUrl, CreateDatabaseRoleDocUrl } from '../constants';
import { FindObjectDialog } from './findObjectDialog'; import { FindObjectDialog } from './findObjectDialog';
import { DefaultMaxTableHeight } from '../../ui/dialogBase'; import { DefaultMaxTableRowCount } from '../../ui/dialogBase';
import { PrincipalDialogBase } from './principalDialogBase';
export class DatabaseRoleDialog extends ObjectManagementDialogBase<ObjectManagement.DatabaseRoleInfo, ObjectManagement.DatabaseRoleViewInfo> { export class DatabaseRoleDialog extends PrincipalDialogBase<ObjectManagement.DatabaseRoleInfo, ObjectManagement.DatabaseRoleViewInfo> {
// Sections // Sections
private generalSection: azdata.GroupContainer; private generalSection: azdata.GroupContainer;
private ownedSchemasSection: azdata.GroupContainer; private ownedSchemasSection: azdata.GroupContainer;
@@ -27,18 +28,19 @@ export class DatabaseRoleDialog extends ObjectManagementDialogBase<ObjectManagem
private memberTable: azdata.TableComponent; private memberTable: azdata.TableComponent;
constructor(objectManagementService: IObjectManagementService, options: ObjectManagementDialogOptions) { constructor(objectManagementService: IObjectManagementService, options: ObjectManagementDialogOptions) {
super(objectManagementService, options); super(objectManagementService, options, true, false);
} }
protected override get helpUrl(): string { protected override get helpUrl(): string {
return this.options.isNewObject ? CreateDatabaseRoleDocUrl : AlterDatabaseRoleDocUrl; return this.options.isNewObject ? CreateDatabaseRoleDocUrl : AlterDatabaseRoleDocUrl;
} }
protected async initializeUI(): Promise<void> { protected override async initializeUI(): Promise<void> {
await super.initializeUI();
this.initializeGeneralSection(); this.initializeGeneralSection();
this.initializeOwnedSchemasSection(); this.initializeOwnedSchemasSection();
this.initializeMemberSection(); this.initializeMemberSection();
this.formContainer.addItems([this.generalSection, this.ownedSchemasSection, this.memberSection]); this.formContainer.addItems([this.generalSection, this.ownedSchemasSection, this.memberSection, this.securableSection], this.getSectionItemLayout());
} }
private initializeGeneralSection(): void { private initializeGeneralSection(): void {
@@ -53,9 +55,11 @@ export class DatabaseRoleDialog extends ObjectManagementDialogBase<ObjectManagem
const browseOwnerButton = this.createButton(localizedConstants.BrowseText, localizedConstants.BrowseOwnerButtonAriaLabel, async () => { const browseOwnerButton = this.createButton(localizedConstants.BrowseText, localizedConstants.BrowseOwnerButtonAriaLabel, async () => {
const dialog = new FindObjectDialog(this.objectManagementService, { const dialog = new FindObjectDialog(this.objectManagementService, {
objectTypes: [ObjectManagement.NodeType.ApplicationRole, ObjectManagement.NodeType.DatabaseRole, ObjectManagement.NodeType.User], objectTypes: [ObjectManagement.NodeType.ApplicationRole, ObjectManagement.NodeType.DatabaseRole, ObjectManagement.NodeType.User],
selectAllObjectTypes: true,
multiSelect: false, multiSelect: false,
contextId: this.contextId, contextId: this.contextId,
title: localizedConstants.SelectDatabaseRoleOwnerDialogTitle title: localizedConstants.SelectDatabaseRoleOwnerDialogTitle,
showSchemaColumn: false
}); });
await dialog.open(); await dialog.open();
const result = await dialog.waitForClose(); const result = await dialog.waitForClose();
@@ -70,48 +74,45 @@ export class DatabaseRoleDialog extends ObjectManagementDialogBase<ObjectManagem
} }
private initializeMemberSection(): void { private initializeMemberSection(): void {
this.memberTable = this.createTable(localizedConstants.MemberSectionHeader, [ this.memberTable = this.createTable(localizedConstants.MemberSectionHeader, [localizedConstants.NameText], this.objectInfo.members.map(m => [m]));
{
type: azdata.ColumnType.text,
value: localizedConstants.NameText
}
], this.objectInfo.members.map(m => [m]));
const buttonContainer = this.addButtonsForTable(this.memberTable, localizedConstants.AddMemberAriaLabel, localizedConstants.RemoveMemberAriaLabel, const buttonContainer = this.addButtonsForTable(this.memberTable, localizedConstants.AddMemberAriaLabel, localizedConstants.RemoveMemberAriaLabel,
async () => { async () => {
const dialog = new FindObjectDialog(this.objectManagementService, { const dialog = new FindObjectDialog(this.objectManagementService, {
objectTypes: [ObjectManagement.NodeType.DatabaseRole, ObjectManagement.NodeType.User], objectTypes: [ObjectManagement.NodeType.DatabaseRole, ObjectManagement.NodeType.User],
selectAllObjectTypes: true,
multiSelect: true, multiSelect: true,
contextId: this.contextId, contextId: this.contextId,
title: localizedConstants.SelectDatabaseRoleMemberDialogTitle title: localizedConstants.SelectDatabaseRoleMemberDialogTitle,
showSchemaColumn: false
}); });
await dialog.open(); await dialog.open();
const result = await dialog.waitForClose(); const result = await dialog.waitForClose();
this.addMembers(result.selectedObjects.map(r => r.name)); await this.addMembers(result.selectedObjects.map(r => r.name));
}, },
async () => { async () => {
if (this.memberTable.selectedRows.length === 1) { if (this.memberTable.selectedRows.length === 1) {
this.removeMember(this.memberTable.selectedRows[0]); await this.removeMember(this.memberTable.selectedRows[0]);
} }
}); });
this.memberSection = this.createGroup(localizedConstants.MemberSectionHeader, [this.memberTable, buttonContainer]); this.memberSection = this.createGroup(localizedConstants.MemberSectionHeader, [this.memberTable, buttonContainer]);
} }
private addMembers(names: string[]): void { private async addMembers(names: string[]): Promise<void> {
names.forEach(n => { names.forEach(n => {
if (this.objectInfo.members.indexOf(n) === -1) { if (this.objectInfo.members.indexOf(n) === -1) {
this.objectInfo.members.push(n); this.objectInfo.members.push(n);
} }
}); });
this.updateMembersTable(); await this.updateMembersTable();
} }
private removeMember(idx: number): void { private async removeMember(idx: number): Promise<void> {
this.objectInfo.members.splice(idx, 1); this.objectInfo.members.splice(idx, 1);
this.updateMembersTable(); await this.updateMembersTable();
} }
private updateMembersTable(): void { private async updateMembersTable(): Promise<void> {
this.setTableData(this.memberTable, this.objectInfo.members.map(m => [m])); await this.setTableData(this.memberTable, this.objectInfo.members.map(m => [m]));
this.onFormFieldChange(); this.onFormFieldChange();
} }
@@ -120,7 +121,7 @@ export class DatabaseRoleDialog extends ObjectManagementDialogBase<ObjectManagem
[localizedConstants.SchemaText], [localizedConstants.SchemaText],
this.viewInfo.schemas, this.viewInfo.schemas,
this.objectInfo.ownedSchemas, this.objectInfo.ownedSchemas,
DefaultMaxTableHeight, DefaultMaxTableRowCount,
(item) => { (item) => {
// It is not allowed to have unassigned schema. // It is not allowed to have unassigned schema.
return this.objectInfo.ownedSchemas.indexOf(item) === -1; return this.objectInfo.ownedSchemas.indexOf(item) === -1;

View File

@@ -5,15 +5,19 @@
import * as azdata from 'azdata'; import * as azdata from 'azdata';
import * as mssql from 'mssql'; import * as mssql from 'mssql';
import { DefaultTableListItemEnabledStateGetter, DefaultMaxTableHeight, DialogBase, TableListItemComparer, TableListItemValueGetter } from '../../ui/dialogBase'; import { DefaultTableListItemEnabledStateGetter, DefaultMaxTableRowCount, DialogBase, TableListItemComparer } from '../../ui/dialogBase';
import * as localizedConstants from '../localizedConstants'; import * as localizedConstants from '../localizedConstants';
import { getErrorMessage } from '../../utils'; import { getErrorMessage } from '../../utils';
type ObjectType = string | { name: string, displayName: string };
export interface FindObjectDialogOptions { export interface FindObjectDialogOptions {
objectTypes: mssql.ObjectManagement.NodeType[]; objectTypes: ObjectType[];
selectAllObjectTypes: boolean;
multiSelect: boolean; multiSelect: boolean;
contextId: string; contextId: string;
title: string; title: string;
showSchemaColumn?: boolean;
} }
export interface FindObjectDialogResult { export interface FindObjectDialogResult {
@@ -22,15 +26,10 @@ export interface FindObjectDialogResult {
const ObjectComparer: TableListItemComparer<mssql.ObjectManagement.SearchResultItem> = const ObjectComparer: TableListItemComparer<mssql.ObjectManagement.SearchResultItem> =
(item1, item2) => { (item1, item2) => {
return item1.name === item2.name && item1.type === item2.type; return item1.name === item2.name && item1.type === item2.type && item1.schema === item2.schema;
}; };
const ObjectRowValueGetter: TableListItemValueGetter<mssql.ObjectManagement.SearchResultItem> = const ObjectsTableMaxRowCount = 20;
(item) => {
return [item.name, localizedConstants.getNodeTypeDisplayName(item.type, true)];
};
const ObjectsTableMaxHeight = 700;
export class FindObjectDialog extends DialogBase<FindObjectDialogResult> { export class FindObjectDialog extends DialogBase<FindObjectDialogResult> {
private objectTypesTable: azdata.TableComponent; private objectTypesTable: azdata.TableComponent;
@@ -38,7 +37,7 @@ export class FindObjectDialog extends DialogBase<FindObjectDialogResult> {
private objectsTable: azdata.TableComponent; private objectsTable: azdata.TableComponent;
private objectsLoadingComponent: azdata.LoadingComponent; private objectsLoadingComponent: azdata.LoadingComponent;
private result: FindObjectDialogResult; private result: FindObjectDialogResult;
private selectedObjectTypes: string[] = []; private selectedObjectTypes: ObjectType[] = [];
private allObjects: mssql.ObjectManagement.SearchResultItem[] = []; private allObjects: mssql.ObjectManagement.SearchResultItem[] = [];
constructor(private readonly objectManagementService: mssql.IObjectManagementService, private readonly options: FindObjectDialogOptions) { constructor(private readonly objectManagementService: mssql.IObjectManagementService, private readonly options: FindObjectDialogOptions) {
@@ -47,40 +46,52 @@ export class FindObjectDialog extends DialogBase<FindObjectDialogResult> {
this.result = { this.result = {
selectedObjects: [] selectedObjects: []
}; };
this.selectedObjectTypes = [...options.objectTypes]; this.selectedObjectTypes = options.selectAllObjectTypes ? [...options.objectTypes] : [];
}
private getObjectTypeName(objectType: ObjectType): string {
return typeof objectType === 'string' ? objectType : objectType.name;
}
private getObjectTypeDisplayName(objectType: ObjectType): string {
return typeof objectType === 'string' ? localizedConstants.getNodeTypeDisplayName(objectType, true) : objectType.displayName;
} }
protected override async initialize(): Promise<void> { protected override async initialize(): Promise<void> {
this.dialogObject.okButton.enabled = false; this.dialogObject.okButton.enabled = false;
this.objectTypesTable = this.createTableList<string>(localizedConstants.ObjectTypeText, this.objectTypesTable = this.createTableList<ObjectType>(localizedConstants.ObjectTypeText,
[localizedConstants.ObjectTypeText], [localizedConstants.ObjectTypeText],
this.options.objectTypes, this.options.objectTypes,
this.selectedObjectTypes, this.selectedObjectTypes,
DefaultMaxTableHeight, DefaultMaxTableRowCount,
DefaultTableListItemEnabledStateGetter, (item) => { DefaultTableListItemEnabledStateGetter, (item) => {
return [localizedConstants.getNodeTypeDisplayName(item, true)]; return [this.getObjectTypeDisplayName(item)];
}, (item1, item2) => {
return this.getObjectTypeName(item1) === this.getObjectTypeName(item2);
}); });
this.findButton = this.createButton(localizedConstants.FindText, localizedConstants.FindText, async () => { this.findButton = this.createButton(localizedConstants.FindText, localizedConstants.FindText, async () => {
await this.onFindObjectButtonClick(); await this.onFindObjectButtonClick();
}); }, this.options.selectAllObjectTypes);
const buttonContainer = this.createButtonContainer([this.findButton]); const buttonContainer = this.createButtonContainer([this.findButton]);
const objectTypeSection = this.createGroup(localizedConstants.ObjectTypeText, [this.objectTypesTable, buttonContainer]); const objectTypeSection = this.createGroup(localizedConstants.ObjectTypeText, [this.objectTypesTable, buttonContainer]);
const columns = [localizedConstants.NameText, localizedConstants.ObjectTypeText];
if (this.options.showSchemaColumn) {
columns.splice(1, 0, localizedConstants.SchemaText);
}
if (this.options.multiSelect) { if (this.options.multiSelect) {
this.objectsTable = this.createTableList<mssql.ObjectManagement.SearchResultItem>(localizedConstants.ObjectsText, this.objectsTable = this.createTableList<mssql.ObjectManagement.SearchResultItem>(localizedConstants.ObjectsText,
[localizedConstants.NameText, localizedConstants.ObjectTypeText], columns,
this.allObjects, this.allObjects,
this.result.selectedObjects, this.result.selectedObjects,
ObjectsTableMaxHeight, ObjectsTableMaxRowCount,
DefaultTableListItemEnabledStateGetter, DefaultTableListItemEnabledStateGetter,
ObjectRowValueGetter, (item) => {
return this.getObjectRowValue(item);
},
ObjectComparer); ObjectComparer);
} else { } else {
this.objectsTable = this.createTable(localizedConstants.ObjectsText, [{ this.objectsTable = this.createTable(localizedConstants.ObjectsText, columns, [], ObjectsTableMaxRowCount);
value: localizedConstants.NameText,
}, {
value: localizedConstants.ObjectTypeText
}], []);
this.disposables.push(this.objectsTable.onRowSelected(async () => { this.disposables.push(this.objectsTable.onRowSelected(async () => {
if (this.objectsTable.selectedRows.length > 0) { if (this.objectsTable.selectedRows.length > 0) {
this.result.selectedObjects = [this.allObjects[this.objectsTable.selectedRows[0]]]; this.result.selectedObjects = [this.allObjects[this.objectsTable.selectedRows[0]]];
@@ -95,7 +106,7 @@ export class FindObjectDialog extends DialogBase<FindObjectDialogResult> {
}).component(); }).component();
const objectsSection = this.createGroup(localizedConstants.ObjectsText, [this.objectsLoadingComponent]); const objectsSection = this.createGroup(localizedConstants.ObjectsText, [this.objectsLoadingComponent]);
this.formContainer.addItems([objectTypeSection, objectsSection]); this.formContainer.addItems([objectTypeSection, objectsSection], this.getSectionItemLayout());
} }
protected override get dialogResult(): FindObjectDialogResult | undefined { protected override get dialogResult(): FindObjectDialogResult | undefined {
@@ -107,16 +118,18 @@ export class FindObjectDialog extends DialogBase<FindObjectDialogResult> {
this.objectsLoadingComponent.loading = true; this.objectsLoadingComponent.loading = true;
this.findButton.enabled = false; this.findButton.enabled = false;
try { try {
const results = await this.objectManagementService.search(this.options.contextId, <mssql.ObjectManagement.NodeType[]>this.selectedObjectTypes); const results = await this.objectManagementService.search(this.options.contextId, this.selectedObjectTypes.map(item => this.getObjectTypeName(item)));
this.allObjects.splice(0, this.allObjects.length, ...results); this.allObjects.splice(0, this.allObjects.length, ...results);
let data; let data;
if (this.options.multiSelect) { if (this.options.multiSelect) {
data = this.getDataForTableList(this.allObjects, this.result.selectedObjects, DefaultTableListItemEnabledStateGetter, ObjectRowValueGetter, ObjectComparer); data = this.getDataForTableList(this.allObjects, this.result.selectedObjects, DefaultTableListItemEnabledStateGetter, (item) => {
return this.getObjectRowValue(item);
}, ObjectComparer);
} }
else { else {
data = this.allObjects.map(item => ObjectRowValueGetter(item)); data = this.allObjects.map(item => { return this.getObjectRowValue(item); });
} }
this.setTableData(this.objectsTable, data, ObjectsTableMaxHeight); await this.setTableData(this.objectsTable, data, ObjectsTableMaxRowCount);
this.objectsLoadingComponent.loadingCompletedText = localizedConstants.LoadingObjectsCompletedText(results.length); this.objectsLoadingComponent.loadingCompletedText = localizedConstants.LoadingObjectsCompletedText(results.length);
} catch (err) { } catch (err) {
this.dialogObject.message = { this.dialogObject.message = {
@@ -132,4 +145,12 @@ export class FindObjectDialog extends DialogBase<FindObjectDialogResult> {
this.findButton.enabled = this.selectedObjectTypes.length > 0; this.findButton.enabled = this.selectedObjectTypes.length > 0;
this.dialogObject.okButton.enabled = this.result.selectedObjects.length > 0; this.dialogObject.okButton.enabled = this.result.selectedObjects.length > 0;
} }
private getObjectRowValue(item: mssql.ObjectManagement.SearchResultItem): string[] {
const row = [item.name, this.getObjectTypeName(item.type)];
if (this.options.showSchemaColumn) {
row.splice(1, 0, item.schema);
}
return row;
}
} }

View File

@@ -4,15 +4,16 @@
*--------------------------------------------------------------------------------------------*/ *--------------------------------------------------------------------------------------------*/
import * as azdata from 'azdata'; import * as azdata from 'azdata';
import * as vscode from 'vscode'; import * as vscode from 'vscode';
import { ObjectManagementDialogBase, ObjectManagementDialogOptions } from './objectManagementDialogBase'; import { ObjectManagementDialogOptions } from './objectManagementDialogBase';
import { IObjectManagementService, ObjectManagement } from 'mssql'; import { IObjectManagementService, ObjectManagement } from 'mssql';
import * as objectManagementLoc from '../localizedConstants'; import * as objectManagementLoc from '../localizedConstants';
import * as uiLoc from '../../ui/localizedConstants'; import * as uiLoc from '../../ui/localizedConstants';
import { AlterLoginDocUrl, CreateLoginDocUrl, PublicServerRoleName } from '../constants'; import { AlterLoginDocUrl, CreateLoginDocUrl, PublicServerRoleName } from '../constants';
import { isValidSQLPassword } from '../utils'; import { isValidSQLPassword } from '../utils';
import { DefaultMaxTableHeight } from '../../ui/dialogBase'; import { DefaultMaxTableRowCount } from '../../ui/dialogBase';
import { PrincipalDialogBase } from './principalDialogBase';
export class LoginDialog extends ObjectManagementDialogBase<ObjectManagement.Login, ObjectManagement.LoginViewInfo> { export class LoginDialog extends PrincipalDialogBase<ObjectManagement.Login, ObjectManagement.LoginViewInfo> {
private generalSection: azdata.GroupContainer; private generalSection: azdata.GroupContainer;
private sqlAuthSection: azdata.GroupContainer; private sqlAuthSection: azdata.GroupContainer;
private serverRoleSection: azdata.GroupContainer; private serverRoleSection: azdata.GroupContainer;
@@ -34,7 +35,7 @@ export class LoginDialog extends ObjectManagementDialogBase<ObjectManagement.Log
private lockedOutCheckbox: azdata.CheckBoxComponent; private lockedOutCheckbox: azdata.CheckBoxComponent;
constructor(objectManagementService: IObjectManagementService, options: ObjectManagementDialogOptions) { constructor(objectManagementService: IObjectManagementService, options: ObjectManagementDialogOptions) {
super(objectManagementService, options); super(objectManagementService, options, false);
} }
protected override get helpUrl(): string { protected override get helpUrl(): string {
@@ -82,7 +83,8 @@ export class LoginDialog extends ObjectManagementDialogBase<ObjectManagement.Log
this.objectInfo.password = this.objectInfo.password ?? ''; this.objectInfo.password = this.objectInfo.password ?? '';
} }
protected async initializeUI(): Promise<void> { protected override async initializeUI(): Promise<void> {
await super.initializeUI();
const sections: azdata.Component[] = []; const sections: azdata.Component[] = [];
this.initializeGeneralSection(); this.initializeGeneralSection();
sections.push(this.generalSection); sections.push(this.generalSection);
@@ -94,12 +96,13 @@ export class LoginDialog extends ObjectManagementDialogBase<ObjectManagement.Log
this.initializeServerRolesSection(); this.initializeServerRolesSection();
sections.push(this.serverRoleSection); sections.push(this.serverRoleSection);
sections.push(this.securableSection);
if (this.viewInfo.supportAdvancedOptions) { if (this.viewInfo.supportAdvancedOptions) {
this.initializeAdvancedSection(); this.initializeAdvancedSection();
sections.push(this.advancedSection); sections.push(this.advancedSection);
} }
this.formContainer.addItems(sections); this.formContainer.addItems(sections, this.getSectionItemLayout());
} }
private initializeGeneralSection(): void { private initializeGeneralSection(): void {
@@ -203,7 +206,7 @@ export class LoginDialog extends ObjectManagementDialogBase<ObjectManagement.Log
items.push(defaultDatabaseContainer, defaultLanguageContainer, this.connectPermissionCheckbox); items.push(defaultDatabaseContainer, defaultLanguageContainer, this.connectPermissionCheckbox);
} }
this.advancedSection = this.createGroup(objectManagementLoc.AdvancedSectionHeader, items); this.advancedSection = this.createGroup(objectManagementLoc.AdvancedSectionHeader, items, true, true);
} }
private initializeServerRolesSection(): void { private initializeServerRolesSection(): void {
@@ -211,7 +214,7 @@ export class LoginDialog extends ObjectManagementDialogBase<ObjectManagement.Log
[objectManagementLoc.ServerRoleTypeDisplayNameInTitle], [objectManagementLoc.ServerRoleTypeDisplayNameInTitle],
this.viewInfo.serverRoles, this.viewInfo.serverRoles,
this.objectInfo.serverRoles, this.objectInfo.serverRoles,
DefaultMaxTableHeight, DefaultMaxTableRowCount,
(item) => { (item) => {
return item !== PublicServerRoleName return item !== PublicServerRoleName
}); });
@@ -220,7 +223,7 @@ export class LoginDialog extends ObjectManagementDialogBase<ObjectManagement.Log
private setViewByAuthenticationType(): void { private setViewByAuthenticationType(): void {
if (this.authTypeDropdown.value === objectManagementLoc.SQLAuthenticationTypeDisplayText) { if (this.authTypeDropdown.value === objectManagementLoc.SQLAuthenticationTypeDisplayText) {
this.addItem(this.formContainer, this.sqlAuthSection, 1); this.addItem(this.formContainer, this.sqlAuthSection, this.getSectionItemLayout(), 1);
} else if (this.authTypeDropdown.value !== objectManagementLoc.SQLAuthenticationTypeDisplayText) { } else if (this.authTypeDropdown.value !== objectManagementLoc.SQLAuthenticationTypeDisplayText) {
this.removeItem(this.formContainer, this.sqlAuthSection); this.removeItem(this.formContainer, this.sqlAuthSection);
} }

View File

@@ -0,0 +1,228 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the Source EULA. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import * as azdata from 'azdata';
import * as mssql from 'mssql';
import * as localizedConstants from '../localizedConstants';
import { ObjectManagementDialogBase, ObjectManagementDialogOptions } from './objectManagementDialogBase';
import { FindObjectDialog } from './findObjectDialog';
import { deepClone } from '../../util/objects';
import { DefaultTableWidth, getTableHeight } from '../../ui/dialogBase';
const GrantColumnIndex = 2;
const WithGrantColumnIndex = 3;
const DenyColumnIndex = 4;
/**
* Base class for security principal dialogs such as user, role, etc.
*/
export abstract class PrincipalDialogBase<ObjectInfoType extends mssql.ObjectManagement.SecurityPrincipalObject, ViewInfoType extends mssql.ObjectManagement.SecurityPrincipalViewInfo<ObjectInfoType>> extends ObjectManagementDialogBase<ObjectInfoType, ViewInfoType> {
protected securableTable: azdata.TableComponent;
protected permissionTable: azdata.TableComponent;
protected effectivePermissionTable: azdata.TableComponent;
protected securableSection: azdata.GroupContainer;
protected explicitPermissionTableLabel: azdata.TextComponent;
protected effectivePermissionTableLabel: azdata.TextComponent;
private securablePermissions: mssql.ObjectManagement.SecurablePermissions[] = [];
constructor(objectManagementService: mssql.IObjectManagementService, options: ObjectManagementDialogOptions, private readonly showSchemaColumn: boolean, private readonly supportEffectivePermissions: boolean = true) {
super(objectManagementService, options);
}
protected override async initializeUI(): Promise<void> {
this.securablePermissions = deepClone(this.objectInfo.securablePermissions);
this.initializeSecurableSection();
}
private initializeSecurableSection(): void {
const items: azdata.Component[] = [];
const securableTableColumns = [localizedConstants.NameText, localizedConstants.ObjectTypeText];
if (this.showSchemaColumn) {
securableTableColumns.splice(1, 0, localizedConstants.SchemaText);
}
this.securableTable = this.createTable(localizedConstants.SecurablesText, securableTableColumns, this.getSecurableTableData());
const buttonContainer = this.addButtonsForTable(this.securableTable, localizedConstants.AddSecurableAriaLabel, localizedConstants.RemoveSecurableAriaLabel,
() => this.onAddSecurableButtonClicked(), () => this.onRemoveSecurableButtonClicked());
this.disposables.push(this.securableTable.onRowSelected(async () => {
await this.updatePermissionsTable();
}));
this.explicitPermissionTableLabel = this.modelView.modelBuilder.text().withProps({ value: localizedConstants.ExplicitPermissionsTableLabel }).component();
this.permissionTable = this.modelView.modelBuilder.table().withProps({
ariaLabel: localizedConstants.ExplicitPermissionsTableLabel,
columns:
[{
type: azdata.ColumnType.text,
value: localizedConstants.PermissionColumnHeader
}, {
type: azdata.ColumnType.text,
value: localizedConstants.GrantorColumnHeader
}, {
type: azdata.ColumnType.checkBox,
value: localizedConstants.GrantColumnHeader
}, {
type: azdata.ColumnType.checkBox,
value: localizedConstants.WithGrantColumnHeader
}, {
type: azdata.ColumnType.checkBox,
value: localizedConstants.DenyColumnHeader
}],
data: [],
height: getTableHeight(0),
width: DefaultTableWidth
}).component();
this.disposables.push(this.permissionTable.onCellAction(async (arg: azdata.ICheckboxCellActionEventArgs) => {
const permissionName = this.permissionTable.data[arg.row][0];
const securable = this.securablePermissions[this.securableTable.selectedRows[0]];
let permission: mssql.ObjectManagement.SecurablePermissionItem = securable.permissions.find(securablePermission => securablePermission.permission === permissionName);
if (!permission) {
permission = {
permission: permissionName,
grantor: ''
};
securable.permissions.push(permission);
}
if (arg.column === GrantColumnIndex) {
permission.grant = arg.checked ? true : undefined;
if (!arg.checked) {
permission.withGrant = undefined;
}
} else if (arg.column === WithGrantColumnIndex) {
permission.withGrant = arg.checked ? true : undefined;
if (arg.checked) {
permission.grant = true;
}
} else if (arg.column === DenyColumnIndex) {
permission.grant = arg.checked ? false : undefined;
if (arg.checked) {
permission.withGrant = undefined;
}
}
await this.updatePermissionsTable();
this.updateSecurablePermissions();
// Restore the focus to previously selected cell.
this.permissionTable.setActiveCell(arg.row, arg.column);
}));
items.push(this.securableTable, buttonContainer, this.explicitPermissionTableLabel, this.permissionTable);
if (this.showEffectivePermissions) {
this.effectivePermissionTableLabel = this.modelView.modelBuilder.text().withProps({ value: localizedConstants.EffectivePermissionsTableLabel }).component();
this.effectivePermissionTable = this.createTable(localizedConstants.EffectivePermissionsTableLabel, [localizedConstants.PermissionColumnHeader], []);
items.push(this.effectivePermissionTableLabel, this.effectivePermissionTable);
}
this.securableSection = this.createGroup(localizedConstants.SecurablesText, items, true, true);
}
private async onAddSecurableButtonClicked(): Promise<void> {
const dialog = new FindObjectDialog(this.objectManagementService, {
objectTypes: this.viewInfo.supportedSecurableTypes,
selectAllObjectTypes: false,
multiSelect: true,
contextId: this.contextId,
title: localizedConstants.SelectSecurablesDialogTitle,
showSchemaColumn: this.showSchemaColumn
});
await dialog.open();
const result = await dialog.waitForClose();
if (result && result.selectedObjects.length > 0) {
result.selectedObjects.forEach(obj => {
if (this.securablePermissions.find(securable => securable.type === obj.type && securable.name === obj.name && securable.schema === obj.schema)) {
return;
}
const securableTypeMetadata = this.viewInfo.supportedSecurableTypes.find(securableType => securableType.name === obj.type);
this.securablePermissions.push({
name: obj.name,
schema: obj.schema,
type: obj.type,
permissions: securableTypeMetadata.permissions.map(permission => {
return {
permission: permission.name,
grantor: '',
grant: undefined,
withGrant: undefined
};
}),
effectivePermissions: []
});
});
const data = this.getSecurableTableData();
await this.setTableData(this.securableTable, data);
}
}
private async onRemoveSecurableButtonClicked(): Promise<void> {
if (this.securableTable.selectedRows.length === 1) {
this.securablePermissions.splice(this.securableTable.selectedRows[0], 1);
const data = this.getSecurableTableData();
await this.setTableData(this.securableTable, data);
this.updateSecurablePermissions();
}
}
private getSecurableTableData(): string[][] {
return this.securablePermissions.map(securable => {
const row = [securable.name, this.getSecurableTypeDisplayName(securable.type)];
if (this.showSchemaColumn) {
row.splice(1, 0, securable.schema);
}
return row;
});
}
private async updatePermissionsTable(): Promise<void> {
let permissionsTableData: any[][] = [];
let effectivePermissionsTableData: any[][] = [];
let explicitPermissionsLabel = localizedConstants.ExplicitPermissionsTableLabel;
let effectivePermissionsLabel = localizedConstants.EffectivePermissionsTableLabel;
if (this.securableTable.selectedRows.length === 1) {
const securable = this.securablePermissions[this.securableTable.selectedRows[0]];
if (securable) {
const securableDisplayName = securable.schema ? `${securable.schema}.${securable.name}` : securable.name;
explicitPermissionsLabel = localizedConstants.ExplicitPermissionsTableLabelSelected(securableDisplayName);
effectivePermissionsLabel = localizedConstants.EffectivePermissionsTableLabelSelected(securableDisplayName);
const securableTypeMetadata = this.viewInfo.supportedSecurableTypes.find(securableType => securableType.name === securable.type);
permissionsTableData = securable.permissions.map(permission => {
return [permission.permission, permission.grantor, { checked: permission.grant === true }, { checked: permission.withGrant === true }, { checked: permission.grant === false }];
});
permissionsTableData = securableTypeMetadata.permissions.map(permissionMetadata => {
const permission = securable.permissions.find(securablePermission => securablePermission.permission === permissionMetadata.name);
return [
permissionMetadata.name,
permission?.grantor ?? '',
{ checked: permission?.grant === true },
{ checked: permission?.withGrant === true },
{ checked: permission?.grant === false }];
});
effectivePermissionsTableData = securable.effectivePermissions.map(permission => [permission]);
}
}
this.explicitPermissionTableLabel.value = explicitPermissionsLabel;
await this.setTableData(this.permissionTable, permissionsTableData);
if (this.showEffectivePermissions) {
this.effectivePermissionTableLabel.value = effectivePermissionsLabel;
await this.setTableData(this.effectivePermissionTable, effectivePermissionsTableData);
}
}
private updateSecurablePermissions(): void {
// Only save securable permissions that have grant or deny value.
this.objectInfo.securablePermissions = deepClone(this.securablePermissions.filter((securablePermissions) => {
return securablePermissions.permissions.some(permission => permission.grant !== undefined);
}));
this.objectInfo.securablePermissions.forEach(securablePermissions => {
securablePermissions.permissions = securablePermissions.permissions.filter(permission => permission.grant !== undefined);
});
this.onFormFieldChange();
}
private getSecurableTypeDisplayName(securableType: string): string {
const securableTypeMetadata = this.viewInfo.supportedSecurableTypes.find(securableTypeMetadata => securableTypeMetadata.name === securableType);
return securableTypeMetadata ? securableTypeMetadata.displayName : securableType;
}
private get showEffectivePermissions(): boolean {
return !this.options.isNewObject && this.supportEffectivePermissions;
}
}

View File

@@ -3,13 +3,14 @@
* Licensed under the Source EULA. See License.txt in the project root for license information. * Licensed under the Source EULA. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/ *--------------------------------------------------------------------------------------------*/
import * as azdata from 'azdata'; import * as azdata from 'azdata';
import { ObjectManagementDialogBase, ObjectManagementDialogOptions } from './objectManagementDialogBase'; import { ObjectManagementDialogOptions } from './objectManagementDialogBase';
import { IObjectManagementService, ObjectManagement } from 'mssql'; import { IObjectManagementService, ObjectManagement } from 'mssql';
import * as localizedConstants from '../localizedConstants'; import * as localizedConstants from '../localizedConstants';
import { AlterServerRoleDocUrl, CreateServerRoleDocUrl } from '../constants'; import { AlterServerRoleDocUrl, CreateServerRoleDocUrl } from '../constants';
import { FindObjectDialog } from './findObjectDialog'; import { FindObjectDialog } from './findObjectDialog';
import { PrincipalDialogBase } from './principalDialogBase';
export class ServerRoleDialog extends ObjectManagementDialogBase<ObjectManagement.ServerRoleInfo, ObjectManagement.ServerRoleViewInfo> { export class ServerRoleDialog extends PrincipalDialogBase<ObjectManagement.ServerRoleInfo, ObjectManagement.ServerRoleViewInfo> {
// Sections // Sections
private generalSection: azdata.GroupContainer; private generalSection: azdata.GroupContainer;
private membershipSection: azdata.GroupContainer; private membershipSection: azdata.GroupContainer;
@@ -27,22 +28,24 @@ export class ServerRoleDialog extends ObjectManagementDialogBase<ObjectManagemen
constructor(objectManagementService: IObjectManagementService, options: ObjectManagementDialogOptions) { constructor(objectManagementService: IObjectManagementService, options: ObjectManagementDialogOptions) {
super(objectManagementService, options); super(objectManagementService, options, false, false);
} }
protected override get helpUrl(): string { protected override get helpUrl(): string {
return this.options.isNewObject ? CreateServerRoleDocUrl : AlterServerRoleDocUrl; return this.options.isNewObject ? CreateServerRoleDocUrl : AlterServerRoleDocUrl;
} }
protected async initializeUI(): Promise<void> { protected override async initializeUI(): Promise<void> {
await super.initializeUI();
this.initializeGeneralSection(); this.initializeGeneralSection();
this.initializeMemberSection(); this.initializeMemberSection();
const sections: azdata.Component[] = [this.generalSection, this.memberSection]; const sections: azdata.Component[] = [this.generalSection, this.memberSection];
if (!this.viewInfo.isFixedRole) { if (!this.viewInfo.isFixedRole) {
this.initializeMembershipSection(); this.initializeMembershipSection();
sections.push(this.membershipSection); sections.push(this.membershipSection);
sections.push(this.securableSection);
} }
this.formContainer.addItems(sections); this.formContainer.addItems(sections, this.getSectionItemLayout());
} }
private initializeGeneralSection(): void { private initializeGeneralSection(): void {
@@ -57,6 +60,7 @@ export class ServerRoleDialog extends ObjectManagementDialogBase<ObjectManagemen
const browseOwnerButton = this.createButton(localizedConstants.BrowseText, localizedConstants.BrowseOwnerButtonAriaLabel, async () => { const browseOwnerButton = this.createButton(localizedConstants.BrowseText, localizedConstants.BrowseOwnerButtonAriaLabel, async () => {
const dialog = new FindObjectDialog(this.objectManagementService, { const dialog = new FindObjectDialog(this.objectManagementService, {
objectTypes: [ObjectManagement.NodeType.ServerLevelLogin, ObjectManagement.NodeType.ServerLevelServerRole], objectTypes: [ObjectManagement.NodeType.ServerLevelLogin, ObjectManagement.NodeType.ServerLevelServerRole],
selectAllObjectTypes: true,
multiSelect: false, multiSelect: false,
contextId: this.contextId, contextId: this.contextId,
title: localizedConstants.SelectServerRoleOwnerDialogTitle title: localizedConstants.SelectServerRoleOwnerDialogTitle
@@ -76,48 +80,44 @@ export class ServerRoleDialog extends ObjectManagementDialogBase<ObjectManagemen
} }
private initializeMemberSection(): void { private initializeMemberSection(): void {
this.memberTable = this.createTable(localizedConstants.MemberSectionHeader, [ this.memberTable = this.createTable(localizedConstants.MemberSectionHeader, [localizedConstants.NameText], this.objectInfo.members.map(m => [m]));
{
type: azdata.ColumnType.text,
value: localizedConstants.NameText
}
], this.objectInfo.members.map(m => [m]));
const buttonContainer = this.addButtonsForTable(this.memberTable, localizedConstants.AddMemberAriaLabel, localizedConstants.RemoveMemberAriaLabel, const buttonContainer = this.addButtonsForTable(this.memberTable, localizedConstants.AddMemberAriaLabel, localizedConstants.RemoveMemberAriaLabel,
async () => { async () => {
const dialog = new FindObjectDialog(this.objectManagementService, { const dialog = new FindObjectDialog(this.objectManagementService, {
objectTypes: [ObjectManagement.NodeType.ServerLevelLogin, ObjectManagement.NodeType.ServerLevelServerRole], objectTypes: [ObjectManagement.NodeType.ServerLevelLogin, ObjectManagement.NodeType.ServerLevelServerRole],
selectAllObjectTypes: true,
multiSelect: true, multiSelect: true,
contextId: this.contextId, contextId: this.contextId,
title: localizedConstants.SelectServerRoleMemberDialogTitle title: localizedConstants.SelectServerRoleMemberDialogTitle
}); });
await dialog.open(); await dialog.open();
const result = await dialog.waitForClose(); const result = await dialog.waitForClose();
this.addMembers(result.selectedObjects.map(r => r.name)); await this.addMembers(result.selectedObjects.map(r => r.name));
}, },
async () => { async () => {
if (this.memberTable.selectedRows.length === 1) { if (this.memberTable.selectedRows.length === 1) {
this.removeMember(this.memberTable.selectedRows[0]); await this.removeMember(this.memberTable.selectedRows[0]);
} }
}); });
this.memberSection = this.createGroup(localizedConstants.MemberSectionHeader, [this.memberTable, buttonContainer]); this.memberSection = this.createGroup(localizedConstants.MemberSectionHeader, [this.memberTable, buttonContainer]);
} }
private addMembers(names: string[]): void { private async addMembers(names: string[]): Promise<void> {
names.forEach(n => { names.forEach(n => {
if (this.objectInfo.members.indexOf(n) === -1) { if (this.objectInfo.members.indexOf(n) === -1) {
this.objectInfo.members.push(n); this.objectInfo.members.push(n);
} }
}); });
this.updateMembersTable(); await this.updateMembersTable();
} }
private removeMember(idx: number): void { private async removeMember(idx: number): Promise<void> {
this.objectInfo.members.splice(idx, 1); this.objectInfo.members.splice(idx, 1);
this.updateMembersTable(); await this.updateMembersTable();
} }
private updateMembersTable(): void { private async updateMembersTable(): Promise<void> {
this.setTableData(this.memberTable, this.objectInfo.members.map(m => [m])); await this.setTableData(this.memberTable, this.objectInfo.members.map(m => [m]));
this.onFormFieldChange(); this.onFormFieldChange();
} }

View File

@@ -3,14 +3,15 @@
* Licensed under the Source EULA. See License.txt in the project root for license information. * Licensed under the Source EULA. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/ *--------------------------------------------------------------------------------------------*/
import * as azdata from 'azdata'; import * as azdata from 'azdata';
import { ObjectManagementDialogBase, ObjectManagementDialogOptions } from './objectManagementDialogBase'; import { ObjectManagementDialogOptions } from './objectManagementDialogBase';
import { IObjectManagementService, ObjectManagement } from 'mssql'; import { IObjectManagementService, ObjectManagement } from 'mssql';
import * as localizedConstants from '../localizedConstants'; import * as localizedConstants from '../localizedConstants';
import { AlterUserDocUrl, CreateUserDocUrl } from '../constants'; import { AlterUserDocUrl, CreateUserDocUrl } from '../constants';
import { isValidSQLPassword } from '../utils'; import { isValidSQLPassword } from '../utils';
import { DefaultMaxTableHeight } from '../../ui/dialogBase'; import { DefaultMaxTableRowCount } from '../../ui/dialogBase';
import { PrincipalDialogBase } from './principalDialogBase';
export class UserDialog extends ObjectManagementDialogBase<ObjectManagement.User, ObjectManagement.UserViewInfo> { export class UserDialog extends PrincipalDialogBase<ObjectManagement.User, ObjectManagement.UserViewInfo> {
private generalSection: azdata.GroupContainer; private generalSection: azdata.GroupContainer;
private ownedSchemaSection: azdata.GroupContainer; private ownedSchemaSection: azdata.GroupContainer;
private membershipSection: azdata.GroupContainer; private membershipSection: azdata.GroupContainer;
@@ -31,7 +32,7 @@ export class UserDialog extends ObjectManagementDialogBase<ObjectManagement.User
private membershipTable: azdata.TableComponent; private membershipTable: azdata.TableComponent;
constructor(objectManagementService: IObjectManagementService, options: ObjectManagementDialogOptions) { constructor(objectManagementService: IObjectManagementService, options: ObjectManagementDialogOptions) {
super(objectManagementService, options); super(objectManagementService, options, true);
} }
protected override get helpUrl(): string { protected override get helpUrl(): string {
@@ -61,12 +62,13 @@ export class UserDialog extends ObjectManagementDialogBase<ObjectManagement.User
return errors; return errors;
} }
protected async initializeUI(): Promise<void> { protected override async initializeUI(): Promise<void> {
await super.initializeUI();
this.initializeGeneralSection(); this.initializeGeneralSection();
this.initializeOwnedSchemaSection(); this.initializeOwnedSchemaSection();
this.initializeMembershipSection(); this.initializeMembershipSection();
this.initializeAdvancedSection(); this.initializeAdvancedSection();
this.formContainer.addItems([this.generalSection, this.ownedSchemaSection, this.membershipSection, this.advancedSection]); this.formContainer.addItems([this.generalSection, this.ownedSchemaSection, this.membershipSection, this.securableSection, this.advancedSection], this.getSectionItemLayout());
setTimeout(() => { setTimeout(() => {
this.setViewByUserType(); this.setViewByUserType();
}, 100); }, 100);
@@ -94,7 +96,7 @@ export class UserDialog extends ObjectManagementDialogBase<ObjectManagement.User
this.loginDropdown = this.createDropdown(localizedConstants.LoginText, async (newValue) => { this.loginDropdown = this.createDropdown(localizedConstants.LoginText, async (newValue) => {
this.objectInfo.loginName = newValue; this.objectInfo.loginName = newValue;
}, this.viewInfo.logins, this.objectInfo.loginName, this.options.isNewObject); }, this.options.isNewObject ? this.viewInfo.logins : [this.objectInfo.loginName], this.objectInfo.loginName, this.options.isNewObject);
this.loginContainer = this.createLabelInputContainer(localizedConstants.LoginText, this.loginDropdown); this.loginContainer = this.createLabelInputContainer(localizedConstants.LoginText, this.loginDropdown);
this.passwordInput = this.createPasswordInputBox(localizedConstants.PasswordText, async (newValue) => { this.passwordInput = this.createPasswordInputBox(localizedConstants.PasswordText, async (newValue) => {
@@ -119,7 +121,7 @@ export class UserDialog extends ObjectManagementDialogBase<ObjectManagement.User
[localizedConstants.SchemaText], [localizedConstants.SchemaText],
this.viewInfo.schemas, this.viewInfo.schemas,
this.objectInfo.ownedSchemas, this.objectInfo.ownedSchemas,
DefaultMaxTableHeight, DefaultMaxTableRowCount,
(item) => { (item) => {
// It is not allowed to have unassigned schema. // It is not allowed to have unassigned schema.
return this.objectInfo.ownedSchemas.indexOf(item) === -1; return this.objectInfo.ownedSchemas.indexOf(item) === -1;
@@ -157,6 +159,11 @@ export class UserDialog extends ObjectManagementDialogBase<ObjectManagement.User
this.addItem(this.generalSection, this.confirmPasswordContainer); this.addItem(this.generalSection, this.confirmPasswordContainer);
this.addItem(this.formContainer, this.advancedSection); this.addItem(this.formContainer, this.advancedSection);
break; break;
case ObjectManagement.UserType.WindowsUser:
if (this.objectInfo.loginName) {
this.addItem(this.generalSection, this.loginContainer);
}
break;
default: default:
break; break;
} }

View File

@@ -11,13 +11,13 @@ import * as uiLoc from '../ui/localizedConstants';
export const DefaultLabelWidth = 150; export const DefaultLabelWidth = 150;
export const DefaultInputWidth = 300; export const DefaultInputWidth = 300;
export const DefaultTableWidth = DefaultInputWidth + DefaultLabelWidth; export const DefaultTableWidth = DefaultInputWidth + DefaultLabelWidth;
export const DefaultMaxTableHeight = 400; export const DefaultMaxTableRowCount = 10;
export const DefaultMinTableRowCount = 1; export const DefaultMinTableRowCount = 1;
export const TableRowHeight = 25; const TableRowHeight = 25;
export const TableColumnHeaderHeight = 30; const TableColumnHeaderHeight = 30;
export function getTableHeight(rowCount: number, minRowCount: number = DefaultMinTableRowCount, maxHeight: number = DefaultMaxTableHeight): number { export function getTableHeight(rowCount: number, minRowCount: number = DefaultMinTableRowCount, maxRowCount: number = DefaultMaxTableRowCount): number {
return Math.min(Math.max(rowCount, minRowCount) * TableRowHeight + TableColumnHeaderHeight, maxHeight); return Math.min(Math.max(rowCount, minRowCount), maxRowCount) * TableRowHeight + TableColumnHeaderHeight;
} }
export type TableListItemEnabledStateGetter<T> = (item: T) => boolean; export type TableListItemEnabledStateGetter<T> = (item: T) => boolean;
@@ -168,7 +168,7 @@ export abstract class DialogBase<DialogResult> {
columnNames: string[], columnNames: string[],
allItems: T[], allItems: T[],
selectedItems: T[], selectedItems: T[],
maxHeight: number = DefaultMaxTableHeight, maxRowCount: number = DefaultMaxTableRowCount,
enabledStateGetter: TableListItemEnabledStateGetter<T> = DefaultTableListItemEnabledStateGetter, enabledStateGetter: TableListItemEnabledStateGetter<T> = DefaultTableListItemEnabledStateGetter,
rowValueGetter: TableListItemValueGetter<T> = DefaultTableListItemValueGetter, rowValueGetter: TableListItemValueGetter<T> = DefaultTableListItemValueGetter,
itemComparer: TableListItemComparer<T> = DefaultTableListItemComparer): azdata.TableComponent { itemComparer: TableListItemComparer<T> = DefaultTableListItemComparer): azdata.TableComponent {
@@ -179,7 +179,7 @@ export abstract class DialogBase<DialogResult> {
data: data, data: data,
columns: [ columns: [
{ {
value: uiLoc.SelectedText, value: uiLoc.SelectText,
type: azdata.ColumnType.checkBox, type: azdata.ColumnType.checkBox,
options: { actionOnCheckbox: azdata.ActionOnCellCheckboxCheck.customAction } options: { actionOnCheckbox: azdata.ActionOnCellCheckboxCheck.customAction }
}, ...columnNames.map(name => { }, ...columnNames.map(name => {
@@ -187,7 +187,7 @@ export abstract class DialogBase<DialogResult> {
}) })
], ],
width: DefaultTableWidth, width: DefaultTableWidth,
height: getTableHeight(data.length, DefaultMinTableRowCount, maxHeight) height: getTableHeight(data.length, DefaultMinTableRowCount, maxRowCount)
} }
).component(); ).component();
this.disposables.push(table.onCellAction!((arg: azdata.ICheckboxCellActionEventArgs) => { this.disposables.push(table.onCellAction!((arg: azdata.ICheckboxCellActionEventArgs) => {
@@ -203,9 +203,11 @@ export abstract class DialogBase<DialogResult> {
return table; return table;
} }
protected setTableData(table: azdata.TableComponent, data: any[][], maxHeight: number = DefaultMaxTableHeight) { protected async setTableData(table: azdata.TableComponent, data: any[][], maxRowCount: number = DefaultMaxTableRowCount) {
table.data = data; await table.updateProperties({
table.height = getTableHeight(data.length, DefaultMinTableRowCount, maxHeight); data: data,
height: getTableHeight(data.length, DefaultMinTableRowCount, maxRowCount)
});
} }
protected getDataForTableList<T>( protected getDataForTableList<T>(
@@ -221,14 +223,14 @@ export abstract class DialogBase<DialogResult> {
}); });
} }
protected createTable(ariaLabel: string, columns: azdata.TableColumn[], data: any[][], maxHeight: number = DefaultMaxTableHeight): azdata.TableComponent { protected createTable(ariaLabel: string, columns: string[], data: any[][], maxRowCount: number = DefaultMaxTableRowCount): azdata.TableComponent {
const table = this.modelView.modelBuilder.table().withProps( const table = this.modelView.modelBuilder.table().withProps(
{ {
ariaLabel: ariaLabel, ariaLabel: ariaLabel,
data: data, data: data,
columns: columns, columns: columns,
width: DefaultTableWidth, width: DefaultTableWidth,
height: getTableHeight(data.length, DefaultMinTableRowCount, maxHeight) height: getTableHeight(data.length, DefaultMinTableRowCount, maxRowCount)
} }
).component(); ).component();
return table; return table;
@@ -238,7 +240,8 @@ export abstract class DialogBase<DialogResult> {
let addButton: azdata.ButtonComponent; let addButton: azdata.ButtonComponent;
let removeButton: azdata.ButtonComponent; let removeButton: azdata.ButtonComponent;
const updateButtons = () => { const updateButtons = () => {
removeButton.enabled = table.selectedRows.length > 0; this.onFormFieldChange();
removeButton.enabled = table.selectedRows?.length === 1 && table.selectedRows[0] !== -1 && table.selectedRows[0] < table.data.length;
} }
addButton = this.createButton(uiLoc.AddText, addButtonAriaLabel, async () => { addButton = this.createButton(uiLoc.AddText, addButtonAriaLabel, async () => {
await addHandler(); await addHandler();
@@ -246,6 +249,9 @@ export abstract class DialogBase<DialogResult> {
}); });
removeButton = this.createButton(uiLoc.RemoveText, removeButtonAriaLabel, async () => { removeButton = this.createButton(uiLoc.RemoveText, removeButtonAriaLabel, async () => {
await removeHandler(); await removeHandler();
if (table.selectedRows.length === 1 && table.selectedRows[0] >= table.data.length) {
table.selectedRows = [table.data.length - 1];
}
updateButtons(); updateButtons();
}, false); }, false);
this.disposables.push(table.onRowSelected(() => { this.disposables.push(table.onRowSelected(() => {
@@ -308,12 +314,12 @@ export abstract class DialogBase<DialogResult> {
} }
} }
protected addItem(container: azdata.DivContainer | azdata.FlexContainer, item: azdata.Component, index?: number): void { protected addItem(container: azdata.DivContainer | azdata.FlexContainer, item: azdata.Component, itemLayout?: azdata.FlexItemLayout, index?: number): void {
if (container.items.indexOf(item) === -1) { if (container.items.indexOf(item) === -1) {
if (index === undefined) { if (index === undefined) {
container.addItem(item); container.addItem(item, itemLayout);
} else { } else {
container.insertItem(item, index); container.insertItem(item, index, itemLayout);
} }
} }
} }
@@ -327,6 +333,10 @@ export abstract class DialogBase<DialogResult> {
private createFormContainer(items: azdata.Component[]): azdata.DivContainer { private createFormContainer(items: azdata.Component[]): azdata.DivContainer {
return this.modelView.modelBuilder.divContainer().withLayout({ width: 'calc(100% - 20px)', height: 'calc(100% - 20px)' }).withProps({ return this.modelView.modelBuilder.divContainer().withLayout({ width: 'calc(100% - 20px)', height: 'calc(100% - 20px)' }).withProps({
CSSStyles: { 'padding': '10px' } CSSStyles: { 'padding': '10px' }
}).withItems(items, { CSSStyles: { 'margin-block-end': '10px' } }).component(); }).withItems(items, this.getSectionItemLayout()).component();
}
protected getSectionItemLayout(): azdata.FlexItemLayout {
return { CSSStyles: { 'margin-block-end': '5px' } };
} }
} }

View File

@@ -11,7 +11,7 @@ export const YesText: string = localize('mssql.ui.yesText', "Yes");
export const OkText: string = localize('mssql.ui.OkText', "OK"); export const OkText: string = localize('mssql.ui.OkText', "OK");
export const LoadingDialogText: string = localize('mssql.ui.loadingDialog', "Loading dialog..."); export const LoadingDialogText: string = localize('mssql.ui.loadingDialog', "Loading dialog...");
export const ScriptText: string = localize('mssql.ui.scriptText', "Script"); export const ScriptText: string = localize('mssql.ui.scriptText', "Script");
export const SelectedText = localize('objectManagement.selectedLabel', "Selected"); export const SelectText = localize('objectManagement.selectLabel', "Select");
export const AddText = localize('objectManagement.addText', "Add…"); export const AddText = localize('objectManagement.addText', "Add…");
export const RemoveText = localize('objectManagement.removeText', "Remove"); export const RemoveText = localize('objectManagement.removeText', "Remove");
export const NoActionScriptedMessage: string = localize('mssql.ui.noActionScriptedMessage', "There is no action to be scripted."); export const NoActionScriptedMessage: string = localize('mssql.ui.noActionScriptedMessage', "There is no action to be scripted.");

View File

@@ -163,11 +163,6 @@
"command": "jupyter.reinstallDependencies", "command": "jupyter.reinstallDependencies",
"title": "%title.reinstallNotebookDependencies%" "title": "%title.reinstallNotebookDependencies%"
}, },
{
"command": "books.sqlserver2019",
"title": "%title.SQL19PreviewBook%",
"category": "%books-preview-category%"
},
{ {
"command": "books.command.openLocalizedBooks", "command": "books.command.openLocalizedBooks",
"title": "%title.PreviewLocalizedBook%", "title": "%title.PreviewLocalizedBook%",
@@ -380,10 +375,6 @@
"command": "jupyter.cmd.managePackages", "command": "jupyter.cmd.managePackages",
"when": "false" "when": "false"
}, },
{
"command": "books.sqlserver2019",
"when": "sqlserver2019"
},
{ {
"command": "notebook.command.saveBook", "command": "notebook.command.saveBook",
"when": "false" "when": "false"
@@ -542,10 +533,6 @@
"when": "view == bookTreeView", "when": "view == bookTreeView",
"group": "navigation" "group": "navigation"
}, },
{
"command": "books.sqlserver2019",
"when": "view == providedBooksView"
},
{ {
"command": "notebook.command.openNotebookFolder", "command": "notebook.command.openNotebookFolder",
"when": "view == bookTreeView", "when": "view == bookTreeView",

View File

@@ -295,7 +295,8 @@ export function createViewContext(): ViewTestContext {
columns: [] as string[], columns: [] as string[],
onRowSelected: onClick.event, onRowSelected: onClick.event,
onCellAction: onClick.event, onCellAction: onClick.event,
appendData: (_data: any[][]) => undefined appendData: (_data: any[][]) => undefined,
setActiveCell: (_row: number, _column: number) => undefined
}); });
let tableBuilder: azdata.ComponentBuilder<azdata.TableComponent, azdata.TableComponentProperties> = { let tableBuilder: azdata.ComponentBuilder<azdata.TableComponent, azdata.TableComponentProperties> = {
component: () => table(), component: () => table(),

View File

@@ -2,7 +2,7 @@
"name": "sql-database-projects", "name": "sql-database-projects",
"displayName": "SQL Database Projects", "displayName": "SQL Database Projects",
"description": "Enables users to develop and publish database schemas for MSSQL Databases", "description": "Enables users to develop and publish database schemas for MSSQL Databases",
"version": "1.1.0", "version": "1.1.1",
"publisher": "Microsoft", "publisher": "Microsoft",
"preview": false, "preview": false,
"engines": { "engines": {

View File

@@ -20,6 +20,7 @@ import { TelemetryActions, TelemetryReporter, TelemetryViews } from '../common/t
import { Deferred } from '../common/promise'; import { Deferred } from '../common/promise';
import { PublishOptionsDialog } from './publishOptionsDialog'; import { PublishOptionsDialog } from './publishOptionsDialog';
import { IPublishToDockerSettings, ISqlProjectPublishSettings } from '../models/deploy/publishSettings'; import { IPublishToDockerSettings, ISqlProjectPublishSettings } from '../models/deploy/publishSettings';
import { PublishProfile } from '../models/publishProfile/publishProfile';
interface DataSourceDropdownValue extends azdataType.CategoryValue { interface DataSourceDropdownValue extends azdataType.CategoryValue {
dataSource: SqlConnectionDataSource; dataSource: SqlConnectionDataSource;
@@ -69,7 +70,7 @@ export class PublishDatabaseDialog {
public publish: ((proj: Project, profile: ISqlProjectPublishSettings) => any) | undefined; public publish: ((proj: Project, profile: ISqlProjectPublishSettings) => any) | undefined;
public publishToContainer: ((proj: Project, profile: IPublishToDockerSettings) => any) | undefined; public publishToContainer: ((proj: Project, profile: IPublishToDockerSettings) => any) | undefined;
public generateScript: ((proj: Project, profile: ISqlProjectPublishSettings) => any) | undefined; public generateScript: ((proj: Project, profile: ISqlProjectPublishSettings) => any) | undefined;
public readPublishProfile: ((profileUri: vscode.Uri) => any) | undefined; public readPublishProfile: ((profileUri: vscode.Uri) => Promise<PublishProfile>) | undefined;
public savePublishProfile: ((profilePath: string, databaseName: string, connectionString: string, sqlCommandVariableValues?: Map<string, string>, deploymentOptions?: DeploymentOptions) => any) | undefined; public savePublishProfile: ((profilePath: string, databaseName: string, connectionString: string, sqlCommandVariableValues?: Map<string, string>, deploymentOptions?: DeploymentOptions) => any) | undefined;
constructor(private project: Project) { constructor(private project: Project) {
@@ -814,8 +815,8 @@ export class PublishDatabaseDialog {
this.formBuilder?.removeFormItem(<azdataType.FormComponentGroup>this.sqlCmdVariablesFormComponentGroup); this.formBuilder?.removeFormItem(<azdataType.FormComponentGroup>this.sqlCmdVariablesFormComponentGroup);
} }
for (let key in result.sqlCmdVariables) { for (let key of result.sqlCmdVariables.keys()) {
this.sqlCmdVars?.set(key, result.sqlCmdVariableColumn.get(key)); this.sqlCmdVars?.set(key, result.sqlCmdVariables.get(key)!);
} }
this.updateRevertSqlCmdVarsButtonState(); this.updateRevertSqlCmdVarsButtonState();
@@ -983,7 +984,7 @@ export class PublishDatabaseDialog {
/* /*
* Sets the default deployment options to deployment options model object * Sets the default deployment options to deployment options model object
*/ */
public setDeploymentOptions(deploymentOptions: DeploymentOptions): void { public setDeploymentOptions(deploymentOptions: DeploymentOptions | undefined): void {
this.deploymentOptions = deploymentOptions; this.deploymentOptions = deploymentOptions;
} }
} }

View File

@@ -159,9 +159,7 @@ export async function getPublishDatabaseSettings(project: ISqlProject, promptFor
} }
// 4. Modify sqlcmd vars // 4. Modify sqlcmd vars
// If a publish profile is provided then the values from there will overwrite the ones in the let sqlCmdVariables: Map<string, string> = getInitialSqlCmdVariables(project, publishProfile);
// project file (if they exist)
let sqlCmdVariables = Object.assign({}, project.sqlCmdVariables, publishProfile?.sqlCmdVariables);
if (sqlCmdVariables.size > 0) { if (sqlCmdVariables.size > 0) {
// Continually loop here, allowing the user to modify SQLCMD variables one // Continually loop here, allowing the user to modify SQLCMD variables one
@@ -170,13 +168,14 @@ export async function getPublishDatabaseSettings(project: ISqlProject, promptFor
// as many times as they wish - with an option to reset all the variables // as many times as they wish - with an option to reset all the variables
// to their starting values being provided as well. // to their starting values being provided as well.
while (true) { while (true) {
const quickPickItems = Object.keys(sqlCmdVariables).map(key => { let quickPickItems = [];
return { for (const key of sqlCmdVariables.keys()) {
quickPickItems.push({
label: key, label: key,
description: sqlCmdVariables.get(key), description: sqlCmdVariables.get(key),
key: key key: key
} as vscode.QuickPickItem & { key?: string, isResetAllVars?: boolean, isDone?: boolean }; } as vscode.QuickPickItem & { key?: string, isResetAllVars?: boolean, isDone?: boolean })
}); }
quickPickItems.push({ label: `$(refresh) ${constants.resetAllVars}`, isResetAllVars: true }); quickPickItems.push({ label: `$(refresh) ${constants.resetAllVars}`, isResetAllVars: true });
quickPickItems.unshift({ label: `$(check) ${constants.done}`, isDone: true }); quickPickItems.unshift({ label: `$(check) ${constants.done}`, isDone: true });
const sqlCmd = await vscode.window.showQuickPick( const sqlCmd = await vscode.window.showQuickPick(
@@ -200,7 +199,7 @@ export async function getPublishDatabaseSettings(project: ISqlProject, promptFor
sqlCmdVariables.set(sqlCmd.key, newValue); sqlCmdVariables.set(sqlCmd.key, newValue);
} }
} else if (sqlCmd.isResetAllVars) { } else if (sqlCmd.isResetAllVars) {
sqlCmdVariables = Object.assign({}, project.sqlCmdVariables, publishProfile?.sqlCmdVariables); sqlCmdVariables = getInitialSqlCmdVariables(project, publishProfile);
} else if (sqlCmd.isDone) { } else if (sqlCmd.isDone) {
break; break;
} }
@@ -220,6 +219,24 @@ export async function getPublishDatabaseSettings(project: ISqlProject, promptFor
return settings; return settings;
} }
/**
* Loads the sqlcmd variables from a sql projects. If a publish profile is provided then the values from there will overwrite the ones in the project file (if they exist)
* @param project
* @param publishProfile
* @returns Map of sqlcmd variables
*/
function getInitialSqlCmdVariables(project: ISqlProject, publishProfile?: PublishProfile): Map<string, string> {
// create a copy of the sqlcmd variable map so that the original ones don't get overwritten
let sqlCmdVariables = new Map(project.sqlCmdVariables);
if (publishProfile?.sqlCmdVariables) {
for (const [key, value] of publishProfile.sqlCmdVariables) {
sqlCmdVariables.set(key, value);
}
}
return sqlCmdVariables;
}
export async function launchPublishTargetOption(project: Project): Promise<constants.PublishTargetType | undefined> { export async function launchPublishTargetOption(project: Project): Promise<constants.PublishTargetType | undefined> {
// Show options to user for deploy to existing server or docker // Show options to user for deploy to existing server or docker
const target = project.getProjectTargetVersion(); const target = project.getProjectTargetVersion();

View File

@@ -108,7 +108,7 @@
"tas-client-umd": "0.1.6", "tas-client-umd": "0.1.6",
"turndown": "^7.0.0", "turndown": "^7.0.0",
"turndown-plugin-gfm": "^1.0.2", "turndown-plugin-gfm": "^1.0.2",
"v8-inspect-profiler": "^0.0.22", "v8-inspect-profiler": "^0.1.0",
"vscode-oniguruma": "1.6.1", "vscode-oniguruma": "1.6.1",
"vscode-policy-watcher": "^1.1.1", "vscode-policy-watcher": "^1.1.1",
"vscode-proxy-agent": "^0.12.0", "vscode-proxy-agent": "^0.12.0",
@@ -145,7 +145,7 @@
"@types/node": "16.x", "@types/node": "16.x",
"@types/plotly.js": "^1.44.9", "@types/plotly.js": "^1.44.9",
"@types/sanitize-html": "^1.18.2", "@types/sanitize-html": "^1.18.2",
"@types/sinon": "^10.0.2", "@types/sinon": "10.0.2",
"@types/sinon-test": "^2.4.2", "@types/sinon-test": "^2.4.2",
"@types/trusted-types": "^1.0.6", "@types/trusted-types": "^1.0.6",
"@types/vscode-notebook-renderer": "1.60.0", "@types/vscode-notebook-renderer": "1.60.0",
@@ -187,7 +187,7 @@
"gulp-bom": "^3.0.0", "gulp-bom": "^3.0.0",
"gulp-buffer": "0.0.2", "gulp-buffer": "0.0.2",
"gulp-concat": "^2.6.1", "gulp-concat": "^2.6.1",
"gulp-eslint": "^6.0.0", "gulp-eslint": "^5.0.0",
"gulp-filter": "^5.1.0", "gulp-filter": "^5.1.0",
"gulp-flatmap": "^1.0.2", "gulp-flatmap": "^1.0.2",
"gulp-gunzip": "^1.0.0", "gulp-gunzip": "^1.0.0",
@@ -198,7 +198,6 @@
"gulp-remote-retry-src": "^0.8.0", "gulp-remote-retry-src": "^0.8.0",
"gulp-rename": "^1.2.0", "gulp-rename": "^1.2.0",
"gulp-replace": "^0.5.4", "gulp-replace": "^0.5.4",
"gulp-shell": "^0.6.5",
"gulp-sourcemaps": "^3.0.0", "gulp-sourcemaps": "^3.0.0",
"gulp-svgmin": "^4.1.0", "gulp-svgmin": "^4.1.0",
"gulp-untar": "^0.0.7", "gulp-untar": "^0.0.7",
@@ -230,16 +229,16 @@
"rcedit": "^1.1.0", "rcedit": "^1.1.0",
"request": "^2.85.0", "request": "^2.85.0",
"rimraf": "^2.2.8", "rimraf": "^2.2.8",
"sinon": "^11.1.1", "sinon": "11.1.1",
"sinon-test": "^3.1.3", "sinon-test": "^3.1.3",
"source-map": "0.6.1", "source-map": "0.6.1",
"source-map-support": "^0.3.2", "source-map-support": "^0.3.2",
"style-loader": "^1.0.0", "style-loader": "^1.3.0",
"temp-write": "^3.4.0", "temp-write": "^3.4.0",
"ts-loader": "^9.2.7", "ts-loader": "^9.2.7",
"tsec": "0.1.4", "tsec": "0.1.4",
"typemoq": "^0.3.2", "typemoq": "^0.3.2",
"typescript": "^4.8.0-dev.20220518", "typescript": "4.8.0-dev.20220719",
"typescript-formatter": "7.1.0", "typescript-formatter": "7.1.0",
"underscore": "^1.12.1", "underscore": "^1.12.1",
"util": "^0.12.4", "util": "^0.12.4",

View File

@@ -1797,6 +1797,10 @@ declare module 'azdata' {
} }
export interface NodeFilterProperty { export interface NodeFilterProperty {
/**
* The non-localized name of the filter property
*/
name: string;
/** /**
* The name of the filter property displayed to the user * The name of the filter property displayed to the user
*/ */
@@ -1818,14 +1822,27 @@ declare module 'azdata' {
/** /**
* The list of choices for the filter property if the type is choice * The list of choices for the filter property if the type is choice
*/ */
choices: string[]; choices: NodeFilterChoicePropertyValue[];
}
export interface NodeFilterChoicePropertyValue {
/**
* The value of the choice
*/
value: string;
/**
* The display name of the choice
* If not specified, the value will be used as the display name
* If specified, the display name will be used in the dropdown
*/
displayName?: string;
} }
export interface NodeFilter { export interface NodeFilter {
/** /**
* The name of the filter property * The name of the filter property
*/ */
name: string; displayName: string;
/** /**
* The operator of the filter property * The operator of the filter property
*/ */
@@ -1833,7 +1850,7 @@ declare module 'azdata' {
/** /**
* The applied values of the filter property * The applied values of the filter property
*/ */
value: string | string[] | number | boolean | undefined; value: string | string[] | number | number[] | boolean | undefined;
} }
export enum NodeFilterPropertyDataType { export enum NodeFilterPropertyDataType {
@@ -1930,4 +1947,11 @@ declare module 'azdata' {
isPrimary: boolean; isPrimary: boolean;
} }
} }
export interface TableComponent {
/**
* Set active cell.
*/
setActiveCell(row: number, column: number): void;
}
} }

View File

@@ -41,7 +41,7 @@ export class TableCellEditorFactory {
}; };
} }
public getTextEditorClass(context: any, inputType: 'text' | 'number' = 'text'): any { public getTextEditorClass(context: any, inputType: 'text' | 'number' | 'date' = 'text', presetValue?: string): any {
const self = this; const self = this;
class TextEditor extends Disposable { class TextEditor extends Disposable {
private _originalValue: string; private _originalValue: string;
@@ -76,6 +76,8 @@ export class TableCellEditorFactory {
this._register(self._options.onStyleChange(() => { this._register(self._options.onStyleChange(() => {
self._options.editorStyler(this._input); self._options.editorStyler(this._input);
})); }));
this._input.value = presetValue ?? '';
} }
private async commitEdit(): Promise<void> { private async commitEdit(): Promise<void> {
@@ -96,11 +98,21 @@ export class TableCellEditorFactory {
public loadValue(item: Slick.SlickData): void { public loadValue(item: Slick.SlickData): void {
this._originalValue = self._options.valueGetter(item, this._args.column) ?? ''; this._originalValue = self._options.valueGetter(item, this._args.column) ?? '';
this._input.value = this._originalValue; if (inputType === 'date') {
this._input.inputElement.valueAsDate = new Date(this._originalValue);
} else {
this._input.value = this._originalValue;
}
} }
public applyValue(item: Slick.SlickData, state: string): void { public applyValue(item: Slick.SlickData, state: string): void {
const activeCell = this._args.grid.getActiveCell(); const activeCell = this._args.grid.getActiveCell();
if (inputType === 'date') {
// Usually, the date picker will return the date in the local time zone and change the date to the previous day.
// We need to convert the date to UTC time zone to avoid this behavior so that the date will be the same as the
// date picked in the date picker.
state = new Date(state).toLocaleDateString(window.navigator.language, { timeZone: 'UTC' });
}
self._options.valueSetter(context, activeCell.row, item, this._args.column, state); self._options.valueSetter(context, activeCell.row, item, this._args.column, state);
} }

View File

@@ -97,10 +97,24 @@ export class TestCapabilitiesService implements ICapabilitiesService {
valueType: ServiceOptionType.string valueType: ServiceOptionType.string
} }
]; ];
let mssqlAdvancedOptions: azdata.ConnectionOption[] = [
{
name: 'trustServerCertificate',
displayName: undefined!,
description: undefined!,
groupName: undefined!,
categoryValues: undefined!,
defaultValue: 'false',
isIdentity: false,
isRequired: false,
specialValueType: undefined!,
valueType: ServiceOptionType.boolean
}
];
let msSQLCapabilities = { let msSQLCapabilities = {
providerId: mssqlProviderName, providerId: mssqlProviderName,
displayName: 'MSSQL', displayName: 'MSSQL',
connectionOptions: connectionProvider, connectionOptions: connectionProvider.concat(mssqlAdvancedOptions),
}; };
let pgSQLCapabilities = { let pgSQLCapabilities = {
providerId: this.pgsqlProviderName, providerId: this.pgsqlProviderName,

View File

@@ -9,7 +9,7 @@ import { ConnectionConfig } from 'sql/platform/connection/common/connectionConfi
import { fixupConnectionCredentials } from 'sql/platform/connection/common/connectionInfo'; import { fixupConnectionCredentials } from 'sql/platform/connection/common/connectionInfo';
import { ConnectionProfile } from 'sql/platform/connection/common/connectionProfile'; import { ConnectionProfile } from 'sql/platform/connection/common/connectionProfile';
import { ConnectionProfileGroup, IConnectionProfileGroup } from 'sql/platform/connection/common/connectionProfileGroup'; import { ConnectionProfileGroup, IConnectionProfileGroup } from 'sql/platform/connection/common/connectionProfileGroup';
import { AuthenticationType } from 'sql/platform/connection/common/constants'; import { AuthenticationType, mssqlProviderName } from 'sql/platform/connection/common/constants';
import { IConnectionProfile, ProfileMatcher } from 'sql/platform/connection/common/interfaces'; import { IConnectionProfile, ProfileMatcher } from 'sql/platform/connection/common/interfaces';
import { ICredentialsService } from 'sql/platform/credentials/common/credentialsService'; import { ICredentialsService } from 'sql/platform/credentials/common/credentialsService';
import { isDisposable } from 'vs/base/common/lifecycle'; import { isDisposable } from 'vs/base/common/lifecycle';
@@ -84,10 +84,28 @@ export class ConnectionStore {
if (credentialsItem.savePassword && this.isPasswordRequired(credentialsItem) && !credentialsItem.password) { if (credentialsItem.savePassword && this.isPasswordRequired(credentialsItem) && !credentialsItem.password) {
const credentialId = this.formatCredentialId(credentialsItem, CRED_PROFILE_USER); const credentialId = this.formatCredentialId(credentialsItem, CRED_PROFILE_USER);
return this.credentialService.readCredential(credentialId) return this.credentialService.readCredential(credentialId)
.then(savedCred => { .then(async savedCred => {
if (savedCred) { if (savedCred?.password) {
credentialsItem.password = savedCred.password; credentialsItem.password = savedCred.password;
credentialsItem.options['password'] = savedCred.password; credentialsItem.options['password'] = savedCred.password;
} else if (credentialsItem.providerName === mssqlProviderName) {
// Special handling for MSSQL provider as "applicationName:azdata" is no longer included
// in credential string starting with MAY 2023 release.
// We will try to read credential including applicationName and if it is found,
// we will update the saved credential with new credential key.
// This special case handling should be removed in a future release.
let credParts = credentialId.split('|');
credParts.splice(3, 0, 'applicationName:azdata');
const oldCredentialId = credParts.join('|');
const savedMssqlCred = await this.credentialService.readCredential(oldCredentialId);
if (savedMssqlCred?.password) {
credentialsItem.password = savedMssqlCred.password;
credentialsItem.options['password'] = savedMssqlCred.password;
// Update credential in credential store.
await this.credentialService.deleteCredential(oldCredentialId);
await this.credentialService.saveCredential(credentialId, savedMssqlCred.password);
savedCred.password = savedMssqlCred.password;
}
} }
return { profile: credentialsItem, savedCred: !!savedCred }; return { profile: credentialsItem, savedCred: !!savedCred };
}); });

View File

@@ -202,6 +202,27 @@ export class ProviderConnectionInfo implements azdata.ConnectionInfo {
* Example: "providerName:MSSQL|authenticationType:|databaseName:database|serverName:server3|userName:user|group:testid" * Example: "providerName:MSSQL|authenticationType:|databaseName:database|serverName:server3|userName:user|group:testid"
*/ */
public getOptionsKey(): string { public getOptionsKey(): string {
let idNames = this.getOptionKeyIdNames();
idNames = idNames.filter(x => x !== undefined);
//Sort to make sure using names in the same order every time otherwise the ids would be different
idNames.sort();
let idValues: string[] = [];
for (let index = 0; index < idNames.length; index++) {
let value = this.options[idNames[index]!];
value = value ? value : '';
idValues.push(`${idNames[index]}${ProviderConnectionInfo.nameValueSeparator}${value}`);
}
return ProviderConnectionInfo.ProviderPropertyName + ProviderConnectionInfo.nameValueSeparator +
this.providerName + ProviderConnectionInfo.idSeparator + idValues.join(ProviderConnectionInfo.idSeparator);
}
/**
* @returns Array of option key names
*/
public getOptionKeyIdNames(): string[] {
let idNames = []; let idNames = [];
if (this.serverCapabilities) { if (this.serverCapabilities) {
idNames = this.serverCapabilities.connectionOptions.map(o => { idNames = this.serverCapabilities.connectionOptions.map(o => {
@@ -217,21 +238,7 @@ export class ProviderConnectionInfo implements azdata.ConnectionInfo {
// This should never happen but just incase the serverCapabilities was not ready at this time // This should never happen but just incase the serverCapabilities was not ready at this time
idNames = ['authenticationType', 'database', 'server', 'user']; idNames = ['authenticationType', 'database', 'server', 'user'];
} }
return idNames;
idNames = idNames.filter(x => x !== undefined);
//Sort to make sure using names in the same order every time otherwise the ids would be different
idNames.sort();
let idValues: string[] = [];
for (let index = 0; index < idNames.length; index++) {
let value = this.options[idNames[index]!];
value = value ? value : '';
idValues.push(`${idNames[index]}${ProviderConnectionInfo.nameValueSeparator}${value}`);
}
return ProviderConnectionInfo.ProviderPropertyName + ProviderConnectionInfo.nameValueSeparator +
this.providerName + ProviderConnectionInfo.idSeparator + idValues.join(ProviderConnectionInfo.idSeparator);
} }
public static getProviderFromOptionsKey(optionsKey: string) { public static getProviderFromOptionsKey(optionsKey: string) {

View File

@@ -32,7 +32,8 @@ export enum ComponentEventType {
export enum ModelViewAction { export enum ModelViewAction {
SelectTab = 'selectTab', SelectTab = 'selectTab',
AppendData = 'appendData', AppendData = 'appendData',
Filter = 'filter' Filter = 'filter',
SetActiveCell = 'setActiveCell'
} }
/** /**

View File

@@ -50,7 +50,8 @@ export const enum TelemetryView {
ResultsPanel = 'ResultsPanel', ResultsPanel = 'ResultsPanel',
Shell = 'Shell', Shell = 'Shell',
SqlAssessment = 'SqlAssessment', SqlAssessment = 'SqlAssessment',
TableDesigner = 'TableDesigner' TableDesigner = 'TableDesigner',
ObjectExplorer = 'ObjectExplorer'
} }
export const enum TelemetryError { export const enum TelemetryError {
@@ -98,6 +99,8 @@ export const enum TelemetryAction {
MoveServerGroup = 'MoveServerGroup', MoveServerGroup = 'MoveServerGroup',
NewQuery = 'NewQuery', NewQuery = 'NewQuery',
ObjectExplorerExpand = 'ObjectExplorerExpand', ObjectExplorerExpand = 'ObjectExplorerExpand',
ObjectExplorerFilter = 'ObjectExplorerFilter',
ObjectExplorerRemoveFilter = 'ObjectExplorerRemoveFilter',
Open = 'Open', Open = 'Open',
OpenQuery = 'OpenQuery', OpenQuery = 'OpenQuery',
OpenExecutionPlanProperties = 'OpenExecutionPlanProperties', OpenExecutionPlanProperties = 'OpenExecutionPlanProperties',

View File

@@ -1503,6 +1503,10 @@ class TableComponentWrapper extends ComponentWrapper implements azdata.TableComp
public appendData(v: any[][]): Thenable<void> { public appendData(v: any[][]): Thenable<void> {
return this.doAction(ModelViewAction.AppendData, v); return this.doAction(ModelViewAction.AppendData, v);
} }
public setActiveCell(row: number, column: number): void {
this.doAction(ModelViewAction.SetActiveCell, row, column);
}
} }
class DropDownWrapper extends ComponentWrapper implements azdata.DropDownComponent { class DropDownWrapper extends ComponentWrapper implements azdata.DropDownComponent {

View File

@@ -186,7 +186,8 @@ export enum ModelComponentTypes {
export enum ModelViewAction { export enum ModelViewAction {
SelectTab = 'selectTab', SelectTab = 'selectTab',
AppendData = 'appendData', AppendData = 'appendData',
Filter = 'filter' Filter = 'filter',
SetActiveCell = 'setActiveCell'
} }
export enum ColumnSizingMode { export enum ColumnSizingMode {

View File

@@ -40,6 +40,7 @@ import { IInstantiationService } from 'vs/platform/instantiation/common/instanti
import { IAccessibilityService } from 'vs/platform/accessibility/common/accessibility'; import { IAccessibilityService } from 'vs/platform/accessibility/common/accessibility';
import { IQuickInputService } from 'vs/platform/quickinput/common/quickInput'; import { IQuickInputService } from 'vs/platform/quickinput/common/quickInput';
import { ITableService } from 'sql/workbench/services/table/browser/tableService'; import { ITableService } from 'sql/workbench/services/table/browser/tableService';
import { deepClone, equals } from 'vs/base/common/objects';
export enum ColumnSizingMode { export enum ColumnSizingMode {
ForceFit = 0, // all columns will be sized to fit in viewable space, no horiz scroll bar ForceFit = 0, // all columns will be sized to fit in viewable space, no horiz scroll bar
@@ -358,24 +359,27 @@ export default class TableComponent extends ComponentBase<azdata.TableComponentP
} }
public override setProperties(properties: { [key: string]: any; }): void { public override setProperties(properties: { [key: string]: any; }): void {
const oldColumns = deepClone(this.columns);
super.setProperties(properties); super.setProperties(properties);
this._tableData.clear(); this._tableData.clear();
this._tableData.push(this.transformData(this.data, this.columns)); this._tableData.push(this.transformData(this.data, this.columns));
this._tableColumns = this.transformColumns(this.columns); if (!equals(oldColumns, this.columns)) {
this._table.columns = this._tableColumns; this._tableColumns = this.transformColumns(this.columns);
this._table.columns = this._tableColumns;
this._checkboxColumns.forEach((column, columnName) => { this.registerPlugins(columnName, column); })
Object.keys(this._buttonColumns).forEach(col => this.registerPlugins(col, this._buttonColumns[col]));
Object.keys(this._hyperlinkColumns).forEach(col => this.registerPlugins(col, this._hyperlinkColumns[col]));
Object.keys(this._contextMenuColumns).forEach(col => this.registerPlugins(col, this._contextMenuColumns[col]));
this._table.columns = this._tableColumns;
this._table.autosizeColumns();
}
this._table.setData(this._tableData); this._table.setData(this._tableData);
this._table.setTableTitle(this.title); this._table.setTableTitle(this.title);
if (this.selectedRows) { if (this.selectedRows) {
this._table.setSelectedRows(this.selectedRows); this._table.setSelectedRows(this.selectedRows);
} }
this._checkboxColumns.forEach((column, columnName) => {
this.registerPlugins(columnName, column);
})
Object.keys(this._buttonColumns).forEach(col => this.registerPlugins(col, this._buttonColumns[col]));
Object.keys(this._hyperlinkColumns).forEach(col => this.registerPlugins(col, this._hyperlinkColumns[col]));
Object.keys(this._contextMenuColumns).forEach(col => this.registerPlugins(col, this._contextMenuColumns[col]));
if (this.headerFilter === true) { if (this.headerFilter === true) {
this.registerFilterPlugin(); this.registerFilterPlugin();
this._tableData.clearFilter(); this._tableData.clearFilter();
@@ -433,7 +437,8 @@ export default class TableComponent extends ComponentBase<azdata.TableComponentP
width: col.width, width: col.width,
cssClass: col.cssClass, cssClass: col.cssClass,
headerCssClass: col.headerCssClass, headerCssClass: col.headerCssClass,
actionOnCheck: checkboxAction actionOnCheck: checkboxAction,
columnId: `checkbox-column-${index}`,
}, index)); }, index));
this._register(this._checkboxColumns.get(col.value).onChange((state) => { this._register(this._checkboxColumns.get(col.value).onChange((state) => {
@@ -589,7 +594,6 @@ export default class TableComponent extends ComponentBase<azdata.TableComponentP
private registerPlugins(col: string, plugin: CheckboxSelectColumn<{}> | ButtonColumn<{}> | HyperlinkColumn<{}> | ContextMenuColumn<{}>): void { private registerPlugins(col: string, plugin: CheckboxSelectColumn<{}> | ButtonColumn<{}> | HyperlinkColumn<{}> | ContextMenuColumn<{}>): void {
const index = 'index' in plugin ? plugin.index : this.columns?.findIndex(x => x === col || ('value' in x && x['value'] === col)); const index = 'index' in plugin ? plugin.index : this.columns?.findIndex(x => x === col || ('value' in x && x['value'] === col));
if (index >= 0) { if (index >= 0) {
this._tableColumns.splice(index, 0, plugin.definition); this._tableColumns.splice(index, 0, plugin.definition);
@@ -598,10 +602,6 @@ export default class TableComponent extends ComponentBase<azdata.TableComponentP
this._pluginsRegisterStatus[col] = true; this._pluginsRegisterStatus[col] = true;
} }
} }
this._table.columns = this._tableColumns;
this._table.autosizeColumns();
} }
@@ -723,6 +723,10 @@ export default class TableComponent extends ComponentBase<azdata.TableComponentP
switch (action) { switch (action) {
case ModelViewAction.AppendData: case ModelViewAction.AppendData:
this.appendData(args[0]); this.appendData(args[0]);
break;
case ModelViewAction.SetActiveCell:
this._table.grid.setActiveCell(args[0], args[1]);
break;
} }
} }

View File

@@ -31,17 +31,61 @@ import { IEnvironmentService, INativeEnvironmentService } from 'vs/platform/envi
import { NativeParsedArgs } from 'vs/platform/environment/common/argv'; import { NativeParsedArgs } from 'vs/platform/environment/common/argv';
export interface SqlArgs { export interface SqlArgs {
/**
* Used to determine file paths to be opened with SQL Editor.
* If provided, we connect the given profile to to it.
* More than one files can be passed to connect to provided profile.
*/
_?: string[]; _?: string[];
/**
* Provide authenticationType to be used.
* accepted values: AzureMFA, SqlLogin, Integrated, etc.
*/
authenticationType?: string authenticationType?: string
/**
* Name of database
*/
database?: string; database?: string;
/**
* Name of server
*/
server?: string; server?: string;
/**
* User name/email address
*/
user?: string; user?: string;
/**
* Operation to perform:
* accepted values: connect, openConnectionDialog
*/
command?: string; command?: string;
/**
* Name of connection provider,
* accepted values: mssql (by default), pgsql, etc.
*/
provider?: string; provider?: string;
aad?: boolean; // deprecated - used by SSMS - authenticationType should be used instead /**
integrated?: boolean; // deprecated - used by SSMS - authenticationType should be used instead. * Deprecated - used by SSMS - authenticationType should be used instead
*/
aad?: boolean;
/**
* Deprecated - used by SSMS - authenticationType should be used instead.
*/
integrated?: boolean;
/**
* Whether or not to show dashboard
* accepted values: true, false (by default).
*/
showDashboard?: boolean; showDashboard?: boolean;
/**
* Supports providing applicationName that will be used for connection profile app name.
*/
applicationName?: string; applicationName?: string;
/**
* Supports providing advanced connection properties that providers support.
* Value must be a json object containing key-value pairs in format: '{"key1":"value1","key2":"value2",...}'
*/
connectionProperties?: string;
} }
//#region decorators //#region decorators
@@ -324,9 +368,33 @@ export class CommandLineWorkbenchContribution implements IWorkbenchContribution,
profile.setOptionValue('applicationName', applicationName); profile.setOptionValue('applicationName', applicationName);
profile.setOptionValue('databaseDisplayName', profile.databaseName); profile.setOptionValue('databaseDisplayName', profile.databaseName);
profile.setOptionValue('groupId', profile.groupId); profile.setOptionValue('groupId', profile.groupId);
// Set all advanced options
let advancedOptions = this.getAdvancedOptions(args.connectionProperties, profile.getOptionKeyIdNames());
advancedOptions.forEach((v, k) => {
profile.setOptionValue(k, v);
});
return this._connectionManagementService ? this.tryMatchSavedProfile(profile) : profile; return this._connectionManagementService ? this.tryMatchSavedProfile(profile) : profile;
} }
private getAdvancedOptions(options: string, idNames: string[]): Map<string, string> {
const ignoredProperties = idNames.concat(['password', 'azureAccountToken']);
let advancedOptionsMap = new Map<string, string>();
if (options) {
try {
// Decode options if they contain any encoded URL characters
options = decodeURI(options);
JSON.parse(options, (k, v) => {
if (!(k in ignoredProperties)) {
advancedOptionsMap.set(k, v);
}
});
} catch (e) {
throw new Error(localize('commandline.propertiesFormatError', 'Advanced connection properties could not be parsed as JSON, error occurred: {0} Received properties value: {1}', e, options));
}
}
return advancedOptionsMap;
}
private tryMatchSavedProfile(profile: ConnectionProfile) { private tryMatchSavedProfile(profile: ConnectionProfile) {
let match: ConnectionProfile = undefined; let match: ConnectionProfile = undefined;
// If we can find a saved mssql provider connection that matches the args, use it // If we can find a saved mssql provider connection that matches the args, use it

View File

@@ -96,6 +96,7 @@ class TestParsedArgs implements NativeParsedArgs, SqlArgs {
waitMarkerFilePath?: string; waitMarkerFilePath?: string;
authenticationType?: string; authenticationType?: string;
applicationName?: string; applicationName?: string;
connectionProperties?: string;
} }
suite('commandLineService tests', () => { suite('commandLineService tests', () => {
@@ -219,6 +220,42 @@ suite('commandLineService tests', () => {
connectionManagementService.verifyAll(); connectionManagementService.verifyAll();
}); });
test('processCommandLine loads advanced options in args', async () => {
const connectionManagementService: TypeMoq.Mock<IConnectionManagementService>
= TypeMoq.Mock.ofType<IConnectionManagementService>(TestConnectionManagementService, TypeMoq.MockBehavior.Strict);
const args: TestParsedArgs = new TestParsedArgs();
args.server = 'myserver';
args.database = 'mydatabase';
args.user = 'myuser';
args.authenticationType = Constants.AuthenticationType.SqlLogin;
args.applicationName = 'myapplication';
// Pass advanced connection properties
args.connectionProperties = `{"trustServerCertificate":"true"}`;
connectionManagementService.setup((c) => c.showConnectionDialog()).verifiable(TypeMoq.Times.never());
connectionManagementService.setup(c => c.hasRegisteredServers()).returns(() => true).verifiable(TypeMoq.Times.atMostOnce());
connectionManagementService.setup(c => c.getConnectionGroups(TypeMoq.It.isAny())).returns(() => []);
let originalProfile: IConnectionProfile = undefined;
connectionManagementService.setup(c => c.connectIfNotConnected(TypeMoq.It.is<ConnectionProfile>(
p => p.serverName === 'myserver'
&& p.authenticationType === Constants.AuthenticationType.SqlLogin
&& p.options['applicationName'] === 'myapplication-azdata'), 'connection', true))
.returns((conn) => {
originalProfile = conn;
return Promise.resolve('unused');
})
.verifiable(TypeMoq.Times.once());
connectionManagementService.setup(c => c.getConnectionProfileById(TypeMoq.It.isAnyString())).returns(() => originalProfile);
const configurationService = getConfigurationServiceMock(true);
const logService = new NullLogService();
let contribution = getCommandLineContribution(connectionManagementService.object, configurationService.object, capabilitiesService, undefined, undefined, logService);
await contribution.processCommandLine(args);
assert.equal(originalProfile.options['applicationName'], 'myapplication-azdata', 'Application Name not received as expected.');
assert.equal(originalProfile.options['trustServerCertificate'], 'true', 'Advanced option not received as expected.');
connectionManagementService.verifyAll();
});
test('processCommandLine invokes a command without a profile parameter when no server is passed', async () => { test('processCommandLine invokes a command without a profile parameter when no server is passed', async () => {
const connectionManagementService: TypeMoq.Mock<IConnectionManagementService> const connectionManagementService: TypeMoq.Mock<IConnectionManagementService>
= TypeMoq.Mock.ofType<IConnectionManagementService>(TestConnectionManagementService, TypeMoq.MockBehavior.Loose); = TypeMoq.Mock.ofType<IConnectionManagementService>(TestConnectionManagementService, TypeMoq.MockBehavior.Loose);
@@ -568,7 +605,5 @@ suite('commandLineService tests', () => {
notificationService.verifyAll(); notificationService.verifyAll();
connectionManagementService.verifyAll(); connectionManagementService.verifyAll();
}); });
}); });
}); });

View File

@@ -27,7 +27,7 @@ export class LinkHandlerDirective {
@Inject(INotebookService) private readonly notebookService: INotebookService, @Inject(INotebookService) private readonly notebookService: INotebookService,
@Inject(IFileService) private readonly fileService: IFileService @Inject(IFileService) private readonly fileService: IFileService
) { ) {
this.workbenchFilePath = URI.parse(require.toUrl('vs/code/electron-browser/workbench/workbench.html')); this.workbenchFilePath = URI.parse(require.toUrl('vs/code/electron-sandbox/workbench/workbench.html'));
} }
@HostListener('click', ['$event']) @HostListener('click', ['$event'])

View File

@@ -47,6 +47,9 @@ import { ActionRunner } from 'vs/base/common/actions';
import { IHostService } from 'vs/workbench/services/host/browser/host'; import { IHostService } from 'vs/workbench/services/host/browser/host';
import { USE_ASYNC_SERVER_TREE_CONFIG } from 'sql/workbench/contrib/objectExplorer/common/serverGroup.contribution'; import { USE_ASYNC_SERVER_TREE_CONFIG } from 'sql/workbench/contrib/objectExplorer/common/serverGroup.contribution';
import { INotificationService } from 'vs/platform/notification/common/notification'; import { INotificationService } from 'vs/platform/notification/common/notification';
import { FilterDialog } from 'sql/workbench/services/objectExplorer/browser/filterDialog/filterDialog';
import * as TelemetryKeys from 'sql/platform/telemetry/common/telemetryKeys';
import { IAdsTelemetryService } from 'sql/platform/telemetry/common/telemetry';
export const CONTEXT_SERVER_TREE_VIEW = new RawContextKey<ServerTreeViewView>('serverTreeView.view', ServerTreeViewView.all); export const CONTEXT_SERVER_TREE_VIEW = new RawContextKey<ServerTreeViewView>('serverTreeView.view', ServerTreeViewView.all);
export const CONTEXT_SERVER_TREE_HAS_CONNECTIONS = new RawContextKey<boolean>('serverTreeView.hasConnections', false); export const CONTEXT_SERVER_TREE_HAS_CONNECTIONS = new RawContextKey<boolean>('serverTreeView.hasConnections', false);
@@ -78,7 +81,8 @@ export class ServerTreeView extends Disposable implements IServerTreeView {
@IKeybindingService private _keybindingService: IKeybindingService, @IKeybindingService private _keybindingService: IKeybindingService,
@IContextKeyService contextKeyService: IContextKeyService, @IContextKeyService contextKeyService: IContextKeyService,
@IHostService private _hostService: IHostService, @IHostService private _hostService: IHostService,
@INotificationService private _notificationService: INotificationService @INotificationService private _notificationService: INotificationService,
@IAdsTelemetryService private _telemetryService: IAdsTelemetryService
) { ) {
super(); super();
this._hasConnectionsKey = CONTEXT_SERVER_TREE_HAS_CONNECTIONS.bindTo(contextKeyService); this._hasConnectionsKey = CONTEXT_SERVER_TREE_HAS_CONNECTIONS.bindTo(contextKeyService);
@@ -588,6 +592,50 @@ export class ServerTreeView extends Disposable implements IServerTreeView {
} }
} }
public async filterElementChildren(node: TreeNode): Promise<void> {
await FilterDialog.getFiltersForProperties(
node.filterProperties,
localize('objectExplorer.filterDialogTitle', "(Preview) Filter Settings: {0}", node.getConnectionProfile().title),
localize('objectExplorer.nodePath', "Node Path: {0}", node.nodePath),
node.filters,
async (filters) => {
let errorListener;
try {
let expansionError = undefined;
errorListener = this._objectExplorerService.onUpdateObjectExplorerNodes(e => {
if (e.errorMessage) {
expansionError = e.errorMessage;
}
errorListener.dispose();
});
node.forceRefresh = true;
node.filters = filters || [];
if (this._tree instanceof AsyncServerTree) {
await this._tree.rerender(node);
}
await this.refreshElement(node);
await this._tree.expand(node);
if (expansionError) {
throw new Error(expansionError);
}
} finally {
if (errorListener) {
errorListener.dispose();
}
this._telemetryService.createActionEvent(TelemetryKeys.TelemetryView.ObjectExplorer, TelemetryKeys.TelemetryAction.ObjectExplorerFilter)
.withAdditionalProperties({
filterPropertyNames: JSON.stringify(filters.map(f => node.filterProperties.find(p => f.displayName === p.displayName)?.name)),
filterCount: filters.length,
objectType: node.objectType
}).send();
}
return;
},
this._instantiationService
);
}
/** /**
* Filter connections based on view (recent/active) * Filter connections based on view (recent/active)
*/ */

View File

@@ -49,7 +49,7 @@ const serverTreeConfig: IConfigurationNode = {
'properties': { 'properties': {
'serverTree.useAsyncServerTree': { 'serverTree.useAsyncServerTree': {
'type': 'boolean', 'type': 'boolean',
'default': true, 'default': false,
'description': localize('serverTree.useAsyncServerTree', "Use the new async server tree for the Servers view and Connection Dialog with support for new features such as dynamic node filtering. Requires a restart to take effect.") 'description': localize('serverTree.useAsyncServerTree', "Use the new async server tree for the Servers view and Connection Dialog with support for new features such as dynamic node filtering. Requires a restart to take effect.")
} }
} }

View File

@@ -39,7 +39,7 @@ suite('ServerTreeView onAddConnectionProfile handler tests', () => {
); );
mockConnectionManagementService.setup(x => x.getConnectionGroups()).returns(x => []); mockConnectionManagementService.setup(x => x.getConnectionGroups()).returns(x => []);
mockConnectionManagementService.setup(x => x.hasRegisteredServers()).returns(() => true); mockConnectionManagementService.setup(x => x.hasRegisteredServers()).returns(() => true);
serverTreeView = new ServerTreeView(mockConnectionManagementService.object, instantiationService, undefined, new TestThemeService(), undefined, new TestConfigurationService(), capabilitiesService, undefined, undefined, new MockContextKeyService(), undefined, undefined); serverTreeView = new ServerTreeView(mockConnectionManagementService.object, instantiationService, undefined, new TestThemeService(), undefined, new TestConfigurationService(), capabilitiesService, undefined, undefined, new MockContextKeyService(), undefined, undefined, undefined);
mockTree = TypeMoq.Mock.ofType<ITree>(TestTree); mockTree = TypeMoq.Mock.ofType<ITree>(TestTree);
(serverTreeView as any)._tree = mockTree.object; (serverTreeView as any)._tree = mockTree.object;
mockRefreshTreeMethod = TypeMoq.Mock.ofType(Function); mockRefreshTreeMethod = TypeMoq.Mock.ofType(Function);

View File

@@ -21,6 +21,8 @@ import { ILogService } from 'vs/platform/log/common/log';
import { AsyncServerTree, ServerTreeElement } from 'sql/workbench/services/objectExplorer/browser/asyncServerTree'; import { AsyncServerTree, ServerTreeElement } from 'sql/workbench/services/objectExplorer/browser/asyncServerTree';
import { SqlIconId } from 'sql/base/common/codicons'; import { SqlIconId } from 'sql/base/common/codicons';
import { IDialogService } from 'vs/platform/dialogs/common/dialogs'; import { IDialogService } from 'vs/platform/dialogs/common/dialogs';
import { IAdsTelemetryService } from 'sql/platform/telemetry/common/telemetry';
import * as TelemetryKeys from 'sql/platform/telemetry/common/telemetryKeys';
export interface IServerView { export interface IServerView {
showFilteredTree(filter: string): void; showFilteredTree(filter: string): void;
@@ -310,3 +312,64 @@ export class DeleteConnectionAction extends Action {
} }
} }
} }
export class FilterChildrenAction extends Action {
public static ID = 'objectExplorer.filterChildren';
public static LABEL = localize('objectExplorer.filterChildren', "Filter (Preview)");
constructor(
id: string,
label: string,
private _node: TreeNode,
@IObjectExplorerService private _objectExplorerService: IObjectExplorerService) {
super(id, label);
}
public override async run(): Promise<void> {
await this._objectExplorerService.getServerTreeView().filterElementChildren(this._node);
}
}
export class RemoveFilterAction extends Action {
public static ID = 'objectExplorer.removeFilter';
public static LABEL = localize('objectExplorer.removeFilter', "Remove Filter");
constructor(
id: string,
label: string,
private _node: TreeNode,
private _tree: AsyncServerTree | ITree,
private _profile: ConnectionProfile | undefined,
@IObjectExplorerService private _objectExplorerService: IObjectExplorerService,
@IAdsTelemetryService private _telemetryService: IAdsTelemetryService
) {
super(id, label);
}
public override async run(): Promise<void> {
let node = this._node;
let nodeToRefresh: ServerTreeElement = this._node;
if (this._profile) {
node = this._objectExplorerService.getObjectExplorerNode(this._profile);
nodeToRefresh = this._profile;
}
node.filters = [];
if (nodeToRefresh instanceof TreeNode) {
nodeToRefresh.forceRefresh = true;
}
if (this._tree instanceof AsyncServerTree) {
await this._tree.rerender(nodeToRefresh);
await this._tree.updateChildren(nodeToRefresh);
await this._tree.expand(nodeToRefresh);
} else {
await this._tree.refresh(nodeToRefresh);
await this._tree.expand(nodeToRefresh);
}
this._telemetryService.createActionEvent(
TelemetryKeys.TelemetryView.ObjectExplorer,
TelemetryKeys.TelemetryAction.ObjectExplorerRemoveFilter
).withAdditionalProperties({
objectType: node.objectType
}).send();
}
}

View File

@@ -0,0 +1,726 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the Source EULA. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import 'vs/css!./../media/filterDialog';
import { Button } from 'sql/base/browser/ui/button/button';
import { IClipboardService } from 'sql/platform/clipboard/common/clipboardService';
import { IAdsTelemetryService } from 'sql/platform/telemetry/common/telemetry';
import { Modal } from 'sql/workbench/browser/modal/modal'
import { ITextResourcePropertiesService } from 'vs/editor/common/services/textResourceConfiguration';
import { IContextKeyService } from 'vs/platform/contextkey/common/contextkey';
import { ILayoutService } from 'vs/platform/layout/browser/layoutService';
import { ILogService } from 'vs/platform/log/common/log';
import { IThemeService } from 'vs/platform/theme/common/themeService';
import { localize } from 'vs/nls';
import { attachModalDialogStyler } from 'sql/workbench/common/styler';
import { attachButtonStyler, attachInputBoxStyler, attachSelectBoxStyler } from 'vs/platform/theme/common/styler';
import * as DOM from 'vs/base/browser/dom';
import * as azdata from 'azdata';
import { InputBox } from 'sql/base/browser/ui/inputBox/inputBox';
import { IContextViewService } from 'vs/platform/contextview/browser/contextView';
import { NodeFilterPropertyDataType, NodeFilterOperator } from 'sql/workbench/api/common/sqlExtHostTypes';
import { SelectBox } from 'sql/base/browser/ui/selectBox/selectBox';
import { Table } from 'sql/base/browser/ui/table/table';
import { TableCellEditorFactory } from 'sql/base/browser/ui/table/tableCellEditorFactory';
import { Emitter } from 'vs/base/common/event';
import { IAccessibilityService } from 'vs/platform/accessibility/common/accessibility';
import { IQuickInputService } from 'vs/platform/quickinput/common/quickInput';
import { TableDataView } from 'sql/base/browser/ui/table/tableDataView';
import { TableHeaderRowHeight, TableRowHeight } from 'sql/workbench/browser/designer/designerTableUtil';
import { textFormatter } from 'sql/base/browser/ui/table/formatters';
import { Dropdown } from 'sql/base/browser/ui/editableDropdown/browser/dropdown';
import { Checkbox } from 'sql/base/browser/ui/checkbox/checkbox';
import { TabbedPanel } from 'sql/base/browser/ui/panel/panel';
import { attachTableStyler } from 'sql/platform/theme/common/styler';
import { ButtonColumn } from 'sql/base/browser/ui/table/plugins/buttonColumn.plugin';
import Severity from 'vs/base/common/severity';
import { status } from 'vs/base/browser/ui/aria/aria';
import { IErrorMessageService } from 'sql/platform/errorMessage/common/errorMessageService';
import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
// strings for filter dialog
const OkButtonText = localize('objectExplorer.okButtonText', "OK");
const CancelButtonText = localize('objectExplorer.cancelButtonText', "Cancel");
const ClearAllButtonText = localize('objectExplorer.clearAllButtonText', "Clear All");
const TitleIconClass: string = 'icon filterLabel';
// strings for filter operator select box
const EQUALS_SELECT_BOX = localize('objectExplorer.equalsSelectBox', "Equals");
const NOT_EQUALS_SELECT_BOX = localize('objectExplorer.notEqualsSelectBox', "Not Equals");
const LESS_THAN_SELECT_BOX = localize('objectExplorer.lessThanSelectBox', "Less Than");
const LESS_THAN_OR_EQUALS_SELECT_BOX = localize('objectExplorer.lessThanOrEqualsSelectBox', "Less Than Or Equals");
const GREATER_THAN_SELECT_BOX = localize('objectExplorer.greaterThanSelectBox', "Greater Than");
const GREATER_THAN_OR_EQUALS_SELECT_BOX = localize('objectExplorer.greaterThanOrEqualsSelectBox', "Greater Than Or Equals");
const BETWEEN_SELECT_BOX = localize('objectExplorer.betweenSelectBox', "Between");
const NOT_BETWEEN_SELECT_BOX = localize('objectExplorer.notBetweenSelectBox', "Not Between");
const CONTAINS_SELECT_BOX = localize('objectExplorer.containsSelectBox', "Contains");
const NOT_CONTAINS_SELECT_BOX = localize('objectExplorer.notContainsSelectBox', "Not Contains");
const AND_SELECT_BOX = localize('objectExplorer.andSelectBox', "And");
const IS_NULL_SELECT_BOX = localize('objectExplorer.isNullSelectBox', "Is Null");
const IS_NOT_NULL_SELECT_BOX = localize('objectExplorer.isNotNullSelectBox', "Is Not Null");
// strings for filter table column headers
const PROPERTY_NAME_COLUMN_HEADER = localize('objectExplorer.propertyNameColumnHeader', "Property");
const OPERATOR_COLUMN_HEADER = localize('objectExplorer.operatorColumnHeader', "Operator");
const VALUE_COLUMN_HEADER = localize('objectExplorer.valueColumnHeader', "Value");
const CLEAR_COLUMN_HEADER = localize('objectExplorer.clearColumnHeader', "Clear");
// strings for value select box for boolean type filters
const TRUE_SELECT_BOX = localize('objectExplorer.trueSelectBox', "True");
const FALSE_SELECT_BOX = localize('objectExplorer.falseSelectBox', "False");
function nodePathDisplayString(nodepath: string): string { return localize('objectExplorer.nodePath', "Node Path: {0}", nodepath) }
const PROPERTY_COLUMN_ID = 'property';
const OPERATOR_COLUMN_ID = 'operator';
const VALUE_COLUMN_ID = 'value';
const CLEAR_COLUMN_ID = 'clear';
export class FilterDialog extends Modal {
private _okButton?: Button;
private _cancelButton?: Button;
private _clearAllButton?: Button;
private filterTable: Table<Slick.SlickData>;
private _tableCellEditorFactory: TableCellEditorFactory;
private _onStyleChangeEventEmitter = new Emitter<void>();
private _description: HTMLElement;
private _onFilterApplied = new Emitter<azdata.NodeFilter[]>();
public readonly onFilterApplied = this._onFilterApplied.event;
private _onCloseEvent = new Emitter<void>();
public readonly onDialogClose = this._onCloseEvent.event;
constructor(
private _properties: azdata.NodeFilterProperty[],
private _filterDialogTitle: string,
private _filterDialogSubtitle: string,
private _appliedFilters: azdata.NodeFilter[],
private applyFilterAction: (filters: azdata.NodeFilter[]) => Promise<void> | undefined,
@IThemeService themeService: IThemeService,
@IAdsTelemetryService telemetryService: IAdsTelemetryService,
@ILayoutService layoutService: ILayoutService,
@IClipboardService clipboardService: IClipboardService,
@ILogService logService: ILogService,
@ITextResourcePropertiesService textResourcePropertiesService: ITextResourcePropertiesService,
@IContextKeyService contextKeyService: IContextKeyService,
@IContextViewService private readonly _contextViewProvider: IContextViewService,
@IAccessibilityService private readonly _accessibilityService: IAccessibilityService,
@IQuickInputService private readonly _quickInputService: IQuickInputService,
@IErrorMessageService private _errorMessageService: IErrorMessageService,
) {
super(
'ObjectExplorerServiceDialog',
'Object Explorer Service Dialog',
telemetryService,
layoutService,
clipboardService,
themeService,
logService,
textResourcePropertiesService,
contextKeyService,
{
dialogStyle: 'normal',
hasTitleIcon: true,
hasSpinner: true
}
);
}
public open(): void {
this.render();
this.show();
this._okButton.focus();
}
public override render() {
super.render();
this.title = this._filterDialogTitle;
this.titleIconClassName = TitleIconClass;
this._register(attachModalDialogStyler(this, this._themeService));
this._okButton = this.addFooterButton(OkButtonText, async () => { await this.onApply() });
this._cancelButton = this.addFooterButton(CancelButtonText, () => { this.onClose() });
this._clearAllButton = this.addFooterButton(ClearAllButtonText, () => { this.onClearAll() }, 'left', true);
this._register(attachButtonStyler(this._okButton, this._themeService));
this._register(attachButtonStyler(this._cancelButton, this._themeService));
this._register(attachButtonStyler(this._clearAllButton, this._themeService));
}
protected renderBody(container: HTMLElement): void {
const body = DOM.append(container, DOM.$('.filter-dialog-body'));
const subtitle = DOM.append(body, DOM.$('.filter-dialog-node-path'));
subtitle.innerText = nodePathDisplayString(this._filterDialogSubtitle);
const clauseTableContainer = DOM.append(body, DOM.$('.filter-table-container'));
const filter = DOM.append(clauseTableContainer, DOM.$('.filter-table'));
this._tableCellEditorFactory = new TableCellEditorFactory(
{
valueGetter: (item, column): string => {
// if the operator is And and the operator is date, we need to get the date from the previous
// row to make it more user friendly for the user to enter the next value.
if (column.field === VALUE_COLUMN_ID && item[OPERATOR_COLUMN_ID].value === AND_SELECT_BOX) {
const index = item.filterPropertyIndex;
const tableData = this.filterTable.getData().getItems();
if (this._properties[index].type === NodeFilterPropertyDataType.Date) {
let value1 = '';
for (let i = 0; i < tableData.length; i++) {
if (tableData[i].filterPropertyIndex === index) {
value1 = tableData[i].value.value;
break;
}
}
const value2 = item[column.field].value;
return value2 === '' ? value1 : value2;
}
}
return item[column.field].value;
},
valueSetter: (context: any, row: number, item: any, column: Slick.Column<Slick.SlickData>, value: string): void => {
item[column.field].value = value;
if (column.field === 'operator') {
const index = item.filterPropertyIndex;
const nodeOperator = this._properties[index].type;
if (nodeOperator === NodeFilterPropertyDataType.Date || nodeOperator === NodeFilterPropertyDataType.Number) {
if (value === BETWEEN_SELECT_BOX || value === NOT_BETWEEN_SELECT_BOX) {
const tableData = this.filterTable.getData().getItems();
if (tableData.length > row + 1) {
if (tableData[row + 1].operator.value === AND_SELECT_BOX) {
return;
}
}
const newRow: Slick.SlickData = {
property: {
value: ''
},
operator: {
value: AND_SELECT_BOX,
values: [AND_SELECT_BOX]
},
value: {
value: '',
values: []
},
filterPropertyIndex: tableData[row].filterPropertyIndex
};
const activeElement = this.filterTable.activeCell;
tableData.splice(row + 1, 0, newRow);
dataProvider.clear();
dataProvider.push(tableData);
this.filterTable.rerenderGrid();
this.filterTable.layout(new DOM.Dimension(600, (dataProvider.getItems().length + 2) * TableRowHeight));
this.filterTable.setActiveCell(activeElement.row, activeElement.cell);
} else {
const tableData = this.filterTable.getData().getItems();
if (tableData.length > row + 1) {
if (tableData[row + 1].operator.value === AND_SELECT_BOX) {
const activeElement = this.filterTable.activeCell;
tableData.splice(row + 1, 1);
dataProvider.clear();
dataProvider.push(tableData);
this.filterTable.rerenderGrid();
this.filterTable.layout(new DOM.Dimension(600, (dataProvider.getItems().length + 2) * TableRowHeight));
this.filterTable.setActiveCell(activeElement.row, activeElement.cell);
}
}
}
}
}
},
optionsGetter: (item, column): string[] => {
return item[column.field].values;
},
editorStyler: (component) => {
this.styleComponent(component);
},
onStyleChange: this._onStyleChangeEventEmitter.event
}, this._contextViewProvider
);
const columns: Slick.Column<Slick.SlickData>[] = [
{
id: PROPERTY_COLUMN_ID,
name: PROPERTY_NAME_COLUMN_HEADER,
field: PROPERTY_COLUMN_ID,
formatter: textFormatter,
width: 180,
},
{
id: OPERATOR_COLUMN_ID,
name: OPERATOR_COLUMN_HEADER,
editor: this._tableCellEditorFactory.getDropdownEditorClass(this, [], false),
field: OPERATOR_COLUMN_ID,
formatter: textFormatter,
width: 180
},
{
id: VALUE_COLUMN_ID,
name: VALUE_COLUMN_HEADER,
width: 180,
formatter: textFormatter,
field: VALUE_COLUMN_ID
}
];
const clearValueColumn = new ButtonColumn({
id: CLEAR_COLUMN_ID,
iconCssClass: 'icon erase',
name: CLEAR_COLUMN_HEADER,
title: CLEAR_COLUMN_HEADER,
width: 60,
resizable: true,
isFontIcon: true
});
this._register(clearValueColumn.onClick(e => {
const row = e.row;
const data = this.filterTable.getData().getItems();
data[row][VALUE_COLUMN_ID].value = '';
dataProvider.clear();
dataProvider.push(data);
this.filterTable.rerenderGrid();
}));
columns.push(clearValueColumn.definition);
const tableData: Slick.SlickData[] = [];
if (!this._appliedFilters) {
this._appliedFilters = [];
}
this._properties.forEach((f, i) => {
const appliedFilter = this._appliedFilters.find(filter => filter.displayName === f.displayName);
const filterOperators = this.getOperatorsForType(f.type);
const row: Slick.SlickData = {
property: {
value: f.displayName
},
operator: {
value: appliedFilter ? this.getFilterOperatorString(appliedFilter.operator) : filterOperators[0],
values: filterOperators
},
value: {
value: appliedFilter ? this.getStringValueForFilter(f, appliedFilter.value) : '',
values: this.getChoiceValuesForFilterProperties(f)
},
filterPropertyIndex: i
};
tableData.push(row);
if (appliedFilter?.operator === NodeFilterOperator.Between || appliedFilter?.operator === NodeFilterOperator.NotBetween) {
row.value.value = this.getStringValueForFilter(f, appliedFilter.value[0]);
const andRow: Slick.SlickData = {
property: {
value: ''
},
operator: {
value: AND_SELECT_BOX,
values: [AND_SELECT_BOX]
},
value: {
value: this.getStringValueForFilter(f, appliedFilter.value[1]),
values: []
},
datatype: f.type,
filterPropertyIndex: i
};
tableData.push(andRow);
}
});
const dataProvider = new TableDataView<Slick.SlickData>();
dataProvider.push(tableData);
// Sets up the editor for the value column
(<any>dataProvider).getItemMetadata = (row: number) => {
const rowData = dataProvider.getItem(row);
const filterProperty = this._properties[rowData.filterPropertyIndex];
let editor;
if (rowData.operator.value === AND_SELECT_BOX) {
if (filterProperty.type === NodeFilterPropertyDataType.Number) {
editor = this._tableCellEditorFactory.getTextEditorClass(this, 'number');
} else if (filterProperty.type === NodeFilterPropertyDataType.Date) {
editor = this._tableCellEditorFactory.getTextEditorClass(this, 'date');
}
} else {
if (filterProperty.type === NodeFilterPropertyDataType.String) {
editor = this._tableCellEditorFactory.getTextEditorClass(this, 'text');
} else if (filterProperty.type === NodeFilterPropertyDataType.Date) {
editor = this._tableCellEditorFactory.getTextEditorClass(this, 'date');
} else if (filterProperty.type === NodeFilterPropertyDataType.Boolean) {
editor = this._tableCellEditorFactory.getDropdownEditorClass(this, [TRUE_SELECT_BOX, FALSE_SELECT_BOX], false);
} else if (filterProperty.type === NodeFilterPropertyDataType.Number) {
editor = this._tableCellEditorFactory.getTextEditorClass(this, 'number');
} else if (filterProperty.type === NodeFilterPropertyDataType.Choice) {
editor = this._tableCellEditorFactory.getDropdownEditorClass(this, this.getDropdownOptionsForChoiceProperty(<azdata.NodeFilterChoiceProperty>filterProperty), false);
}
}
return {
columns: {
value: {
editor: editor
}
}
};
}
this.filterTable = new Table(filter, this._accessibilityService, this._quickInputService, {
dataProvider: dataProvider!,
columns: columns,
}, {
editable: true,
autoEdit: true,
dataItemColumnValueExtractor: (data: any, column: Slick.Column<Slick.SlickData>): string => {
if (column.field) {
return data[column.field]?.value;
} else {
return undefined;
}
},
rowHeight: TableRowHeight,
headerRowHeight: TableHeaderRowHeight,
editorLock: new Slick.EditorLock(),
autoHeight: true,
});
this.filterTable.grid.onActiveCellChanged.subscribe((e, any) => {
if (this.filterTable.grid.getActiveCell()) {
const row = this.filterTable.grid.getActiveCell().row;
const data = this.filterTable.getData().getItems()[row];
let index = data.filterPropertyIndex;
const filterPropertyDescription = this._properties[index].description;
this._description.innerText = filterPropertyDescription;
// Announcing the filter property description for screen reader users
status(filterPropertyDescription);
}
});
this.filterTable.registerPlugin(clearValueColumn);
this.filterTable.layout(new DOM.Dimension(600, (tableData.length + 2) * TableRowHeight));
this._register(attachTableStyler(this.filterTable, this._themeService));
this._description = DOM.append(body, DOM.$('.filter-dialog-description'));
this._description.innerHTML = this._properties[0].description;
}
protected layout(height?: number): void {
// noop
}
protected override onClose() {
this.hide('close');
this._onCloseEvent.fire();
}
protected onClearAll() {
const tableAllData = this.filterTable.getData().getItems();
tableAllData.forEach((row) => {
row.value.value = '';
});
this.filterTable.rerenderGrid();
}
// This method is called when the ok button is pressed
private async onApply(): Promise<void> {
const tableData = this.filterTable.getData().getItems();
this._appliedFilters = [];
for (let i = 0; i < tableData.length; i++) {
const row = tableData[i];
let filterProperty = this._properties[row.filterPropertyIndex]
let filter: azdata.NodeFilter = {
displayName: row.property.value,
operator: this.getFilterOperatorEnum(row.operator.value),
value: this.getFilterValue(filterProperty.type, row.value.value, filterProperty),
};
const isMultipleValueFilter = filter.operator === NodeFilterOperator.Between || filter.operator === NodeFilterOperator.NotBetween;
if (isMultipleValueFilter) {
i++;
const row2 = tableData[i];
var value1 = this.getFilterValue(filterProperty.type, row.value.value, filterProperty);
var value2 = this.getFilterValue(filterProperty.type, row2.value.value, filterProperty);
filter.value = <string[] | number[]>[value1, value2];
if (filterProperty.type === NodeFilterPropertyDataType.Date) {
if (filter.value[0] === '' && filter.value[1] !== '') {
// start date not specified.
this._errorMessageService.showDialog(Severity.Error, '', localize('filterDialog.errorStartDate', "Start date is not specified."));
return;
} else if (filter.value[0] !== '' && filter.value[1] === '') {
// end date not specified.
this._errorMessageService.showDialog(Severity.Error, '', localize('filterDialog.errorEndDate', "End date is not specified."));
return;
} else if (new Date(filter.value[0]) > new Date(filter.value[1])) {
// start date is greater than end date.
this._errorMessageService.showDialog(Severity.Error, '', localize('filterDialog.errorDateRange', "Start date cannot be greater than end date."));
return;
}
} else if (filterProperty.type === NodeFilterPropertyDataType.Number) {
if (filter.value[0] === '' && filter.value[1] !== '') {
// start number not specified.
this._errorMessageService.showDialog(Severity.Error, '', localize('filterDialog.errorStartNumber', "Start number is not specified."));
return;
} else if (filter.value[0] !== '' && filter.value[1] === '') {
// end number not specified.
this._errorMessageService.showDialog(Severity.Error, '', localize('filterDialog.errorEndNumber', "End number is not specified."));
return;
} else if (Number(filter.value[0]) > Number(filter.value[1])) {
// start number is greater than end number.
this._errorMessageService.showDialog(Severity.Error, '', localize('filterDialog.errorNumberRange', "Start number cannot be greater than end number."));
return;
}
}
if (value1 !== '' && value2 !== '') {
this._appliedFilters.push(filter);
}
} else {
if (filter.value !== '') {
this._appliedFilters.push(filter);
}
}
}
this.spinner = true;
try {
if (this.applyFilterAction) {
await this.applyFilterAction(this._appliedFilters);
}
this._onFilterApplied.fire(this._appliedFilters);
this.hide('ok');
}
catch (e) {
this.spinner = false;
throw e;
}
}
// This method is called by modal when the enter button is pressed
// We override it to do nothing so that the enter button doesn't close the dialog
protected override async onAccept() {
// noop
}
private getFilterValue(
filterType: NodeFilterPropertyDataType,
value: string,
filterProperty: azdata.NodeFilterProperty
): string | number | boolean {
if (value === '') {
return '';
}
switch (filterType) {
case NodeFilterPropertyDataType.Boolean:
if (value === TRUE_SELECT_BOX) {
return true;
} else if (value === FALSE_SELECT_BOX) {
return false;
}
case NodeFilterPropertyDataType.Number:
return Number(value);
case NodeFilterPropertyDataType.Choice:
const choice = ((<azdata.NodeFilterChoiceProperty>filterProperty).choices.find(c => c.displayName === value));
if (choice) {
return choice.value;
} else {
return value;
}
case NodeFilterPropertyDataType.Date:
case NodeFilterPropertyDataType.String:
return value;
}
}
private getStringValueForFilter(filter: azdata.NodeFilterProperty, value: string | number | boolean | number[] | string[]): string {
switch (filter.type) {
case NodeFilterPropertyDataType.Boolean:
if (value === true) {
return TRUE_SELECT_BOX;
} else if (value === false) {
return FALSE_SELECT_BOX;
}
break;
case NodeFilterPropertyDataType.Number:
return value.toString();
case NodeFilterPropertyDataType.Choice:
return (<azdata.NodeFilterChoiceProperty>filter).choices.find(c => c.value === value).displayName;
case NodeFilterPropertyDataType.Date:
case NodeFilterPropertyDataType.String:
return value as string;
}
return '';
}
private getOperatorsForType(type: NodeFilterPropertyDataType): string[] {
switch (type) {
case NodeFilterPropertyDataType.String:
return [
CONTAINS_SELECT_BOX,
NOT_CONTAINS_SELECT_BOX,
EQUALS_SELECT_BOX,
NOT_EQUALS_SELECT_BOX
];
case NodeFilterPropertyDataType.Number:
return [
EQUALS_SELECT_BOX,
NOT_EQUALS_SELECT_BOX,
GREATER_THAN_SELECT_BOX,
GREATER_THAN_OR_EQUALS_SELECT_BOX,
LESS_THAN_SELECT_BOX,
LESS_THAN_OR_EQUALS_SELECT_BOX,
BETWEEN_SELECT_BOX,
NOT_BETWEEN_SELECT_BOX
];
case NodeFilterPropertyDataType.Boolean:
return [
EQUALS_SELECT_BOX,
NOT_EQUALS_SELECT_BOX
];
case NodeFilterPropertyDataType.Choice:
return [
EQUALS_SELECT_BOX,
NOT_EQUALS_SELECT_BOX
];
case NodeFilterPropertyDataType.Date:
return [
EQUALS_SELECT_BOX,
NOT_EQUALS_SELECT_BOX,
GREATER_THAN_SELECT_BOX,
GREATER_THAN_OR_EQUALS_SELECT_BOX,
LESS_THAN_SELECT_BOX,
LESS_THAN_OR_EQUALS_SELECT_BOX,
BETWEEN_SELECT_BOX,
NOT_BETWEEN_SELECT_BOX
];
}
}
private getFilterOperatorString(operator: NodeFilterOperator): string {
switch (operator) {
case NodeFilterOperator.Contains:
return CONTAINS_SELECT_BOX;
case NodeFilterOperator.NotContains:
return NOT_CONTAINS_SELECT_BOX;
case NodeFilterOperator.Equals:
return EQUALS_SELECT_BOX;
case NodeFilterOperator.NotEquals:
return NOT_EQUALS_SELECT_BOX;
case NodeFilterOperator.GreaterThan:
return GREATER_THAN_SELECT_BOX;
case NodeFilterOperator.GreaterThanOrEquals:
return GREATER_THAN_OR_EQUALS_SELECT_BOX;
case NodeFilterOperator.LessThan:
return LESS_THAN_SELECT_BOX;
case NodeFilterOperator.LessThanOrEquals:
return LESS_THAN_OR_EQUALS_SELECT_BOX;
case NodeFilterOperator.Between:
return BETWEEN_SELECT_BOX;
case NodeFilterOperator.NotBetween:
return NOT_BETWEEN_SELECT_BOX;
case NodeFilterOperator.IsNull:
return IS_NULL_SELECT_BOX;
case NodeFilterOperator.IsNotNull:
return IS_NOT_NULL_SELECT_BOX;
default:
return '';
}
}
private getFilterOperatorEnum(operator: string): NodeFilterOperator {
switch (operator) {
case CONTAINS_SELECT_BOX:
return NodeFilterOperator.Contains;
case NOT_CONTAINS_SELECT_BOX:
return NodeFilterOperator.NotContains;
case EQUALS_SELECT_BOX:
return NodeFilterOperator.Equals;
case NOT_EQUALS_SELECT_BOX:
return NodeFilterOperator.NotEquals;
case GREATER_THAN_SELECT_BOX:
return NodeFilterOperator.GreaterThan;
case GREATER_THAN_OR_EQUALS_SELECT_BOX:
return NodeFilterOperator.GreaterThanOrEquals;
case LESS_THAN_SELECT_BOX:
return NodeFilterOperator.LessThan;
case LESS_THAN_OR_EQUALS_SELECT_BOX:
return NodeFilterOperator.LessThanOrEquals;
case BETWEEN_SELECT_BOX:
return NodeFilterOperator.Between;
case NOT_BETWEEN_SELECT_BOX:
return NodeFilterOperator.NotBetween;
case TRUE_SELECT_BOX:
return NodeFilterOperator.Equals;
case FALSE_SELECT_BOX:
return NodeFilterOperator.NotEquals;
default:
return undefined;
}
}
private getChoiceValuesForFilterProperties(f: azdata.NodeFilterProperty): string[] {
switch (f.type) {
case NodeFilterPropertyDataType.Boolean:
return ['', TRUE_SELECT_BOX, FALSE_SELECT_BOX];
case NodeFilterPropertyDataType.Choice:
return ['', ...this.getDropdownOptionsForChoiceProperty(<azdata.NodeFilterChoiceProperty>f)];
default:
return [];
}
}
private getDropdownOptionsForChoiceProperty(f: azdata.NodeFilterChoiceProperty): string[] {
return f.choices.map(choice => {
return choice.displayName ?? choice.value;
});
}
private styleComponent(component: TabbedPanel | InputBox | Checkbox | Table<Slick.SlickData> | SelectBox | Button | Dropdown): void {
if (component instanceof InputBox) {
this._register(attachInputBoxStyler(component, this._themeService));
} else if (component instanceof SelectBox) {
this._register(attachSelectBoxStyler(component, this._themeService));
} else if (component instanceof Table) {
this._register(attachTableStyler(component, this._themeService));
}
}
/**
* This method is used to let user apply filters on the given filters properties.
* @param properties Properties on which user can apply filters.
* @param filterDialogTitle Title of the filter dialog.
* @param filterDialogSubtile Subtitle of the filter dialog.
* @param appliedFilters Filters that are already applied so that we can prepopulate the filter dialog values.
* @param applyFilterAction Action to be performed when user clicks on apply button. We should pass this so that we can handle the spinner and error message within the dialog.
* @param instantiationService Instantiation service to create the filter dialog.
* @returns
*/
public static async getFiltersForProperties(
properties: azdata.NodeFilterProperty[],
filterDialogTitle: string,
filterDialogSubtile: string,
appliedFilters: azdata.NodeFilter[] | undefined,
applyFilterAction: (filters: azdata.NodeFilter[]) => Promise<void> | undefined,
instantiationService: IInstantiationService,
): Promise<azdata.NodeFilter[]> {
const dialog = instantiationService.createInstance(FilterDialog, properties, filterDialogTitle, filterDialogSubtile, appliedFilters, applyFilterAction);
dialog.open();
return new Promise<azdata.NodeFilter[]>((resolve, reject) => {
dialog.onFilterApplied(filters => {
resolve(filters);
});
dialog.onDialogClose(() => {
reject();
});
});
}
}

View File

@@ -0,0 +1,3 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 2048 2048">
<path fill="#fff" d="M1115 1792h421v128H453L50 1516q-24-24-37-56t-13-68q0-35 13-67t38-58L1248 69l794 795-927 928zm133-1542L538 960l614 613 709-709-613-614zM933 1792l128-128-613-614-306 307q-14 14-14 35t14 35l364 365h427z" />
</svg>

After

Width:  |  Height:  |  Size: 299 B

Some files were not shown because too many files have changed in this diff Show More