@theia/ai-scanoss 1.58.3 → 1.59.0-next.72
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/lib/browser/ai-scanoss-code-scan-action.d.ts +2 -2
- package/lib/browser/ai-scanoss-code-scan-action.d.ts.map +1 -1
- package/lib/browser/ai-scanoss-code-scan-action.js +26 -30
- package/lib/browser/ai-scanoss-code-scan-action.js.map +1 -1
- package/lib/browser/ai-scanoss-frontend-module.d.ts +1 -1
- package/lib/browser/ai-scanoss-frontend-module.d.ts.map +1 -1
- package/lib/browser/ai-scanoss-frontend-module.js +5 -1
- package/lib/browser/ai-scanoss-frontend-module.js.map +1 -1
- package/lib/browser/ai-scanoss-preferences.d.ts.map +1 -1
- package/lib/browser/ai-scanoss-preferences.js +6 -5
- package/lib/browser/ai-scanoss-preferences.js.map +1 -1
- package/lib/browser/change-set-scan-action/change-set-scan-action.d.ts +28 -0
- package/lib/browser/change-set-scan-action/change-set-scan-action.d.ts.map +1 -0
- package/lib/browser/change-set-scan-action/change-set-scan-action.js +214 -0
- package/lib/browser/change-set-scan-action/change-set-scan-action.js.map +1 -0
- package/package.json +10 -8
- package/src/browser/ai-scanoss-code-scan-action.tsx +41 -41
- package/src/browser/ai-scanoss-frontend-module.ts +5 -1
- package/src/browser/ai-scanoss-preferences.ts +7 -5
- package/src/browser/change-set-scan-action/change-set-scan-action.tsx +249 -0
- package/src/browser/style/index.css +37 -0
|
@@ -15,9 +15,9 @@ export declare class ScanOSSScanButtonAction implements CodePartRendererAction {
|
|
|
15
15
|
render(response: CodeChatResponseContent, parentNode: ResponseNode): ReactNode;
|
|
16
16
|
}
|
|
17
17
|
export declare class ScanOSSDialog extends ReactDialog<void> {
|
|
18
|
-
protected
|
|
18
|
+
protected results: ScanOSSResultMatch[];
|
|
19
19
|
protected readonly okButton: HTMLButtonElement;
|
|
20
|
-
constructor(
|
|
20
|
+
constructor(results: ScanOSSResultMatch[]);
|
|
21
21
|
protected render(): React.ReactNode;
|
|
22
22
|
protected renderHeader(): React.ReactNode;
|
|
23
23
|
protected renderSummary(): React.ReactNode;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ai-scanoss-code-scan-action.d.ts","sourceRoot":"","sources":["../../src/browser/ai-scanoss-code-scan-action.tsx"],"names":[],"mappings":";AAgBA,OAAO,EAAE,uBAAuB,EAAE,MAAM,gBAAgB,CAAC;AACzD,OAAO,EAAE,sBAAsB,EAAE,MAAM,sDAAsD,CAAC;AAC9F,OAAO,EAEH,kBAAkB,EAClB,cAAc,EACjB,MAAM,gBAAgB,CAAC;AACxB,OAAO,EAAU,iBAAiB,EAAE,MAAM,yBAAyB,CAAC;AACpE,OAAO,EAAE,SAAS,EAAE,MAAM,0BAA0B,CAAC;AACrD,OAAO,EAAE,YAAY,EAAE,MAAM,8CAA8C,CAAC;AAC5E,OAAO,KAAK,KAAK,MAAM,0BAA0B,CAAC;AAClD,OAAO,EAAE,WAAW,EAAE,MAAM,8CAA8C,CAAC;
|
|
1
|
+
{"version":3,"file":"ai-scanoss-code-scan-action.d.ts","sourceRoot":"","sources":["../../src/browser/ai-scanoss-code-scan-action.tsx"],"names":[],"mappings":";AAgBA,OAAO,EAAE,uBAAuB,EAAE,MAAM,gBAAgB,CAAC;AACzD,OAAO,EAAE,sBAAsB,EAAE,MAAM,sDAAsD,CAAC;AAC9F,OAAO,EAEH,kBAAkB,EAClB,cAAc,EACjB,MAAM,gBAAgB,CAAC;AACxB,OAAO,EAAU,iBAAiB,EAAE,MAAM,yBAAyB,CAAC;AACpE,OAAO,EAAE,SAAS,EAAE,MAAM,0BAA0B,CAAC;AACrD,OAAO,EAAE,YAAY,EAAE,MAAM,8CAA8C,CAAC;AAC5E,OAAO,KAAK,KAAK,MAAM,0BAA0B,CAAC;AAClD,OAAO,EAAE,WAAW,EAAE,MAAM,8CAA8C,CAAC;AAkB3E,qBACa,uBAAwB,YAAW,sBAAsB;IAElE,SAAS,CAAC,QAAQ,CAAC,WAAW,EAAE,cAAc,CAAC;IAE/C,SAAS,CAAC,QAAQ,CAAC,iBAAiB,EAAE,iBAAiB,CAAC;IAExD,QAAQ,SAAM;IAEd,SAAS,CAAC,QAAQ,EAAE,uBAAuB,EAAE,UAAU,EAAE,YAAY,GAAG,OAAO;IAkB/E,MAAM,CACF,QAAQ,EAAE,uBAAuB,EACjC,UAAU,EAAE,YAAY,GACzB,SAAS;CAcf;AAiFD,qBAAa,aAAc,SAAQ,WAAW,CAAC,IAAI,CAAC;IAGpC,SAAS,CAAC,OAAO,EAAE,kBAAkB,EAAE;IAFnD,SAAS,CAAC,QAAQ,CAAC,QAAQ,EAAE,iBAAiB,CAAC;gBAEzB,OAAO,EAAE,kBAAkB,EAAE;IAQnD,SAAS,CAAC,MAAM,IAAI,KAAK,CAAC,SAAS;IAUnC,SAAS,CAAC,YAAY,IAAI,KAAK,CAAC,SAAS;IAWzC,SAAS,CAAC,aAAa,IAAI,KAAK,CAAC,SAAS;IAW1C,SAAS,CAAC,aAAa,IAAI,KAAK,CAAC,SAAS;IAkB1C,IAAI,KAAK,IAAI,SAAS,CAErB;CACJ"}
|
|
@@ -24,6 +24,7 @@ const React = require("@theia/core/shared/react");
|
|
|
24
24
|
const react_dialog_1 = require("@theia/core/lib/browser/dialogs/react-dialog");
|
|
25
25
|
const scanoss_preferences_1 = require("@theia/scanoss/lib/browser/scanoss-preferences");
|
|
26
26
|
const ai_scanoss_preferences_1 = require("./ai-scanoss-preferences");
|
|
27
|
+
const core_1 = require("@theia/core");
|
|
27
28
|
function hasScanOSSResults(data) {
|
|
28
29
|
return 'scanOSSResults' in data && data.scanOSSResults instanceof Map;
|
|
29
30
|
}
|
|
@@ -93,43 +94,42 @@ const ScanOSSIntegration = React.memo((props) => {
|
|
|
93
94
|
scanResult = await scanCode();
|
|
94
95
|
}
|
|
95
96
|
if (scanResult && scanResult.type === 'match') {
|
|
96
|
-
const dialog = new ScanOSSDialog(scanResult);
|
|
97
|
+
const dialog = new ScanOSSDialog([scanResult]);
|
|
97
98
|
dialog.open();
|
|
98
99
|
}
|
|
99
100
|
}, [scanOSSResult]);
|
|
100
101
|
let title = 'SCANOSS - Perform scan';
|
|
101
102
|
if (scanOSSResult) {
|
|
102
103
|
if (scanOSSResult === 'pending') {
|
|
103
|
-
title = 'SCANOSS - Performing scan...';
|
|
104
|
+
title = core_1.nls.localize('theia/ai/scanoss/snippet/in-progress', 'SCANOSS - Performing scan...');
|
|
104
105
|
}
|
|
105
106
|
else if (scanOSSResult.type === 'error') {
|
|
106
|
-
title =
|
|
107
|
+
title = core_1.nls.localize('theia/ai/scanoss/snippet/errored', 'SCANOSS - Error - {0}', scanOSSResult.message);
|
|
107
108
|
}
|
|
108
109
|
else if (scanOSSResult.type === 'match') {
|
|
109
|
-
title =
|
|
110
|
+
title = core_1.nls.localize('theia/ai/scanoss/snippet/matched', 'SCANOSS - Found {0} match', scanOSSResult.matched);
|
|
110
111
|
}
|
|
111
112
|
else if (scanOSSResult.type === 'clean') {
|
|
112
|
-
title = 'SCANOSS - No match';
|
|
113
|
+
title = core_1.nls.localize('theia/ai/scanoss/snippet/no-match', 'SCANOSS - No match');
|
|
113
114
|
}
|
|
114
115
|
}
|
|
115
|
-
return (React.createElement(
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
scanOSSResult
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
scanOSSResult.type === 'error' && React.createElement("span", { className: "codicon codicon-error" }))))));
|
|
116
|
+
return (React.createElement("div", { className: `button scanoss-logo show-check icon-container ${scanOSSResult === 'pending'
|
|
117
|
+
? 'pending'
|
|
118
|
+
: scanOSSResult
|
|
119
|
+
? scanOSSResult.type
|
|
120
|
+
: ''}`, title: title, role: "button", onClick: scanOSSClicked },
|
|
121
|
+
React.createElement("div", { className: "codicon codicon-circle placeholder" }),
|
|
122
|
+
scanOSSResult && scanOSSResult !== 'pending' && (React.createElement("span", { className: "status-icon" },
|
|
123
|
+
scanOSSResult.type === 'clean' && React.createElement("span", { className: "codicon codicon-pass-filled" }),
|
|
124
|
+
scanOSSResult.type === 'match' && React.createElement("span", { className: "codicon codicon-warning" }),
|
|
125
|
+
scanOSSResult.type === 'error' && React.createElement("span", { className: "codicon codicon-error" })))));
|
|
126
126
|
});
|
|
127
127
|
class ScanOSSDialog extends react_dialog_1.ReactDialog {
|
|
128
|
-
constructor(
|
|
128
|
+
constructor(results) {
|
|
129
129
|
super({
|
|
130
|
-
title: '
|
|
130
|
+
title: core_1.nls.localize('theia/ai/scanoss/snippet/dialog-header', 'ScanOSS Results'),
|
|
131
131
|
});
|
|
132
|
-
this.
|
|
132
|
+
this.results = results;
|
|
133
133
|
this.appendAcceptButton(browser_1.Dialog.OK);
|
|
134
134
|
this.update();
|
|
135
135
|
}
|
|
@@ -147,20 +147,16 @@ class ScanOSSDialog extends react_dialog_1.ReactDialog {
|
|
|
147
147
|
}
|
|
148
148
|
renderSummary() {
|
|
149
149
|
return (React.createElement("div", { className: "scanoss-summary" },
|
|
150
|
-
React.createElement("h3", null,
|
|
151
|
-
React.createElement("div", null,
|
|
152
|
-
"Found a ",
|
|
153
|
-
this.result.matched,
|
|
154
|
-
" match in",
|
|
155
|
-
' ',
|
|
156
|
-
React.createElement("a", { href: this.result.url, target: "_blank", rel: "noopener noreferrer" }, this.result.url))));
|
|
150
|
+
React.createElement("h3", null, core_1.nls.localize('theia/ai/scanoss/snippet/summary', 'Summary')),
|
|
151
|
+
React.createElement("div", null, core_1.nls.localize('theia/ai/scanoss/snippet/match-count', 'Found {0} match(es)', this.results.length))));
|
|
157
152
|
}
|
|
158
153
|
renderContent() {
|
|
159
154
|
return (React.createElement("div", { className: "scanoss-details" },
|
|
160
|
-
React.createElement("h4", null,
|
|
161
|
-
React.createElement("
|
|
162
|
-
|
|
163
|
-
|
|
155
|
+
React.createElement("h4", null, core_1.nls.localizeByDefault('Details')),
|
|
156
|
+
this.results.map(result => React.createElement("div", { key: result.matched },
|
|
157
|
+
result.file && React.createElement("h4", null, core_1.nls.localize('theia/ai/scanoss/snippet/file-name-heading', 'Match found in {0}', result.file)),
|
|
158
|
+
React.createElement("a", { href: result.url, target: "_blank", rel: "noopener noreferrer" }, result.url),
|
|
159
|
+
React.createElement("pre", null, JSON.stringify(result.raw, undefined, 2))))));
|
|
164
160
|
}
|
|
165
161
|
get value() {
|
|
166
162
|
return undefined;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ai-scanoss-code-scan-action.js","sourceRoot":"","sources":["../../src/browser/ai-scanoss-code-scan-action.tsx"],"names":[],"mappings":";;;;AAAA,gFAAgF;AAChF,yCAAyC;AACzC,EAAE;AACF,2EAA2E;AAC3E,mEAAmE;AACnE,wCAAwC;AACxC,EAAE;AACF,4EAA4E;AAC5E,8EAA8E;AAC9E,6EAA6E;AAC7E,yDAAyD;AACzD,uDAAuD;AACvD,EAAE;AACF,gFAAgF;AAChF,MAAM;AACN,4DAAkE;AAGlE,4CAIwB;AACxB,qDAAoE;AAGpE,kDAAkD;AAClD,+EAA2E;AAC3E,wFAAuF;AACvF,qEAA6D;
|
|
1
|
+
{"version":3,"file":"ai-scanoss-code-scan-action.js","sourceRoot":"","sources":["../../src/browser/ai-scanoss-code-scan-action.tsx"],"names":[],"mappings":"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"}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { ContainerModule } from '@theia/core/shared/inversify';
|
|
2
1
|
import '../../src/browser/style/index.css';
|
|
2
|
+
import { ContainerModule } from '@theia/core/shared/inversify';
|
|
3
3
|
declare const _default: ContainerModule;
|
|
4
4
|
export default _default;
|
|
5
5
|
//# sourceMappingURL=ai-scanoss-frontend-module.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ai-scanoss-frontend-module.d.ts","sourceRoot":"","sources":["../../src/browser/ai-scanoss-frontend-module.ts"],"names":[],"mappings":"AAgBA,OAAO,EAAE,eAAe,EAAE,MAAM,8BAA8B,CAAC
|
|
1
|
+
{"version":3,"file":"ai-scanoss-frontend-module.d.ts","sourceRoot":"","sources":["../../src/browser/ai-scanoss-frontend-module.ts"],"names":[],"mappings":"AAgBA,OAAO,mCAAmC,CAAC;AAC3C,OAAO,EAAE,eAAe,EAAE,MAAM,8BAA8B,CAAC;;AAQ/D,wBAMG"}
|
|
@@ -15,15 +15,19 @@
|
|
|
15
15
|
// SPDX-License-Identifier: EPL-2.0 OR GPL-2.0-only WITH Classpath-exception-2.0
|
|
16
16
|
// *****************************************************************************
|
|
17
17
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
18
|
+
require("../../src/browser/style/index.css");
|
|
18
19
|
const inversify_1 = require("@theia/core/shared/inversify");
|
|
19
20
|
const ai_scanoss_preferences_1 = require("./ai-scanoss-preferences");
|
|
20
21
|
const browser_1 = require("@theia/core/lib/browser");
|
|
21
22
|
const ai_scanoss_code_scan_action_1 = require("./ai-scanoss-code-scan-action");
|
|
22
23
|
const chat_response_renderer_1 = require("@theia/ai-chat-ui/lib/browser/chat-response-renderer");
|
|
23
|
-
require("
|
|
24
|
+
const change_set_action_service_1 = require("@theia/ai-chat-ui/lib/browser/change-set-actions/change-set-action-service");
|
|
25
|
+
const change_set_scan_action_1 = require("./change-set-scan-action/change-set-scan-action");
|
|
24
26
|
exports.default = new inversify_1.ContainerModule(bind => {
|
|
25
27
|
bind(browser_1.PreferenceContribution).toConstantValue({ schema: ai_scanoss_preferences_1.AIScanOSSPreferencesSchema });
|
|
26
28
|
bind(ai_scanoss_code_scan_action_1.ScanOSSScanButtonAction).toSelf().inSingletonScope();
|
|
27
29
|
bind(chat_response_renderer_1.CodePartRendererAction).toService(ai_scanoss_code_scan_action_1.ScanOSSScanButtonAction);
|
|
30
|
+
bind(change_set_scan_action_1.ChangeSetScanActionRenderer).toSelf();
|
|
31
|
+
bind(change_set_action_service_1.ChangeSetActionRenderer).toService(change_set_scan_action_1.ChangeSetScanActionRenderer);
|
|
28
32
|
});
|
|
29
33
|
//# sourceMappingURL=ai-scanoss-frontend-module.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ai-scanoss-frontend-module.js","sourceRoot":"","sources":["../../src/browser/ai-scanoss-frontend-module.ts"],"names":[],"mappings":";AAAA,gFAAgF;AAChF,yCAAyC;AACzC,EAAE;AACF,2EAA2E;AAC3E,mEAAmE;AACnE,wCAAwC;AACxC,EAAE;AACF,4EAA4E;AAC5E,8EAA8E;AAC9E,6EAA6E;AAC7E,yDAAyD;AACzD,uDAAuD;AACvD,EAAE;AACF,gFAAgF;AAChF,gFAAgF;;AAEhF,4DAA+D;AAC/D,qEAAsE;AACtE,qDAAiE;AACjE,+EAAwE;AACxE,iGAA8F;AAC9F,
|
|
1
|
+
{"version":3,"file":"ai-scanoss-frontend-module.js","sourceRoot":"","sources":["../../src/browser/ai-scanoss-frontend-module.ts"],"names":[],"mappings":";AAAA,gFAAgF;AAChF,yCAAyC;AACzC,EAAE;AACF,2EAA2E;AAC3E,mEAAmE;AACnE,wCAAwC;AACxC,EAAE;AACF,4EAA4E;AAC5E,8EAA8E;AAC9E,6EAA6E;AAC7E,yDAAyD;AACzD,uDAAuD;AACvD,EAAE;AACF,gFAAgF;AAChF,gFAAgF;;AAEhF,6CAA2C;AAC3C,4DAA+D;AAC/D,qEAAsE;AACtE,qDAAiE;AACjE,+EAAwE;AACxE,iGAA8F;AAC9F,0HAAqH;AACrH,4FAA8F;AAE9F,kBAAe,IAAI,2BAAe,CAAC,IAAI,CAAC,EAAE;IACtC,IAAI,CAAC,gCAAsB,CAAC,CAAC,eAAe,CAAC,EAAE,MAAM,EAAE,mDAA0B,EAAE,CAAC,CAAC;IACrF,IAAI,CAAC,qDAAuB,CAAC,CAAC,MAAM,EAAE,CAAC,gBAAgB,EAAE,CAAC;IAC1D,IAAI,CAAC,+CAAsB,CAAC,CAAC,SAAS,CAAC,qDAAuB,CAAC,CAAC;IAChE,IAAI,CAAC,oDAA2B,CAAC,CAAC,MAAM,EAAE,CAAC;IAC3C,IAAI,CAAC,mDAAuB,CAAC,CAAC,SAAS,CAAC,oDAA2B,CAAC,CAAC;AACzE,CAAC,CAAC,CAAC"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ai-scanoss-preferences.d.ts","sourceRoot":"","sources":["../../src/browser/ai-scanoss-preferences.ts"],"names":[],"mappings":"AAgBA,OAAO,EAAE,gBAAgB,EAAE,MAAM,qCAAqC,CAAC;
|
|
1
|
+
{"version":3,"file":"ai-scanoss-preferences.d.ts","sourceRoot":"","sources":["../../src/browser/ai-scanoss-preferences.ts"],"names":[],"mappings":"AAgBA,OAAO,EAAE,gBAAgB,EAAE,MAAM,qCAAqC,CAAC;AAIvE,eAAO,MAAM,iBAAiB,6BAA6B,CAAC;AAE5D,eAAO,MAAM,0BAA0B,EAAE,gBAkBxC,CAAC"}
|
|
@@ -17,6 +17,7 @@
|
|
|
17
17
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
18
18
|
exports.AIScanOSSPreferencesSchema = exports.SCANOSS_MODE_PREF = void 0;
|
|
19
19
|
const ai_core_preferences_1 = require("@theia/ai-core/lib/browser/ai-core-preferences");
|
|
20
|
+
const core_1 = require("@theia/core");
|
|
20
21
|
exports.SCANOSS_MODE_PREF = 'ai-features.SCANOSS.mode';
|
|
21
22
|
exports.AIScanOSSPreferencesSchema = {
|
|
22
23
|
type: 'object',
|
|
@@ -25,12 +26,12 @@ exports.AIScanOSSPreferencesSchema = {
|
|
|
25
26
|
type: 'string',
|
|
26
27
|
enum: ['off', 'manual', 'automatic'],
|
|
27
28
|
markdownEnumDescriptions: [
|
|
28
|
-
'Feature is turned off completely.',
|
|
29
|
-
'User can manually trigger the scan by clicking the SCANOSS item in the chat view.',
|
|
30
|
-
'Enable automatic scan of code snippets in chat views.'
|
|
29
|
+
core_1.nls.localize('theia/ai/scanoss/mode/off/description', 'Feature is turned off completely.'),
|
|
30
|
+
core_1.nls.localize('theia/ai/scanoss/mode/manual/description', 'User can manually trigger the scan by clicking the SCANOSS item in the chat view.'),
|
|
31
|
+
core_1.nls.localize('theia/ai/scanoss/mode/automatic/description', 'Enable automatic scan of code snippets in chat views.')
|
|
31
32
|
],
|
|
32
|
-
markdownDescription: 'Configure the SCANOSS feature for analyzing code snippets in chat views. This will send a hash of suggested code snippets to the SCANOSS\n\
|
|
33
|
-
|
|
33
|
+
markdownDescription: core_1.nls.localize('theia/ai/scanoss/mode/description', 'Configure the SCANOSS feature for analyzing code snippets in chat views. This will send a hash of suggested code snippets to the SCANOSS\n\
|
|
34
|
+
service hosted by the [Software Transparency foundation](https://www.softwaretransparency.org/osskb) for analysis.'),
|
|
34
35
|
default: 'off',
|
|
35
36
|
title: ai_core_preferences_1.AI_CORE_PREFERENCES_TITLE
|
|
36
37
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ai-scanoss-preferences.js","sourceRoot":"","sources":["../../src/browser/ai-scanoss-preferences.ts"],"names":[],"mappings":";AAAA,gFAAgF;AAChF,yCAAyC;AACzC,EAAE;AACF,2EAA2E;AAC3E,mEAAmE;AACnE,wCAAwC;AACxC,EAAE;AACF,4EAA4E;AAC5E,8EAA8E;AAC9E,6EAA6E;AAC7E,yDAAyD;AACzD,uDAAuD;AACvD,EAAE;AACF,gFAAgF;AAChF,gFAAgF;;;AAGhF,wFAA2F;
|
|
1
|
+
{"version":3,"file":"ai-scanoss-preferences.js","sourceRoot":"","sources":["../../src/browser/ai-scanoss-preferences.ts"],"names":[],"mappings":";AAAA,gFAAgF;AAChF,yCAAyC;AACzC,EAAE;AACF,2EAA2E;AAC3E,mEAAmE;AACnE,wCAAwC;AACxC,EAAE;AACF,4EAA4E;AAC5E,8EAA8E;AAC9E,6EAA6E;AAC7E,yDAAyD;AACzD,uDAAuD;AACvD,EAAE;AACF,gFAAgF;AAChF,gFAAgF;;;AAGhF,wFAA2F;AAC3F,sCAAkC;AAErB,QAAA,iBAAiB,GAAG,0BAA0B,CAAC;AAE/C,QAAA,0BAA0B,GAAqB;IACxD,IAAI,EAAE,QAAQ;IACd,UAAU,EAAE;QACR,CAAC,yBAAiB,CAAC,EAAE;YACjB,IAAI,EAAE,QAAQ;YACd,IAAI,EAAE,CAAC,KAAK,EAAE,QAAQ,EAAE,WAAW,CAAC;YACpC,wBAAwB,EAAE;gBACtB,UAAG,CAAC,QAAQ,CAAC,uCAAuC,EAAE,mCAAmC,CAAC;gBAC1F,UAAG,CAAC,QAAQ,CAAC,0CAA0C,EAAE,mFAAmF,CAAC;gBAC7I,UAAG,CAAC,QAAQ,CAAC,6CAA6C,EAAE,uDAAuD,CAAC;aACvH;YACD,mBAAmB,EAAE,UAAG,CAAC,QAAQ,CAAC,mCAAmC,EACjE;mHACmG,CAAC;YACxG,OAAO,EAAE,KAAK;YACd,KAAK,EAAE,+CAAyB;SACnC;KACJ;CACJ,CAAC"}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
/// <reference types="react" />
|
|
2
|
+
import * as React from '@theia/core/shared/react';
|
|
3
|
+
import { ChangeSet, ChangeSetElement } from '@theia/ai-chat';
|
|
4
|
+
import { ChangeSetActionRenderer } from '@theia/ai-chat-ui/lib/browser/change-set-actions/change-set-action-service';
|
|
5
|
+
import { PreferenceService } from '@theia/core/lib/browser/preferences';
|
|
6
|
+
import { ScanOSSService, ScanOSSResult } from '@theia/scanoss';
|
|
7
|
+
import { ChangeSetFileElement } from '@theia/ai-chat/lib/browser/change-set-file-element';
|
|
8
|
+
import { IDocumentDiffProvider } from '@theia/monaco-editor-core/esm/vs/editor/common/diff/documentDiffProvider';
|
|
9
|
+
import { MonacoTextModelService } from '@theia/monaco/lib/browser/monaco-text-model-service';
|
|
10
|
+
import { Emitter, MessageService } from '@theia/core';
|
|
11
|
+
export declare class ChangeSetScanActionRenderer implements ChangeSetActionRenderer {
|
|
12
|
+
readonly id = "change-set-scanoss";
|
|
13
|
+
protected readonly onDidChangeEmitter: Emitter<void>;
|
|
14
|
+
readonly onDidChange: import("@theia/core").Event<void>;
|
|
15
|
+
protected readonly scanService: ScanOSSService;
|
|
16
|
+
protected readonly preferenceService: PreferenceService;
|
|
17
|
+
protected readonly textModelService: MonacoTextModelService;
|
|
18
|
+
protected readonly messageService: MessageService;
|
|
19
|
+
protected differ: IDocumentDiffProvider;
|
|
20
|
+
init(): void;
|
|
21
|
+
canRender(_changeSet: ChangeSet): boolean;
|
|
22
|
+
render(changeSet: ChangeSet): React.ReactNode;
|
|
23
|
+
protected getPreferenceValues(): string;
|
|
24
|
+
protected _scan: (changeSetElements: ChangeSetElement[]) => Promise<ScanOSSResult[]>;
|
|
25
|
+
protected runScan(changeSetElements: ChangeSetFileElement[], cache: Map<string, ScanOSSResult>, userTriggered: boolean): Promise<ScanOSSResult[]>;
|
|
26
|
+
protected getScanContent(fileChange: ChangeSetFileElement): Promise<string>;
|
|
27
|
+
}
|
|
28
|
+
//# sourceMappingURL=change-set-scan-action.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"change-set-scan-action.d.ts","sourceRoot":"","sources":["../../../src/browser/change-set-scan-action/change-set-scan-action.tsx"],"names":[],"mappings":";AAgBA,OAAO,KAAK,KAAK,MAAM,0BAA0B,CAAC;AAClD,OAAO,EAAE,SAAS,EAAE,gBAAgB,EAAE,MAAM,gBAAgB,CAAC;AAE7D,OAAO,EAAE,uBAAuB,EAAE,MAAM,4EAA4E,CAAC;AACrH,OAAO,EAAE,iBAAiB,EAAE,MAAM,qCAAqC,CAAC;AACxE,OAAO,EAAE,cAAc,EAAE,aAAa,EAAsB,MAAM,gBAAgB,CAAC;AAGnF,OAAO,EAAE,oBAAoB,EAAE,MAAM,oDAAoD,CAAC;AAI1F,OAAO,EAAE,qBAAqB,EAAE,MAAM,0EAA0E,CAAC;AACjH,OAAO,EAAE,sBAAsB,EAAE,MAAM,qDAAqD,CAAC;AAC7F,OAAO,EAAqB,OAAO,EAAE,cAAc,EAAO,MAAM,aAAa,CAAC;AAK9E,qBACa,2BAA4B,YAAW,uBAAuB;IACvE,QAAQ,CAAC,EAAE,wBAAwB;IACnC,SAAS,CAAC,QAAQ,CAAC,kBAAkB,gBAAuB;IAC5D,QAAQ,CAAC,WAAW,oCAAiC;IAGrD,SAAS,CAAC,QAAQ,CAAC,WAAW,EAAE,cAAc,CAAC;IAG/C,SAAS,CAAC,QAAQ,CAAC,iBAAiB,EAAE,iBAAiB,CAAC;IAGxD,SAAS,CAAC,QAAQ,CAAC,gBAAgB,EAAE,sBAAsB,CAAC;IAG5D,SAAS,CAAC,QAAQ,CAAC,cAAc,EAAE,cAAc,CAAC;IAElD,SAAS,CAAC,MAAM,EAAE,qBAAqB,CAAC;IAGxC,IAAI,IAAI,IAAI;IAMZ,SAAS,CAAC,UAAU,EAAE,SAAS,GAAG,OAAO;IAIzC,MAAM,CAAC,SAAS,EAAE,SAAS,GAAG,KAAK,CAAC,SAAS;IAU7C,SAAS,CAAC,mBAAmB,IAAI,MAAM;IAIvC,SAAS,CAAC,KAAK,EAAE,CAAC,iBAAiB,EAAE,gBAAgB,EAAE,KAAK,OAAO,CAAC,aAAa,EAAE,CAAC,CAAC;cAErE,OAAO,CAAC,iBAAiB,EAAE,oBAAoB,EAAE,EAAE,KAAK,EAAE,GAAG,CAAC,MAAM,EAAE,aAAa,CAAC,EAAE,aAAa,EAAE,OAAO,GAAG,OAAO,CAAC,aAAa,EAAE,CAAC;cA2BvI,cAAc,CAAC,UAAU,EAAE,oBAAoB,GAAG,OAAO,CAAC,MAAM,CAAC;CA+BpF"}
|
|
@@ -0,0 +1,214 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
// *****************************************************************************
|
|
3
|
+
// Copyright (C) 2025 EclipseSource GmbH and others.
|
|
4
|
+
//
|
|
5
|
+
// This program and the accompanying materials are made available under the
|
|
6
|
+
// terms of the Eclipse Public License v. 2.0 which is available at
|
|
7
|
+
// http://www.eclipse.org/legal/epl-2.0.
|
|
8
|
+
//
|
|
9
|
+
// This Source Code may also be made available under the following Secondary
|
|
10
|
+
// Licenses when the conditions for such availability set forth in the Eclipse
|
|
11
|
+
// Public License v. 2.0 are satisfied: GNU General Public License, version 2
|
|
12
|
+
// with the GNU Classpath Exception which is available at
|
|
13
|
+
// https://www.gnu.org/software/classpath/license.html.
|
|
14
|
+
//
|
|
15
|
+
// SPDX-License-Identifier: EPL-2.0 OR GPL-2.0-only WITH Classpath-exception-2.0
|
|
16
|
+
// *****************************************************************************
|
|
17
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
18
|
+
exports.ChangeSetScanActionRenderer = void 0;
|
|
19
|
+
const tslib_1 = require("tslib");
|
|
20
|
+
const React = require("@theia/core/shared/react");
|
|
21
|
+
const inversify_1 = require("@theia/core/shared/inversify");
|
|
22
|
+
const preferences_1 = require("@theia/core/lib/browser/preferences");
|
|
23
|
+
const scanoss_1 = require("@theia/scanoss");
|
|
24
|
+
const ai_scanoss_preferences_1 = require("../ai-scanoss-preferences");
|
|
25
|
+
const scanoss_preferences_1 = require("@theia/scanoss/lib/browser/scanoss-preferences");
|
|
26
|
+
const change_set_file_element_1 = require("@theia/ai-chat/lib/browser/change-set-file-element");
|
|
27
|
+
const ai_scanoss_code_scan_action_1 = require("../ai-scanoss-code-scan-action");
|
|
28
|
+
const standaloneServices_1 = require("@theia/monaco-editor-core/esm/vs/editor/standalone/browser/standaloneServices");
|
|
29
|
+
const diffProviderFactoryService_1 = require("@theia/monaco-editor-core/esm/vs/editor/browser/widget/diffEditor/diffProviderFactoryService");
|
|
30
|
+
const monaco_text_model_service_1 = require("@theia/monaco/lib/browser/monaco-text-model-service");
|
|
31
|
+
const core_1 = require("@theia/core");
|
|
32
|
+
let ChangeSetScanActionRenderer = class ChangeSetScanActionRenderer {
|
|
33
|
+
constructor() {
|
|
34
|
+
this.id = 'change-set-scanoss';
|
|
35
|
+
this.onDidChangeEmitter = new core_1.Emitter();
|
|
36
|
+
this.onDidChange = this.onDidChangeEmitter.event;
|
|
37
|
+
}
|
|
38
|
+
init() {
|
|
39
|
+
this.differ = standaloneServices_1.StandaloneServices.get(diffProviderFactoryService_1.IDiffProviderFactoryService).createDiffProvider({ diffAlgorithm: 'advanced' });
|
|
40
|
+
this._scan = this.runScan.bind(this);
|
|
41
|
+
this.preferenceService.onPreferenceChanged(e => e.affects(ai_scanoss_preferences_1.SCANOSS_MODE_PREF) && this.onDidChangeEmitter.fire());
|
|
42
|
+
}
|
|
43
|
+
canRender(_changeSet) {
|
|
44
|
+
return true;
|
|
45
|
+
}
|
|
46
|
+
render(changeSet) {
|
|
47
|
+
return (React.createElement(ChangeSetScanOSSIntegration, { changeSet: changeSet, scanOssMode: this.getPreferenceValues(), scanChangeSet: this._scan }));
|
|
48
|
+
}
|
|
49
|
+
getPreferenceValues() {
|
|
50
|
+
return this.preferenceService.get(ai_scanoss_preferences_1.SCANOSS_MODE_PREF, 'off');
|
|
51
|
+
}
|
|
52
|
+
async runScan(changeSetElements, cache, userTriggered) {
|
|
53
|
+
const apiKey = this.preferenceService.get(scanoss_preferences_1.SCAN_OSS_API_KEY_PREF, undefined);
|
|
54
|
+
let notifiedError = false;
|
|
55
|
+
const fileResults = await Promise.all(changeSetElements.map(async (fileChange) => {
|
|
56
|
+
if (fileChange.targetState.trim().length === 0) {
|
|
57
|
+
return { type: 'clean' };
|
|
58
|
+
}
|
|
59
|
+
const toScan = await this.getScanContent(fileChange);
|
|
60
|
+
if (!toScan) {
|
|
61
|
+
return { type: 'clean' };
|
|
62
|
+
}
|
|
63
|
+
const cached = cache.get(toScan);
|
|
64
|
+
if (cached) {
|
|
65
|
+
return cached;
|
|
66
|
+
}
|
|
67
|
+
const result = { ...await this.scanService.scanContent(toScan, apiKey), file: fileChange.uri.path.toString() };
|
|
68
|
+
if (result.type !== 'error') {
|
|
69
|
+
cache.set(toScan, result);
|
|
70
|
+
}
|
|
71
|
+
else if (!notifiedError && userTriggered) {
|
|
72
|
+
notifiedError = true;
|
|
73
|
+
this.messageService.warn(core_1.nls.localize('theia/ai/scanoss/changeSet/error-notification', 'ScanOSS error encountered: {0}.', result.message));
|
|
74
|
+
}
|
|
75
|
+
return result;
|
|
76
|
+
}));
|
|
77
|
+
return fileResults;
|
|
78
|
+
}
|
|
79
|
+
async getScanContent(fileChange) {
|
|
80
|
+
if (fileChange.replacements) {
|
|
81
|
+
return fileChange.replacements.map(({ newContent }) => newContent).join('\n\n').trim();
|
|
82
|
+
}
|
|
83
|
+
const textModels = await Promise.all([
|
|
84
|
+
this.textModelService.createModelReference(fileChange.uri),
|
|
85
|
+
this.textModelService.createModelReference(fileChange.changedUri)
|
|
86
|
+
]);
|
|
87
|
+
const [original, changed] = textModels;
|
|
88
|
+
const diff = await this.differ.computeDiff(original.object.textEditorModel, changed.object.textEditorModel, { maxComputationTimeMs: 5000, computeMoves: false, ignoreTrimWhitespace: true }, core_1.CancellationToken.None);
|
|
89
|
+
if (diff.identical) {
|
|
90
|
+
return '';
|
|
91
|
+
}
|
|
92
|
+
const insertions = diff.changes.filter(candidate => !candidate.modified.isEmpty);
|
|
93
|
+
if (insertions.length === 0) {
|
|
94
|
+
return '';
|
|
95
|
+
}
|
|
96
|
+
const changedLinesInSuggestion = insertions.map(change => {
|
|
97
|
+
const range = change.modified.toInclusiveRange();
|
|
98
|
+
return range ? changed.object.textEditorModel.getValueInRange(range) : ''; // In practice, we've filtered out cases where the range would be null already.
|
|
99
|
+
}).join('\n\n');
|
|
100
|
+
textModels.forEach(ref => ref.dispose());
|
|
101
|
+
return changedLinesInSuggestion.trim();
|
|
102
|
+
}
|
|
103
|
+
};
|
|
104
|
+
exports.ChangeSetScanActionRenderer = ChangeSetScanActionRenderer;
|
|
105
|
+
tslib_1.__decorate([
|
|
106
|
+
(0, inversify_1.inject)(scanoss_1.ScanOSSService),
|
|
107
|
+
tslib_1.__metadata("design:type", Object)
|
|
108
|
+
], ChangeSetScanActionRenderer.prototype, "scanService", void 0);
|
|
109
|
+
tslib_1.__decorate([
|
|
110
|
+
(0, inversify_1.inject)(preferences_1.PreferenceService),
|
|
111
|
+
tslib_1.__metadata("design:type", Object)
|
|
112
|
+
], ChangeSetScanActionRenderer.prototype, "preferenceService", void 0);
|
|
113
|
+
tslib_1.__decorate([
|
|
114
|
+
(0, inversify_1.inject)(monaco_text_model_service_1.MonacoTextModelService),
|
|
115
|
+
tslib_1.__metadata("design:type", monaco_text_model_service_1.MonacoTextModelService)
|
|
116
|
+
], ChangeSetScanActionRenderer.prototype, "textModelService", void 0);
|
|
117
|
+
tslib_1.__decorate([
|
|
118
|
+
(0, inversify_1.inject)(core_1.MessageService),
|
|
119
|
+
tslib_1.__metadata("design:type", core_1.MessageService)
|
|
120
|
+
], ChangeSetScanActionRenderer.prototype, "messageService", void 0);
|
|
121
|
+
tslib_1.__decorate([
|
|
122
|
+
(0, inversify_1.postConstruct)(),
|
|
123
|
+
tslib_1.__metadata("design:type", Function),
|
|
124
|
+
tslib_1.__metadata("design:paramtypes", []),
|
|
125
|
+
tslib_1.__metadata("design:returntype", void 0)
|
|
126
|
+
], ChangeSetScanActionRenderer.prototype, "init", null);
|
|
127
|
+
exports.ChangeSetScanActionRenderer = ChangeSetScanActionRenderer = tslib_1.__decorate([
|
|
128
|
+
(0, inversify_1.injectable)()
|
|
129
|
+
], ChangeSetScanActionRenderer);
|
|
130
|
+
const ChangeSetScanOSSIntegration = React.memo(({ changeSet, scanOssMode, scanChangeSet }) => {
|
|
131
|
+
const [scanOSSResult, setScanOSSResult] = React.useState(undefined);
|
|
132
|
+
const cache = React.useRef(new Map());
|
|
133
|
+
const [changeSetElements, setChangeSetElements] = React.useState(() => changeSet.getElements().filter(candidate => candidate instanceof change_set_file_element_1.ChangeSetFileElement));
|
|
134
|
+
React.useEffect(() => {
|
|
135
|
+
if (scanOSSResult === undefined) {
|
|
136
|
+
if (scanOssMode === 'automatic' && scanOSSResult === undefined) {
|
|
137
|
+
setScanOSSResult('pending');
|
|
138
|
+
scanChangeSet(changeSetElements, cache.current, false).then(result => setScanOSSResult(result));
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
}, [scanOssMode, scanOSSResult]);
|
|
142
|
+
React.useEffect(() => {
|
|
143
|
+
const disposable = changeSet.onDidChange(() => {
|
|
144
|
+
setChangeSetElements(changeSet.getElements().filter(candidate => candidate instanceof change_set_file_element_1.ChangeSetFileElement));
|
|
145
|
+
setScanOSSResult(undefined);
|
|
146
|
+
});
|
|
147
|
+
return () => disposable.dispose();
|
|
148
|
+
}, [changeSet]);
|
|
149
|
+
const scanOSSClicked = React.useCallback(async () => {
|
|
150
|
+
if (scanOSSResult === 'pending') {
|
|
151
|
+
return;
|
|
152
|
+
}
|
|
153
|
+
else if (!scanOSSResult || scanOSSResult.some(candidate => candidate.type === 'error')) {
|
|
154
|
+
setScanOSSResult('pending');
|
|
155
|
+
scanChangeSet(changeSetElements, cache.current, true).then(result => setScanOSSResult(result));
|
|
156
|
+
}
|
|
157
|
+
else {
|
|
158
|
+
const matches = scanOSSResult.filter((candidate) => candidate.type === 'match');
|
|
159
|
+
if (matches.length === 0) {
|
|
160
|
+
return;
|
|
161
|
+
}
|
|
162
|
+
const dialog = new ai_scanoss_code_scan_action_1.ScanOSSDialog(matches);
|
|
163
|
+
dialog.open();
|
|
164
|
+
}
|
|
165
|
+
}, [scanOSSResult, changeSetElements]);
|
|
166
|
+
const state = getResult(scanOSSResult);
|
|
167
|
+
const content = getTitle(state);
|
|
168
|
+
const title = `ScanOSS: ${content}`;
|
|
169
|
+
const icon = getIcon(state);
|
|
170
|
+
if (scanOssMode === 'off' || changeSetElements.length === 0) {
|
|
171
|
+
return undefined;
|
|
172
|
+
}
|
|
173
|
+
else if (state === 'clean' || state === 'pending') {
|
|
174
|
+
return React.createElement("div", { className: `theia-button button theia-changeSet-scanOss ${state}`, title: title },
|
|
175
|
+
React.createElement("span", { className: 'scanoss-logo icon-container' }),
|
|
176
|
+
content,
|
|
177
|
+
icon);
|
|
178
|
+
}
|
|
179
|
+
else {
|
|
180
|
+
return React.createElement("button", { className: `theia-button theia-changeSet-scanOss ${state}`, title: title, onClick: scanOSSClicked },
|
|
181
|
+
React.createElement("span", { className: 'scanoss-logo icon-container' }),
|
|
182
|
+
content,
|
|
183
|
+
icon);
|
|
184
|
+
}
|
|
185
|
+
});
|
|
186
|
+
function getResult(scanOSSResult) {
|
|
187
|
+
switch (true) {
|
|
188
|
+
case scanOSSResult === undefined: return 'none';
|
|
189
|
+
case scanOSSResult === 'pending': return 'pending';
|
|
190
|
+
case scanOSSResult.some(candidate => candidate.type === 'error'): return 'error';
|
|
191
|
+
case scanOSSResult.some(candidate => candidate.type === 'match'): return 'match';
|
|
192
|
+
default: return 'clean';
|
|
193
|
+
}
|
|
194
|
+
}
|
|
195
|
+
function getTitle(result) {
|
|
196
|
+
switch (result) {
|
|
197
|
+
case 'none': return core_1.nls.localize('theia/ai/scanoss/changeSet/scan', 'Scan');
|
|
198
|
+
case 'pending': return core_1.nls.localize('theia/ai/scanoss/changeSet/scanning', 'Scanning...');
|
|
199
|
+
case 'error': return core_1.nls.localize('theia/ai/scanoss/changeSet/error', 'Error: Rerun');
|
|
200
|
+
case 'match': return core_1.nls.localize('theia/ai/scanoss/changeSet/view-matches', 'View Matches');
|
|
201
|
+
case 'clean': return core_1.nls.localize('theia/ai/scanoss/changeSet/clean', 'No Matches');
|
|
202
|
+
}
|
|
203
|
+
}
|
|
204
|
+
function getIcon(result) {
|
|
205
|
+
switch (result) {
|
|
206
|
+
case 'clean': return (React.createElement("span", { className: "status-icon" },
|
|
207
|
+
React.createElement("span", { className: "codicon codicon-pass-filled" })));
|
|
208
|
+
case 'match': return (React.createElement("span", { className: "status-icon" },
|
|
209
|
+
React.createElement("span", { className: "codicon codicon-warning" })));
|
|
210
|
+
case 'pending': return React.createElement("i", { className: "fa fa-spinner fa-spin" });
|
|
211
|
+
default: return undefined;
|
|
212
|
+
}
|
|
213
|
+
}
|
|
214
|
+
//# sourceMappingURL=change-set-scan-action.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"change-set-scan-action.js","sourceRoot":"","sources":["../../../src/browser/change-set-scan-action/change-set-scan-action.tsx"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,13 +1,15 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@theia/ai-scanoss",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.59.0-next.72+f41d8efcd",
|
|
4
4
|
"description": "Theia - SCANOSS AI Integration",
|
|
5
5
|
"dependencies": {
|
|
6
|
-
"@theia/ai-chat": "1.
|
|
7
|
-
"@theia/ai-chat-ui": "1.
|
|
8
|
-
"@theia/ai-core": "1.
|
|
9
|
-
"@theia/core": "1.
|
|
10
|
-
"@theia/
|
|
6
|
+
"@theia/ai-chat": "1.59.0-next.72+f41d8efcd",
|
|
7
|
+
"@theia/ai-chat-ui": "1.59.0-next.72+f41d8efcd",
|
|
8
|
+
"@theia/ai-core": "1.59.0-next.72+f41d8efcd",
|
|
9
|
+
"@theia/core": "1.59.0-next.72+f41d8efcd",
|
|
10
|
+
"@theia/monaco": "1.59.0-next.72+f41d8efcd",
|
|
11
|
+
"@theia/monaco-editor-core": "1.96.302",
|
|
12
|
+
"@theia/scanoss": "1.59.0-next.72+f41d8efcd"
|
|
11
13
|
},
|
|
12
14
|
"publishConfig": {
|
|
13
15
|
"access": "public"
|
|
@@ -43,10 +45,10 @@
|
|
|
43
45
|
"watch": "theiaext watch"
|
|
44
46
|
},
|
|
45
47
|
"devDependencies": {
|
|
46
|
-
"@theia/ext-scripts": "1.58.
|
|
48
|
+
"@theia/ext-scripts": "1.58.0"
|
|
47
49
|
},
|
|
48
50
|
"nyc": {
|
|
49
51
|
"extends": "../../configs/nyc.json"
|
|
50
52
|
},
|
|
51
|
-
"gitHead": "
|
|
53
|
+
"gitHead": "f41d8efcd4abb79167b74bf476eafc7857e97306"
|
|
52
54
|
}
|
|
@@ -28,6 +28,7 @@ import * as React from '@theia/core/shared/react';
|
|
|
28
28
|
import { ReactDialog } from '@theia/core/lib/browser/dialogs/react-dialog';
|
|
29
29
|
import { SCAN_OSS_API_KEY_PREF } from '@theia/scanoss/lib/browser/scanoss-preferences';
|
|
30
30
|
import { SCANOSS_MODE_PREF } from './ai-scanoss-preferences';
|
|
31
|
+
import { nls } from '@theia/core';
|
|
31
32
|
|
|
32
33
|
// cached map of scanOSS results.
|
|
33
34
|
// 'false' is stored when not automatic check is off and it was not (yet) requested deliberately.
|
|
@@ -127,54 +128,52 @@ const ScanOSSIntegration = React.memo((props: {
|
|
|
127
128
|
scanResult = await scanCode();
|
|
128
129
|
}
|
|
129
130
|
if (scanResult && scanResult.type === 'match') {
|
|
130
|
-
const dialog = new ScanOSSDialog(scanResult);
|
|
131
|
+
const dialog = new ScanOSSDialog([scanResult]);
|
|
131
132
|
dialog.open();
|
|
132
133
|
}
|
|
133
134
|
}, [scanOSSResult]);
|
|
134
135
|
let title = 'SCANOSS - Perform scan';
|
|
135
136
|
if (scanOSSResult) {
|
|
136
137
|
if (scanOSSResult === 'pending') {
|
|
137
|
-
title = 'SCANOSS - Performing scan...';
|
|
138
|
+
title = nls.localize('theia/ai/scanoss/snippet/in-progress', 'SCANOSS - Performing scan...');
|
|
138
139
|
} else if (scanOSSResult.type === 'error') {
|
|
139
|
-
title =
|
|
140
|
+
title = nls.localize('theia/ai/scanoss/snippet/errored', 'SCANOSS - Error - {0}', scanOSSResult.message);
|
|
140
141
|
} else if (scanOSSResult.type === 'match') {
|
|
141
|
-
title =
|
|
142
|
+
title = nls.localize('theia/ai/scanoss/snippet/matched', 'SCANOSS - Found {0} match', scanOSSResult.matched);
|
|
142
143
|
} else if (scanOSSResult.type === 'clean') {
|
|
143
|
-
title = 'SCANOSS - No match';
|
|
144
|
+
title = nls.localize('theia/ai/scanoss/snippet/no-match', 'SCANOSS - No match');
|
|
144
145
|
}
|
|
145
146
|
}
|
|
146
147
|
return (
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
<span className="
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
</div>
|
|
168
|
-
</>
|
|
148
|
+
<div
|
|
149
|
+
className={`button scanoss-logo show-check icon-container ${scanOSSResult === 'pending'
|
|
150
|
+
? 'pending'
|
|
151
|
+
: scanOSSResult
|
|
152
|
+
? scanOSSResult.type
|
|
153
|
+
: ''
|
|
154
|
+
}`}
|
|
155
|
+
title={title}
|
|
156
|
+
role="button"
|
|
157
|
+
onClick={scanOSSClicked}
|
|
158
|
+
>
|
|
159
|
+
<div className="codicon codicon-circle placeholder" />
|
|
160
|
+
{scanOSSResult && scanOSSResult !== 'pending' && (
|
|
161
|
+
<span className="status-icon">
|
|
162
|
+
{scanOSSResult.type === 'clean' && <span className="codicon codicon-pass-filled" />}
|
|
163
|
+
{scanOSSResult.type === 'match' && <span className="codicon codicon-warning" />}
|
|
164
|
+
{scanOSSResult.type === 'error' && <span className="codicon codicon-error" />}
|
|
165
|
+
</span>
|
|
166
|
+
)}
|
|
167
|
+
</div>
|
|
169
168
|
);
|
|
170
169
|
});
|
|
171
170
|
|
|
172
171
|
export class ScanOSSDialog extends ReactDialog<void> {
|
|
173
172
|
protected readonly okButton: HTMLButtonElement;
|
|
174
173
|
|
|
175
|
-
constructor(protected
|
|
174
|
+
constructor(protected results: ScanOSSResultMatch[]) {
|
|
176
175
|
super({
|
|
177
|
-
title: '
|
|
176
|
+
title: nls.localize('theia/ai/scanoss/snippet/dialog-header', 'ScanOSS Results'),
|
|
178
177
|
});
|
|
179
178
|
this.appendAcceptButton(Dialog.OK);
|
|
180
179
|
this.update();
|
|
@@ -204,12 +203,9 @@ export class ScanOSSDialog extends ReactDialog<void> {
|
|
|
204
203
|
protected renderSummary(): React.ReactNode {
|
|
205
204
|
return (
|
|
206
205
|
<div className="scanoss-summary">
|
|
207
|
-
<h3>Summary</h3>
|
|
206
|
+
<h3>{nls.localize('theia/ai/scanoss/snippet/summary', 'Summary')}</h3>
|
|
208
207
|
<div>
|
|
209
|
-
Found
|
|
210
|
-
<a href={this.result.url} target="_blank" rel="noopener noreferrer">
|
|
211
|
-
{this.result.url}
|
|
212
|
-
</a>
|
|
208
|
+
{nls.localize('theia/ai/scanoss/snippet/match-count', 'Found {0} match(es)', this.results.length)}
|
|
213
209
|
</div>
|
|
214
210
|
</div>
|
|
215
211
|
);
|
|
@@ -218,13 +214,17 @@ export class ScanOSSDialog extends ReactDialog<void> {
|
|
|
218
214
|
protected renderContent(): React.ReactNode {
|
|
219
215
|
return (
|
|
220
216
|
<div className="scanoss-details">
|
|
221
|
-
<h4>Details</h4>
|
|
222
|
-
|
|
223
|
-
{
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
217
|
+
<h4>{nls.localizeByDefault('Details')}</h4>
|
|
218
|
+
{this.results.map(result =>
|
|
219
|
+
<div key={result.matched}>
|
|
220
|
+
{result.file && <h4>{nls.localize('theia/ai/scanoss/snippet/file-name-heading', 'Match found in {0}', result.file)}</h4>}
|
|
221
|
+
<a href={result.url} target="_blank" rel="noopener noreferrer">
|
|
222
|
+
{result.url}
|
|
223
|
+
</a>
|
|
224
|
+
<pre>
|
|
225
|
+
{JSON.stringify(result.raw, undefined, 2)}
|
|
226
|
+
</pre>
|
|
227
|
+
</div>)}
|
|
228
228
|
</div>
|
|
229
229
|
);
|
|
230
230
|
}
|
|
@@ -14,15 +14,19 @@
|
|
|
14
14
|
// SPDX-License-Identifier: EPL-2.0 OR GPL-2.0-only WITH Classpath-exception-2.0
|
|
15
15
|
// *****************************************************************************
|
|
16
16
|
|
|
17
|
+
import '../../src/browser/style/index.css';
|
|
17
18
|
import { ContainerModule } from '@theia/core/shared/inversify';
|
|
18
19
|
import { AIScanOSSPreferencesSchema } from './ai-scanoss-preferences';
|
|
19
20
|
import { PreferenceContribution } from '@theia/core/lib/browser';
|
|
20
21
|
import { ScanOSSScanButtonAction } from './ai-scanoss-code-scan-action';
|
|
21
22
|
import { CodePartRendererAction } from '@theia/ai-chat-ui/lib/browser/chat-response-renderer';
|
|
22
|
-
import '
|
|
23
|
+
import { ChangeSetActionRenderer } from '@theia/ai-chat-ui/lib/browser/change-set-actions/change-set-action-service';
|
|
24
|
+
import { ChangeSetScanActionRenderer } from './change-set-scan-action/change-set-scan-action';
|
|
23
25
|
|
|
24
26
|
export default new ContainerModule(bind => {
|
|
25
27
|
bind(PreferenceContribution).toConstantValue({ schema: AIScanOSSPreferencesSchema });
|
|
26
28
|
bind(ScanOSSScanButtonAction).toSelf().inSingletonScope();
|
|
27
29
|
bind(CodePartRendererAction).toService(ScanOSSScanButtonAction);
|
|
30
|
+
bind(ChangeSetScanActionRenderer).toSelf();
|
|
31
|
+
bind(ChangeSetActionRenderer).toService(ChangeSetScanActionRenderer);
|
|
28
32
|
});
|
|
@@ -16,6 +16,7 @@
|
|
|
16
16
|
|
|
17
17
|
import { PreferenceSchema } from '@theia/core/lib/browser/preferences';
|
|
18
18
|
import { AI_CORE_PREFERENCES_TITLE } from '@theia/ai-core/lib/browser/ai-core-preferences';
|
|
19
|
+
import { nls } from '@theia/core';
|
|
19
20
|
|
|
20
21
|
export const SCANOSS_MODE_PREF = 'ai-features.SCANOSS.mode';
|
|
21
22
|
|
|
@@ -26,12 +27,13 @@ export const AIScanOSSPreferencesSchema: PreferenceSchema = {
|
|
|
26
27
|
type: 'string',
|
|
27
28
|
enum: ['off', 'manual', 'automatic'],
|
|
28
29
|
markdownEnumDescriptions: [
|
|
29
|
-
'Feature is turned off completely.',
|
|
30
|
-
'User can manually trigger the scan by clicking the SCANOSS item in the chat view.',
|
|
31
|
-
'Enable automatic scan of code snippets in chat views.'
|
|
30
|
+
nls.localize('theia/ai/scanoss/mode/off/description', 'Feature is turned off completely.'),
|
|
31
|
+
nls.localize('theia/ai/scanoss/mode/manual/description', 'User can manually trigger the scan by clicking the SCANOSS item in the chat view.'),
|
|
32
|
+
nls.localize('theia/ai/scanoss/mode/automatic/description', 'Enable automatic scan of code snippets in chat views.')
|
|
32
33
|
],
|
|
33
|
-
markdownDescription: '
|
|
34
|
-
|
|
34
|
+
markdownDescription: nls.localize('theia/ai/scanoss/mode/description',
|
|
35
|
+
'Configure the SCANOSS feature for analyzing code snippets in chat views. This will send a hash of suggested code snippets to the SCANOSS\n\
|
|
36
|
+
service hosted by the [Software Transparency foundation](https://www.softwaretransparency.org/osskb) for analysis.'),
|
|
35
37
|
default: 'off',
|
|
36
38
|
title: AI_CORE_PREFERENCES_TITLE
|
|
37
39
|
}
|
|
@@ -0,0 +1,249 @@
|
|
|
1
|
+
// *****************************************************************************
|
|
2
|
+
// Copyright (C) 2025 EclipseSource GmbH and others.
|
|
3
|
+
//
|
|
4
|
+
// This program and the accompanying materials are made available under the
|
|
5
|
+
// terms of the Eclipse Public License v. 2.0 which is available at
|
|
6
|
+
// http://www.eclipse.org/legal/epl-2.0.
|
|
7
|
+
//
|
|
8
|
+
// This Source Code may also be made available under the following Secondary
|
|
9
|
+
// Licenses when the conditions for such availability set forth in the Eclipse
|
|
10
|
+
// Public License v. 2.0 are satisfied: GNU General Public License, version 2
|
|
11
|
+
// with the GNU Classpath Exception which is available at
|
|
12
|
+
// https://www.gnu.org/software/classpath/license.html.
|
|
13
|
+
//
|
|
14
|
+
// SPDX-License-Identifier: EPL-2.0 OR GPL-2.0-only WITH Classpath-exception-2.0
|
|
15
|
+
// *****************************************************************************
|
|
16
|
+
|
|
17
|
+
import * as React from '@theia/core/shared/react';
|
|
18
|
+
import { ChangeSet, ChangeSetElement } from '@theia/ai-chat';
|
|
19
|
+
import { inject, injectable, postConstruct } from '@theia/core/shared/inversify';
|
|
20
|
+
import { ChangeSetActionRenderer } from '@theia/ai-chat-ui/lib/browser/change-set-actions/change-set-action-service';
|
|
21
|
+
import { PreferenceService } from '@theia/core/lib/browser/preferences';
|
|
22
|
+
import { ScanOSSService, ScanOSSResult, ScanOSSResultMatch } from '@theia/scanoss';
|
|
23
|
+
import { SCANOSS_MODE_PREF } from '../ai-scanoss-preferences';
|
|
24
|
+
import { SCAN_OSS_API_KEY_PREF } from '@theia/scanoss/lib/browser/scanoss-preferences';
|
|
25
|
+
import { ChangeSetFileElement } from '@theia/ai-chat/lib/browser/change-set-file-element';
|
|
26
|
+
import { ScanOSSDialog } from '../ai-scanoss-code-scan-action';
|
|
27
|
+
import { StandaloneServices } from '@theia/monaco-editor-core/esm/vs/editor/standalone/browser/standaloneServices';
|
|
28
|
+
import { IDiffProviderFactoryService } from '@theia/monaco-editor-core/esm/vs/editor/browser/widget/diffEditor/diffProviderFactoryService';
|
|
29
|
+
import { IDocumentDiffProvider } from '@theia/monaco-editor-core/esm/vs/editor/common/diff/documentDiffProvider';
|
|
30
|
+
import { MonacoTextModelService } from '@theia/monaco/lib/browser/monaco-text-model-service';
|
|
31
|
+
import { CancellationToken, Emitter, MessageService, nls } from '@theia/core';
|
|
32
|
+
|
|
33
|
+
type ScanOSSState = 'pending' | 'clean' | 'match' | 'error' | 'none';
|
|
34
|
+
type ScanOSSResultOptions = 'pending' | ScanOSSResult[] | undefined;
|
|
35
|
+
|
|
36
|
+
@injectable()
|
|
37
|
+
export class ChangeSetScanActionRenderer implements ChangeSetActionRenderer {
|
|
38
|
+
readonly id = 'change-set-scanoss';
|
|
39
|
+
protected readonly onDidChangeEmitter = new Emitter<void>();
|
|
40
|
+
readonly onDidChange = this.onDidChangeEmitter.event;
|
|
41
|
+
|
|
42
|
+
@inject(ScanOSSService)
|
|
43
|
+
protected readonly scanService: ScanOSSService;
|
|
44
|
+
|
|
45
|
+
@inject(PreferenceService)
|
|
46
|
+
protected readonly preferenceService: PreferenceService;
|
|
47
|
+
|
|
48
|
+
@inject(MonacoTextModelService)
|
|
49
|
+
protected readonly textModelService: MonacoTextModelService;
|
|
50
|
+
|
|
51
|
+
@inject(MessageService)
|
|
52
|
+
protected readonly messageService: MessageService;
|
|
53
|
+
|
|
54
|
+
protected differ: IDocumentDiffProvider;
|
|
55
|
+
|
|
56
|
+
@postConstruct()
|
|
57
|
+
init(): void {
|
|
58
|
+
this.differ = StandaloneServices.get(IDiffProviderFactoryService).createDiffProvider({ diffAlgorithm: 'advanced' });
|
|
59
|
+
this._scan = this.runScan.bind(this);
|
|
60
|
+
this.preferenceService.onPreferenceChanged(e => e.affects(SCANOSS_MODE_PREF) && this.onDidChangeEmitter.fire());
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
canRender(_changeSet: ChangeSet): boolean {
|
|
64
|
+
return true;
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
render(changeSet: ChangeSet): React.ReactNode {
|
|
68
|
+
return (
|
|
69
|
+
<ChangeSetScanOSSIntegration
|
|
70
|
+
changeSet={changeSet}
|
|
71
|
+
scanOssMode={this.getPreferenceValues()}
|
|
72
|
+
scanChangeSet={this._scan}
|
|
73
|
+
/>
|
|
74
|
+
);
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
protected getPreferenceValues(): string {
|
|
78
|
+
return this.preferenceService.get(SCANOSS_MODE_PREF, 'off');
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
protected _scan: (changeSetElements: ChangeSetElement[]) => Promise<ScanOSSResult[]>;
|
|
82
|
+
|
|
83
|
+
protected async runScan(changeSetElements: ChangeSetFileElement[], cache: Map<string, ScanOSSResult>, userTriggered: boolean): Promise<ScanOSSResult[]> {
|
|
84
|
+
const apiKey = this.preferenceService.get(SCAN_OSS_API_KEY_PREF, undefined);
|
|
85
|
+
let notifiedError = false;
|
|
86
|
+
const fileResults = await Promise.all(changeSetElements.map(async fileChange => {
|
|
87
|
+
if (fileChange.targetState.trim().length === 0) {
|
|
88
|
+
return { type: 'clean' } satisfies ScanOSSResult;
|
|
89
|
+
}
|
|
90
|
+
const toScan = await this.getScanContent(fileChange);
|
|
91
|
+
|
|
92
|
+
if (!toScan) { return { type: 'clean' } satisfies ScanOSSResult; }
|
|
93
|
+
|
|
94
|
+
const cached = cache.get(toScan);
|
|
95
|
+
if (cached) { return cached; }
|
|
96
|
+
|
|
97
|
+
const result = { ...await this.scanService.scanContent(toScan, apiKey), file: fileChange.uri.path.toString() };
|
|
98
|
+
if (result.type !== 'error') {
|
|
99
|
+
cache.set(toScan, result);
|
|
100
|
+
} else if (!notifiedError && userTriggered) {
|
|
101
|
+
notifiedError = true;
|
|
102
|
+
this.messageService.warn(nls.localize('theia/ai/scanoss/changeSet/error-notification', 'ScanOSS error encountered: {0}.', result.message));
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
return result;
|
|
106
|
+
}));
|
|
107
|
+
return fileResults;
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
protected async getScanContent(fileChange: ChangeSetFileElement): Promise<string> {
|
|
111
|
+
if (fileChange.replacements) {
|
|
112
|
+
return fileChange.replacements.map(({ newContent }) => newContent).join('\n\n').trim();
|
|
113
|
+
}
|
|
114
|
+
const textModels = await Promise.all([
|
|
115
|
+
this.textModelService.createModelReference(fileChange.uri),
|
|
116
|
+
this.textModelService.createModelReference(fileChange.changedUri)
|
|
117
|
+
]);
|
|
118
|
+
|
|
119
|
+
const [original, changed] = textModels;
|
|
120
|
+
const diff = await this.differ.computeDiff(
|
|
121
|
+
original.object.textEditorModel,
|
|
122
|
+
changed.object.textEditorModel,
|
|
123
|
+
{ maxComputationTimeMs: 5000, computeMoves: false, ignoreTrimWhitespace: true },
|
|
124
|
+
CancellationToken.None
|
|
125
|
+
);
|
|
126
|
+
|
|
127
|
+
if (diff.identical) { return ''; }
|
|
128
|
+
|
|
129
|
+
const insertions = diff.changes.filter(candidate => !candidate.modified.isEmpty);
|
|
130
|
+
|
|
131
|
+
if (insertions.length === 0) { return ''; }
|
|
132
|
+
|
|
133
|
+
const changedLinesInSuggestion = insertions.map(change => {
|
|
134
|
+
const range = change.modified.toInclusiveRange();
|
|
135
|
+
return range ? changed.object.textEditorModel.getValueInRange(range) : ''; // In practice, we've filtered out cases where the range would be null already.
|
|
136
|
+
}).join('\n\n');
|
|
137
|
+
|
|
138
|
+
textModels.forEach(ref => ref.dispose());
|
|
139
|
+
return changedLinesInSuggestion.trim();
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
interface ChangeSetScanActionProps {
|
|
144
|
+
changeSet: ChangeSet;
|
|
145
|
+
scanOssMode: string;
|
|
146
|
+
scanChangeSet: (changeSet: ChangeSetElement[], cache: Map<string, ScanOSSResult>, userTriggered: boolean) => Promise<ScanOSSResult[]>
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
const ChangeSetScanOSSIntegration = React.memo(({
|
|
150
|
+
changeSet,
|
|
151
|
+
scanOssMode,
|
|
152
|
+
scanChangeSet
|
|
153
|
+
}: ChangeSetScanActionProps) => {
|
|
154
|
+
const [scanOSSResult, setScanOSSResult] = React.useState<ScanOSSResult[] | 'pending' | undefined>(undefined);
|
|
155
|
+
const cache = React.useRef(new Map<string, ScanOSSResult>());
|
|
156
|
+
const [changeSetElements, setChangeSetElements] = React.useState(() => changeSet.getElements().filter(candidate => candidate instanceof ChangeSetFileElement));
|
|
157
|
+
|
|
158
|
+
React.useEffect(() => {
|
|
159
|
+
if (scanOSSResult === undefined) {
|
|
160
|
+
if (scanOssMode === 'automatic' && scanOSSResult === undefined) {
|
|
161
|
+
setScanOSSResult('pending');
|
|
162
|
+
scanChangeSet(changeSetElements, cache.current, false).then(result => setScanOSSResult(result));
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
}, [scanOssMode, scanOSSResult]);
|
|
166
|
+
|
|
167
|
+
React.useEffect(() => {
|
|
168
|
+
const disposable = changeSet.onDidChange(() => {
|
|
169
|
+
setChangeSetElements(changeSet.getElements().filter(candidate => candidate instanceof ChangeSetFileElement));
|
|
170
|
+
setScanOSSResult(undefined);
|
|
171
|
+
});
|
|
172
|
+
return () => disposable.dispose();
|
|
173
|
+
}, [changeSet]);
|
|
174
|
+
|
|
175
|
+
const scanOSSClicked = React.useCallback(async () => {
|
|
176
|
+
if (scanOSSResult === 'pending') {
|
|
177
|
+
return;
|
|
178
|
+
} else if (!scanOSSResult || scanOSSResult.some(candidate => candidate.type === 'error')) {
|
|
179
|
+
setScanOSSResult('pending');
|
|
180
|
+
scanChangeSet(changeSetElements, cache.current, true).then(result => setScanOSSResult(result));
|
|
181
|
+
} else {
|
|
182
|
+
const matches = scanOSSResult.filter((candidate): candidate is ScanOSSResultMatch => candidate.type === 'match');
|
|
183
|
+
if (matches.length === 0) { return; }
|
|
184
|
+
const dialog = new ScanOSSDialog(matches);
|
|
185
|
+
dialog.open();
|
|
186
|
+
}
|
|
187
|
+
}, [scanOSSResult, changeSetElements]);
|
|
188
|
+
|
|
189
|
+
const state = getResult(scanOSSResult);
|
|
190
|
+
const content = getTitle(state);
|
|
191
|
+
const title = `ScanOSS: ${content}`;
|
|
192
|
+
const icon = getIcon(state);
|
|
193
|
+
|
|
194
|
+
if (scanOssMode === 'off' || changeSetElements.length === 0) {
|
|
195
|
+
return undefined;
|
|
196
|
+
} else if (state === 'clean' || state === 'pending') {
|
|
197
|
+
return <div
|
|
198
|
+
className={`theia-button button theia-changeSet-scanOss ${state}`}
|
|
199
|
+
title={title}
|
|
200
|
+
>
|
|
201
|
+
<span className={'scanoss-logo icon-container'} />
|
|
202
|
+
{content}
|
|
203
|
+
{icon}
|
|
204
|
+
</div>;
|
|
205
|
+
} else {
|
|
206
|
+
return <button
|
|
207
|
+
className={`theia-button theia-changeSet-scanOss ${state}`}
|
|
208
|
+
title={title}
|
|
209
|
+
onClick={scanOSSClicked}
|
|
210
|
+
>
|
|
211
|
+
<span className={'scanoss-logo icon-container'} />
|
|
212
|
+
{content}
|
|
213
|
+
{icon}
|
|
214
|
+
</button>;
|
|
215
|
+
}
|
|
216
|
+
});
|
|
217
|
+
|
|
218
|
+
function getResult(scanOSSResult: ScanOSSResultOptions): ScanOSSState {
|
|
219
|
+
switch (true) {
|
|
220
|
+
case scanOSSResult === undefined: return 'none';
|
|
221
|
+
case scanOSSResult === 'pending': return 'pending';
|
|
222
|
+
case (scanOSSResult as ScanOSSResult[]).some(candidate => candidate.type === 'error'): return 'error';
|
|
223
|
+
case (scanOSSResult as ScanOSSResult[]).some(candidate => candidate.type === 'match'): return 'match';
|
|
224
|
+
default: return 'clean';
|
|
225
|
+
}
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
function getTitle(result: ScanOSSState): string {
|
|
229
|
+
switch (result) {
|
|
230
|
+
case 'none': return nls.localize('theia/ai/scanoss/changeSet/scan', 'Scan');
|
|
231
|
+
case 'pending': return nls.localize('theia/ai/scanoss/changeSet/scanning', 'Scanning...');
|
|
232
|
+
case 'error': return nls.localize('theia/ai/scanoss/changeSet/error', 'Error: Rerun');
|
|
233
|
+
case 'match': return nls.localize('theia/ai/scanoss/changeSet/view-matches', 'View Matches');
|
|
234
|
+
case 'clean': return nls.localize('theia/ai/scanoss/changeSet/clean', 'No Matches');
|
|
235
|
+
}
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
function getIcon(result: ScanOSSState): React.ReactNode {
|
|
239
|
+
switch (result) {
|
|
240
|
+
case 'clean': return (<span className="status-icon">
|
|
241
|
+
<span className="codicon codicon-pass-filled" />
|
|
242
|
+
</span>);
|
|
243
|
+
case 'match': return (<span className="status-icon">
|
|
244
|
+
<span className="codicon codicon-warning" />
|
|
245
|
+
</span>);
|
|
246
|
+
case 'pending': return <i className="fa fa-spinner fa-spin" />;
|
|
247
|
+
default: return undefined;
|
|
248
|
+
}
|
|
249
|
+
}
|
|
@@ -130,3 +130,40 @@
|
|
|
130
130
|
overflow: auto;
|
|
131
131
|
font-size: 0.9em;
|
|
132
132
|
}
|
|
133
|
+
|
|
134
|
+
.theia-changeSet-scanOss {
|
|
135
|
+
display: flex;
|
|
136
|
+
flex-flow: row nowrap;
|
|
137
|
+
align-items: center;
|
|
138
|
+
justify-content: center;
|
|
139
|
+
gap: var(--theia-ui-padding);
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
.theia-changeSet-Action .theia-changeSet-scanOss .scanoss-logo {
|
|
143
|
+
background-size: cover;
|
|
144
|
+
background-color: inherit;
|
|
145
|
+
/* Buttons in all themes tested used a light font color */
|
|
146
|
+
background-image: url("scanoss_logo_dark_theme.svg");
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
.theia-changeSet-scanOss.clean,
|
|
150
|
+
.theia-changeSet-scanOss.pending {
|
|
151
|
+
cursor: default;
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
.theia-changeSet-scanOss.clean:hover,
|
|
155
|
+
.theia-changeSet-scanOss.pending:hover {
|
|
156
|
+
background-color: var(--theia-button-background);
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
.theia-changeSet-scanOss .status-icon {
|
|
160
|
+
height: 16px;
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
.theia-changeSet-scanOss.clean .status-icon {
|
|
164
|
+
color: var(--theia-notebookStatusSuccessIcon-foreground);
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
.theia-changeSet-scanOss.match .status-icon {
|
|
168
|
+
color: var(--theia-problemsWarningIcon-foreground);
|
|
169
|
+
}
|