@theia/core 1.25.0-next.7 → 1.25.0
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/README.md +3 -3
- package/lib/browser/browser.d.ts +3 -0
- package/lib/browser/browser.d.ts.map +1 -1
- package/lib/browser/browser.js +51 -1
- package/lib/browser/browser.js.map +1 -1
- package/lib/browser/common-frontend-contribution.d.ts.map +1 -1
- package/lib/browser/common-frontend-contribution.js +59 -10
- package/lib/browser/common-frontend-contribution.js.map +1 -1
- package/lib/browser/preferences/preference-validation-service.d.ts +13 -0
- package/lib/browser/preferences/preference-validation-service.d.ts.map +1 -1
- package/lib/browser/preferences/preference-validation-service.js +92 -7
- package/lib/browser/preferences/preference-validation-service.js.map +1 -1
- package/lib/browser/preferences/preference-validation-service.spec.js +58 -0
- package/lib/browser/preferences/preference-validation-service.spec.js.map +1 -1
- package/lib/browser/preloader.d.ts +2 -0
- package/lib/browser/preloader.d.ts.map +1 -0
- package/lib/browser/{nls-loader.js → preloader.js} +25 -6
- package/lib/browser/preloader.js.map +1 -0
- package/lib/browser/quick-input/quick-pick-service-impl.d.ts +1 -1
- package/lib/browser/quick-input/quick-pick-service-impl.d.ts.map +1 -1
- package/lib/browser/quick-input/quick-pick-service-impl.js.map +1 -1
- package/lib/browser/resource-context-key.js +2 -3
- package/lib/browser/resource-context-key.js.map +1 -1
- package/lib/browser/saveable.d.ts +6 -1
- package/lib/browser/saveable.d.ts.map +1 -1
- package/lib/browser/saveable.js.map +1 -1
- package/lib/browser/shell/application-shell.d.ts.map +1 -1
- package/lib/browser/shell/application-shell.js +1 -0
- package/lib/browser/shell/application-shell.js.map +1 -1
- package/lib/browser/status-bar/status-bar.d.ts +2 -0
- package/lib/browser/status-bar/status-bar.d.ts.map +1 -1
- package/lib/browser/status-bar/status-bar.js +2 -1
- package/lib/browser/status-bar/status-bar.js.map +1 -1
- package/lib/browser/tree/tree-widget.d.ts +1 -1
- package/lib/browser/tree/tree-widget.d.ts.map +1 -1
- package/lib/browser/tree/tree-widget.js +18 -7
- package/lib/browser/tree/tree-widget.js.map +1 -1
- package/lib/browser/widget-decoration.d.ts +11 -0
- package/lib/browser/widget-decoration.d.ts.map +1 -1
- package/lib/browser/widget-decoration.js +7 -0
- package/lib/browser/widget-decoration.js.map +1 -1
- package/lib/browser/widgets/select-component.d.ts +52 -0
- package/lib/browser/widgets/select-component.d.ts.map +1 -0
- package/lib/browser/widgets/select-component.js +287 -0
- package/lib/browser/widgets/select-component.js.map +1 -0
- package/lib/common/application-protocol.d.ts +3 -0
- package/lib/common/application-protocol.d.ts.map +1 -1
- package/lib/common/disposable.d.ts +1 -0
- package/lib/common/disposable.d.ts.map +1 -1
- package/lib/common/disposable.js +12 -4
- package/lib/common/disposable.js.map +1 -1
- package/lib/common/disposable.spec.d.ts +2 -0
- package/lib/common/disposable.spec.d.ts.map +1 -0
- package/lib/common/disposable.spec.js +31 -0
- package/lib/common/disposable.spec.js.map +1 -0
- package/lib/common/i18n/localization.d.ts +7 -5
- package/lib/common/i18n/localization.d.ts.map +1 -1
- package/lib/common/i18n/localization.js.map +1 -1
- package/lib/common/json-schema.d.ts +1 -0
- package/lib/common/json-schema.d.ts.map +1 -1
- package/lib/common/nls.js +24 -4
- package/lib/common/nls.js.map +1 -1
- package/lib/common/os.d.ts +5 -0
- package/lib/common/os.d.ts.map +1 -1
- package/lib/common/os.js +5 -0
- package/lib/common/os.js.map +1 -1
- package/lib/common/path.d.ts +20 -17
- package/lib/common/path.d.ts.map +1 -1
- package/lib/common/path.js +37 -0
- package/lib/common/path.js.map +1 -1
- package/lib/common/path.spec.js +37 -0
- package/lib/common/path.spec.js.map +1 -1
- package/lib/common/quick-pick-service.d.ts +1 -1
- package/lib/common/quick-pick-service.d.ts.map +1 -1
- package/lib/common/quick-pick-service.js +0 -15
- package/lib/common/quick-pick-service.js.map +1 -1
- package/lib/common/selection-service.d.ts +7 -0
- package/lib/common/selection-service.d.ts.map +1 -1
- package/lib/common/selection-service.js +5 -0
- package/lib/common/selection-service.js.map +1 -1
- package/lib/common/uri.d.ts +12 -1
- package/lib/common/uri.d.ts.map +1 -1
- package/lib/common/uri.js +14 -0
- package/lib/common/uri.js.map +1 -1
- package/lib/electron-browser/menu/electron-menu-contribution.d.ts +1 -0
- package/lib/electron-browser/menu/electron-menu-contribution.d.ts.map +1 -1
- package/lib/electron-browser/menu/electron-menu-contribution.js +10 -4
- package/lib/electron-browser/menu/electron-menu-contribution.js.map +1 -1
- package/lib/electron-common/electron-token.d.ts +3 -3
- package/lib/electron-common/electron-token.d.ts.map +1 -1
- package/lib/electron-common/electron-token.js +4 -3
- package/lib/electron-common/electron-token.js.map +1 -1
- package/lib/node/backend-application-module.d.ts.map +1 -1
- package/lib/node/backend-application-module.js +3 -0
- package/lib/node/backend-application-module.js.map +1 -1
- package/lib/node/i18n/localization-backend-contribution.js +1 -1
- package/lib/node/i18n/localization-backend-contribution.js.map +1 -1
- package/lib/node/i18n/localization-contribution.d.ts +4 -3
- package/lib/node/i18n/localization-contribution.d.ts.map +1 -1
- package/lib/node/i18n/localization-contribution.js +15 -10
- package/lib/node/i18n/localization-contribution.js.map +1 -1
- package/lib/node/i18n/localization-provider.d.ts +2 -2
- package/lib/node/i18n/localization-provider.d.ts.map +1 -1
- package/lib/node/i18n/localization-provider.js +9 -4
- package/lib/node/i18n/localization-provider.js.map +1 -1
- package/lib/node/os-backend-application-contribution.d.ts +6 -0
- package/lib/node/os-backend-application-contribution.d.ts.map +1 -0
- package/lib/node/os-backend-application-contribution.js +38 -0
- package/lib/node/os-backend-application-contribution.js.map +1 -0
- package/package.json +5 -5
- package/src/browser/browser.ts +62 -0
- package/src/browser/common-frontend-contribution.ts +68 -10
- package/src/browser/preferences/preference-validation-service.spec.ts +59 -0
- package/src/browser/preferences/preference-validation-service.ts +85 -8
- package/src/browser/{nls-loader.ts → preloader.ts} +26 -4
- package/src/browser/quick-input/quick-pick-service-impl.ts +2 -2
- package/src/browser/resource-context-key.ts +2 -2
- package/src/browser/saveable.ts +3 -1
- package/src/browser/shell/application-shell.ts +1 -0
- package/src/browser/status-bar/status-bar.tsx +4 -1
- package/src/browser/style/select-component.css +96 -0
- package/src/browser/style/tree.css +6 -0
- package/src/browser/style/view-container.css +2 -2
- package/src/browser/tree/tree-widget.tsx +21 -9
- package/src/browser/widget-decoration.ts +14 -0
- package/src/browser/widgets/select-component.tsx +340 -0
- package/src/common/application-protocol.ts +3 -0
- package/src/common/disposable.spec.ts +30 -0
- package/src/common/disposable.ts +15 -4
- package/src/common/i18n/localization.ts +6 -3
- package/src/common/json-schema.ts +1 -0
- package/src/common/nls.ts +25 -4
- package/src/common/os.ts +6 -0
- package/src/common/path.spec.ts +44 -0
- package/src/common/path.ts +40 -0
- package/src/common/quick-pick-service.ts +1 -17
- package/src/common/selection-service.ts +8 -2
- package/src/common/uri.ts +26 -1
- package/src/electron-browser/menu/electron-menu-contribution.ts +11 -4
- package/src/electron-common/electron-token.ts +4 -3
- package/src/node/backend-application-module.ts +4 -0
- package/src/node/i18n/localization-backend-contribution.ts +1 -1
- package/src/node/i18n/localization-contribution.ts +21 -13
- package/src/node/i18n/localization-provider.ts +12 -7
- package/src/node/os-backend-application-contribution.ts +30 -0
- package/lib/browser/nls-loader.d.ts +0 -2
- package/lib/browser/nls-loader.d.ts.map +0 -1
- package/lib/browser/nls-loader.js.map +0 -1
|
@@ -1143,17 +1143,19 @@ export class CommonFrontendContribution implements FrontendApplicationContributi
|
|
|
1143
1143
|
protected async configureDisplayLanguage(): Promise<void> {
|
|
1144
1144
|
const availableLanguages = await this.localizationProvider.getAvailableLanguages();
|
|
1145
1145
|
const items: QuickPickItem[] = [];
|
|
1146
|
-
for (const
|
|
1147
|
-
|
|
1148
|
-
|
|
1149
|
-
|
|
1150
|
-
|
|
1151
|
-
this.
|
|
1152
|
-
|
|
1153
|
-
|
|
1146
|
+
for (const languageId of ['en', ...availableLanguages.map(e => e.languageId)]) {
|
|
1147
|
+
if (typeof languageId === 'string') {
|
|
1148
|
+
items.push({
|
|
1149
|
+
label: languageId,
|
|
1150
|
+
execute: async () => {
|
|
1151
|
+
if (languageId !== nls.locale && await this.confirmRestart()) {
|
|
1152
|
+
this.windowService.setSafeToShutDown();
|
|
1153
|
+
window.localStorage.setItem(nls.localeId, languageId);
|
|
1154
|
+
this.windowService.reload();
|
|
1155
|
+
}
|
|
1154
1156
|
}
|
|
1155
|
-
}
|
|
1156
|
-
}
|
|
1157
|
+
});
|
|
1158
|
+
}
|
|
1157
1159
|
}
|
|
1158
1160
|
this.quickInputService?.showQuickPick(items,
|
|
1159
1161
|
{
|
|
@@ -1589,6 +1591,34 @@ export class CommonFrontendContribution implements FrontendApplicationContributi
|
|
|
1589
1591
|
hc: Color.rgba(255, 255, 255, 0.12)
|
|
1590
1592
|
}, description: 'Status bar item background color when hovering. The status bar is shown in the bottom of the window.'
|
|
1591
1593
|
},
|
|
1594
|
+
{
|
|
1595
|
+
id: 'statusBarItem.errorBackground', defaults: {
|
|
1596
|
+
dark: Color.darken('errorBackground', 0.4),
|
|
1597
|
+
light: Color.darken('errorBackground', 0.4),
|
|
1598
|
+
hc: undefined,
|
|
1599
|
+
}, description: 'Status bar error items background color. Error items stand out from other status bar entries to indicate error conditions. The status bar is shown in the bottom of the window.'
|
|
1600
|
+
},
|
|
1601
|
+
{
|
|
1602
|
+
id: 'statusBarItem.errorForeground', defaults: {
|
|
1603
|
+
dark: Color.white,
|
|
1604
|
+
light: Color.white,
|
|
1605
|
+
hc: Color.white
|
|
1606
|
+
}, description: 'Status bar error items foreground color. Error items stand out from other status bar entries to indicate error conditions. The status bar is shown in the bottom of the window.'
|
|
1607
|
+
},
|
|
1608
|
+
{
|
|
1609
|
+
id: 'statusBarItem.warningBackground', defaults: {
|
|
1610
|
+
dark: Color.darken('warningBackground', 0.4),
|
|
1611
|
+
light: Color.darken('warningBackground', 0.4),
|
|
1612
|
+
hc: undefined
|
|
1613
|
+
}, description: 'Status bar warning items background color. Warning items stand out from other status bar entries to indicate warning conditions. The status bar is shown in the bottom of the window.'
|
|
1614
|
+
},
|
|
1615
|
+
{
|
|
1616
|
+
id: 'statusBarItem.warningForeground', defaults: {
|
|
1617
|
+
dark: Color.white,
|
|
1618
|
+
light: Color.white,
|
|
1619
|
+
hc: Color.white
|
|
1620
|
+
}, description: 'Status bar warning items foreground color. Warning items stand out from other status bar entries to indicate warning conditions. The status bar is shown in the bottom of the window.'
|
|
1621
|
+
},
|
|
1592
1622
|
|
|
1593
1623
|
// Quickinput colors should be aligned with https://code.visualstudio.com/api/references/theme-color#quick-picker
|
|
1594
1624
|
// if not yet contributed by Monaco, check runtime css variables to learn.
|
|
@@ -1765,6 +1795,34 @@ export class CommonFrontendContribution implements FrontendApplicationContributi
|
|
|
1765
1795
|
{ id: 'welcomePage.buttonHoverBackground', defaults: { dark: Color.rgba(200, 235, 255, .072), light: Color.rgba(0, 0, 0, .10) }, description: 'Hover background color for the buttons on the Welcome page.' },
|
|
1766
1796
|
{ id: 'walkThrough.embeddedEditorBackground', defaults: { dark: Color.rgba(0, 0, 0, .4), light: '#f4f4f4' }, description: 'Background color for the embedded editors on the Interactive Playground.' },
|
|
1767
1797
|
|
|
1798
|
+
// Dropdown colors should be aligned with https://code.visualstudio.com/api/references/theme-color#dropdown-control
|
|
1799
|
+
|
|
1800
|
+
{
|
|
1801
|
+
id: 'dropdown.background', defaults: {
|
|
1802
|
+
light: Color.white,
|
|
1803
|
+
dark: '#3C3C3C',
|
|
1804
|
+
hc: Color.black
|
|
1805
|
+
}, description: 'Dropdown background.'
|
|
1806
|
+
},
|
|
1807
|
+
{
|
|
1808
|
+
id: 'dropdown.listBackground', defaults: {
|
|
1809
|
+
hc: Color.black
|
|
1810
|
+
}, description: 'Dropdown list background.'
|
|
1811
|
+
},
|
|
1812
|
+
{
|
|
1813
|
+
id: 'dropdown.foreground', defaults: {
|
|
1814
|
+
dark: '#F0F0F0',
|
|
1815
|
+
hc: Color.white
|
|
1816
|
+
}, description: 'Dropdown foreground.'
|
|
1817
|
+
},
|
|
1818
|
+
{
|
|
1819
|
+
id: 'dropdown.border', defaults: {
|
|
1820
|
+
light: '#CECECE',
|
|
1821
|
+
dark: 'dropdown.background',
|
|
1822
|
+
hc: '#6FC3DF'
|
|
1823
|
+
}, description: 'Dropdown border.'
|
|
1824
|
+
},
|
|
1825
|
+
|
|
1768
1826
|
// Settings Editor colors should be aligned with https://code.visualstudio.com/api/references/theme-color#settings-editor-colors
|
|
1769
1827
|
{
|
|
1770
1828
|
id: 'settings.headerForeground', defaults: {
|
|
@@ -20,6 +20,7 @@ import { JsonType, PreferenceItem, PreferenceSchemaProvider } from './preference
|
|
|
20
20
|
import { PreferenceLanguageOverrideService } from './preference-language-override-service';
|
|
21
21
|
import * as assert from 'assert';
|
|
22
22
|
import { JSONValue } from '@phosphor/coreutils';
|
|
23
|
+
import { IJSONSchema } from 'src/common/json-schema';
|
|
23
24
|
|
|
24
25
|
/* eslint-disable no-unused-expressions,no-null/no-null */
|
|
25
26
|
|
|
@@ -194,6 +195,39 @@ describe('Preference Validation Service', () => {
|
|
|
194
195
|
assert.deepStrictEqual(actual, expected);
|
|
195
196
|
});
|
|
196
197
|
});
|
|
198
|
+
describe('should validate tuples', () => {
|
|
199
|
+
const schema: PreferenceItem & { items: IJSONSchema[] } = {
|
|
200
|
+
'type': 'array',
|
|
201
|
+
'items': [{
|
|
202
|
+
'type': 'number',
|
|
203
|
+
},
|
|
204
|
+
{
|
|
205
|
+
'type': 'string',
|
|
206
|
+
}],
|
|
207
|
+
};
|
|
208
|
+
it('good input -> returns same object', () => {
|
|
209
|
+
const expected = [1, 'two'];
|
|
210
|
+
assert.strictEqual(validateBySchema(expected, schema), expected);
|
|
211
|
+
});
|
|
212
|
+
it('bad input -> should use the default if supplied present and valid', () => {
|
|
213
|
+
const defaultValue = [8, 'three'];
|
|
214
|
+
const withDefault = { ...schema, default: defaultValue };
|
|
215
|
+
assert.strictEqual(validateBySchema('not even an array!', withDefault), defaultValue);
|
|
216
|
+
assert.strictEqual(validateBySchema(['first fails', 'second ok'], withDefault), defaultValue);
|
|
217
|
+
assert.strictEqual(validateBySchema([], withDefault), defaultValue);
|
|
218
|
+
assert.strictEqual(validateBySchema([2, ['second fails']], withDefault), defaultValue);
|
|
219
|
+
});
|
|
220
|
+
it('bad input -> in the absence of a default, it should return any good values or the default for each subschema', () => {
|
|
221
|
+
const withSubDefault: PreferenceItem = { ...schema, items: [{ type: 'string', default: 'cool' }, ...schema.items] };
|
|
222
|
+
assert.deepStrictEqual(validateBySchema('not an array', withSubDefault), ['cool', 0, '']);
|
|
223
|
+
assert.deepStrictEqual(validateBySchema([2, 8, null], withSubDefault), ['cool', 8, '']);
|
|
224
|
+
});
|
|
225
|
+
it("bad input -> uses the default, but fixes fields that don't match schema", () => {
|
|
226
|
+
const defaultValue = [8, 8];
|
|
227
|
+
const withDefault = { ...schema, default: defaultValue };
|
|
228
|
+
assert.deepStrictEqual(validateBySchema('something invalid', withDefault), [8, '']);
|
|
229
|
+
});
|
|
230
|
+
});
|
|
197
231
|
describe('should validate type arrays', () => {
|
|
198
232
|
const type: JsonType[] = ['boolean', 'string', 'number'];
|
|
199
233
|
it('good input -> returns same value', () => {
|
|
@@ -232,6 +266,31 @@ describe('Preference Validation Service', () => {
|
|
|
232
266
|
assert.strictEqual(validateBySchema({}, { ...schema, default: undefined }), 1);
|
|
233
267
|
});
|
|
234
268
|
});
|
|
269
|
+
describe('should validate oneOfs', () => {
|
|
270
|
+
// Between 4 and 6 should be rejected
|
|
271
|
+
const schema: PreferenceItem = { oneOf: [{ type: 'number', minimum: 1, maximum: 6 }, { type: 'number', minimum: 4, maximum: 10 }], default: 8 };
|
|
272
|
+
it('good input -> returns same value', () => {
|
|
273
|
+
assert.strictEqual(validateBySchema(2, schema), 2);
|
|
274
|
+
assert.strictEqual(validateBySchema(7, schema), 7);
|
|
275
|
+
});
|
|
276
|
+
it('bad input -> returns default if present and valid', () => {
|
|
277
|
+
assert.strictEqual(validateBySchema(5, schema), 8);
|
|
278
|
+
});
|
|
279
|
+
it('bad input -> returns value if default absent or invalid.', () => {
|
|
280
|
+
assert.strictEqual(validateBySchema(5, { ...schema, default: undefined }), 5);
|
|
281
|
+
});
|
|
282
|
+
});
|
|
283
|
+
describe('should validate consts', () => {
|
|
284
|
+
const schema: PreferenceItem = { const: { 'the only': 'possible value' }, default: 'ignore-the-default' };
|
|
285
|
+
const goodValue = { 'the only': 'possible value' };
|
|
286
|
+
it('good input -> returns same value', () => {
|
|
287
|
+
assert.strictEqual(validateBySchema(goodValue, schema), goodValue);
|
|
288
|
+
});
|
|
289
|
+
it('bad input -> returns the const value for any other value', () => {
|
|
290
|
+
assert.deepStrictEqual(validateBySchema('literally anything else', schema), goodValue);
|
|
291
|
+
assert.deepStrictEqual(validateBySchema('ignore-the-default', schema), goodValue);
|
|
292
|
+
});
|
|
293
|
+
});
|
|
235
294
|
describe('should maintain triple equality for valid object types', () => {
|
|
236
295
|
const arraySchema: PreferenceItem = { type: 'array', items: { type: 'string' } };
|
|
237
296
|
it('maintains triple equality for arrays', () => {
|
|
@@ -37,6 +37,8 @@ export interface PreferenceValidationResult<T extends JSONValue> {
|
|
|
37
37
|
messages: string[];
|
|
38
38
|
}
|
|
39
39
|
|
|
40
|
+
type ValidatablePreferenceTuple = ValidatablePreference & ({ items: ValidatablePreference[] } | { prefixItems: ValidatablePreference[] });
|
|
41
|
+
|
|
40
42
|
@injectable()
|
|
41
43
|
export class PreferenceValidationService {
|
|
42
44
|
@inject(PreferenceSchemaProvider) protected readonly schemaProvider: PreferenceSchemaProvider;
|
|
@@ -75,12 +77,18 @@ export class PreferenceValidationService {
|
|
|
75
77
|
console.warn('Request to validate preference with no schema registered:', key);
|
|
76
78
|
return value;
|
|
77
79
|
}
|
|
80
|
+
if (schema.const !== undefined) {
|
|
81
|
+
return this.validateConst(key, value, schema as ValidatablePreference & { const: JSONValue });
|
|
82
|
+
}
|
|
78
83
|
if (Array.isArray(schema.enum)) {
|
|
79
84
|
return this.validateEnum(key, value, schema as ValidatablePreference & { enum: JSONValue[] });
|
|
80
85
|
}
|
|
81
86
|
if (Array.isArray(schema.anyOf)) {
|
|
82
87
|
return this.validateAnyOf(key, value, schema as ValidatablePreference & { anyOf: ValidatablePreference[] });
|
|
83
88
|
}
|
|
89
|
+
if (Array.isArray(schema.oneOf)) {
|
|
90
|
+
return this.validateOneOf(key, value, schema as ValidatablePreference & { oneOf: ValidatablePreference[] });
|
|
91
|
+
}
|
|
84
92
|
if (schema.type === undefined) {
|
|
85
93
|
console.warn('Request to validate preference with no type information:', key);
|
|
86
94
|
return value;
|
|
@@ -149,6 +157,28 @@ export class PreferenceValidationService {
|
|
|
149
157
|
return candidate;
|
|
150
158
|
}
|
|
151
159
|
|
|
160
|
+
protected validateOneOf(key: string, value: JSONValue, schema: ValidatablePreference & { oneOf: ValidatablePreference[] }): JSONValue {
|
|
161
|
+
let passed = false;
|
|
162
|
+
for (const subSchema of schema.oneOf) {
|
|
163
|
+
const validValue = this.validateBySchema(key, value, subSchema);
|
|
164
|
+
if (!passed && validValue === value) {
|
|
165
|
+
passed = true;
|
|
166
|
+
} else if (passed && validValue === value) {
|
|
167
|
+
passed = false;
|
|
168
|
+
break;
|
|
169
|
+
}
|
|
170
|
+
}
|
|
171
|
+
if (passed) {
|
|
172
|
+
return value;
|
|
173
|
+
}
|
|
174
|
+
if (schema.default !== undefined || schema.defaultValue !== undefined) {
|
|
175
|
+
const configuredDefault = this.getDefaultFromSchema(schema);
|
|
176
|
+
return this.validateOneOf(key, configuredDefault, { ...schema, default: undefined, defaultValue: undefined });
|
|
177
|
+
}
|
|
178
|
+
console.log(`While validating ${key}, failed to find a valid value or default value. Using configured value ${value}.`);
|
|
179
|
+
return value;
|
|
180
|
+
}
|
|
181
|
+
|
|
152
182
|
protected mapValidators(key: string, value: JSONValue, validators: Iterable<(value: JSONValue) => JSONValue>): JSONValue {
|
|
153
183
|
const candidates = [];
|
|
154
184
|
for (const validator of validators) {
|
|
@@ -160,26 +190,73 @@ export class PreferenceValidationService {
|
|
|
160
190
|
}
|
|
161
191
|
return candidates[0];
|
|
162
192
|
}
|
|
163
|
-
|
|
164
193
|
protected validateArray(key: string, value: JSONValue, schema: ValidatablePreference): JSONValue[] {
|
|
165
194
|
const candidate = Array.isArray(value) ? value : this.getDefaultFromSchema(schema);
|
|
166
195
|
if (!Array.isArray(candidate)) {
|
|
167
196
|
return [];
|
|
168
197
|
}
|
|
169
|
-
if (!schema.items
|
|
198
|
+
if (!schema.items && !schema.prefixItems) {
|
|
170
199
|
console.warn('Requested validation of array without item specification:', key);
|
|
171
200
|
return candidate;
|
|
172
201
|
}
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
const validated = this.validateBySchema(key, item, schema.items);
|
|
176
|
-
if (validated === item) {
|
|
177
|
-
valid.push(item);
|
|
178
|
-
}
|
|
202
|
+
if (Array.isArray(schema.items) || Array.isArray(schema.prefixItems)) {
|
|
203
|
+
return this.validateTuple(key, value, schema as ValidatablePreferenceTuple);
|
|
179
204
|
}
|
|
205
|
+
const itemSchema = schema.items!;
|
|
206
|
+
const valid = candidate.filter(item => this.validateBySchema(key, item, itemSchema) === item);
|
|
180
207
|
return valid.length === candidate.length ? candidate : valid;
|
|
181
208
|
}
|
|
182
209
|
|
|
210
|
+
protected validateTuple(key: string, value: JSONValue, schema: ValidatablePreferenceTuple): JSONValue[] {
|
|
211
|
+
const defaultValue = this.getDefaultFromSchema(schema);
|
|
212
|
+
const maybeCandidate = Array.isArray(value) ? value : defaultValue;
|
|
213
|
+
// If we find that the provided value is not valid, we immediately bail and try the default value instead.
|
|
214
|
+
const shouldTryDefault = Array.isArray(schema.defaultValue ?? schema.default) && !PreferenceProvider.deepEqual(defaultValue, maybeCandidate);
|
|
215
|
+
const tryDefault = () => this.validateTuple(key, defaultValue, schema);
|
|
216
|
+
const candidate = Array.isArray(maybeCandidate) ? maybeCandidate : [];
|
|
217
|
+
// Only `prefixItems` is officially part of the JSON Schema spec, but `items` as array was part of a draft and was used by VSCode.
|
|
218
|
+
const tuple = (schema.prefixItems ?? schema.items) as Required<ValidatablePreference>['prefixItems'];
|
|
219
|
+
const lengthIsWrong = candidate.length < tuple.length || (candidate.length > tuple.length && !schema.additionalItems);
|
|
220
|
+
if (lengthIsWrong && shouldTryDefault) { return tryDefault(); }
|
|
221
|
+
let valid = true;
|
|
222
|
+
const validItems: JSONValue[] = [];
|
|
223
|
+
for (const [index, subschema] of tuple.entries()) {
|
|
224
|
+
const targetItem = candidate[index];
|
|
225
|
+
const validatedItem = targetItem === undefined ? this.getDefaultFromSchema(subschema) : this.validateBySchema(key, targetItem, subschema);
|
|
226
|
+
valid &&= validatedItem === targetItem;
|
|
227
|
+
if (!valid && shouldTryDefault) { return tryDefault(); }
|
|
228
|
+
validItems.push(validatedItem);
|
|
229
|
+
};
|
|
230
|
+
if (candidate.length > tuple.length) {
|
|
231
|
+
if (!schema.additionalItems) {
|
|
232
|
+
return validItems;
|
|
233
|
+
} else if (schema.additionalItems === true && !valid) {
|
|
234
|
+
validItems.push(...candidate.slice(tuple.length));
|
|
235
|
+
return validItems;
|
|
236
|
+
} else if (schema.additionalItems !== true) {
|
|
237
|
+
const applicableSchema = schema.additionalItems;
|
|
238
|
+
for (let i = tuple.length; i < candidate.length; i++) {
|
|
239
|
+
const targetItem = candidate[i];
|
|
240
|
+
const validatedItem = this.validateBySchema(key, targetItem, applicableSchema);
|
|
241
|
+
if (validatedItem === targetItem) {
|
|
242
|
+
validItems.push(targetItem);
|
|
243
|
+
} else {
|
|
244
|
+
valid = false;
|
|
245
|
+
if (shouldTryDefault) { return tryDefault(); }
|
|
246
|
+
}
|
|
247
|
+
}
|
|
248
|
+
}
|
|
249
|
+
}
|
|
250
|
+
return valid ? candidate : validItems;
|
|
251
|
+
}
|
|
252
|
+
|
|
253
|
+
protected validateConst(key: string, value: JSONValue, schema: ValidatablePreference & { const: JSONValue }): JSONValue {
|
|
254
|
+
if (PreferenceProvider.deepEqual(value, schema.const)) {
|
|
255
|
+
return value;
|
|
256
|
+
}
|
|
257
|
+
return schema.const;
|
|
258
|
+
}
|
|
259
|
+
|
|
183
260
|
protected validateEnum(key: string, value: JSONValue, schema: ValidatablePreference & { enum: JSONValue[] }): JSONValue {
|
|
184
261
|
const options = schema.enum;
|
|
185
262
|
if (options.some(option => PreferenceProvider.deepEqual(option, value))) {
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
// *****************************************************************************
|
|
2
|
-
// Copyright (C)
|
|
2
|
+
// Copyright (C) 2022 TypeFox and others.
|
|
3
3
|
//
|
|
4
4
|
// This program and the accompanying materials are made available under the
|
|
5
5
|
// terms of the Eclipse Public License v. 2.0 which is available at
|
|
@@ -16,9 +16,15 @@
|
|
|
16
16
|
|
|
17
17
|
import { nls } from '../common/nls';
|
|
18
18
|
import { Endpoint } from './endpoint';
|
|
19
|
+
import { OS } from '../common/os';
|
|
19
20
|
import { FrontendApplicationConfigProvider } from './frontend-application-config-provider';
|
|
20
21
|
|
|
21
|
-
|
|
22
|
+
function fetchFrom(path: string): Promise<Response> {
|
|
23
|
+
const endpoint = new Endpoint({ path }).getRestUrl().toString();
|
|
24
|
+
return fetch(endpoint);
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
async function loadTranslations(): Promise<void> {
|
|
22
28
|
const defaultLocale = FrontendApplicationConfigProvider.get().defaultLocale;
|
|
23
29
|
if (defaultLocale && !nls.locale) {
|
|
24
30
|
Object.assign(nls, {
|
|
@@ -26,8 +32,24 @@ export async function loadTranslations(): Promise<void> {
|
|
|
26
32
|
});
|
|
27
33
|
}
|
|
28
34
|
if (nls.locale) {
|
|
29
|
-
const
|
|
30
|
-
const response = await fetch(endpoint);
|
|
35
|
+
const response = await fetchFrom(`/i18n/${nls.locale}`);
|
|
31
36
|
nls.localization = await response.json();
|
|
32
37
|
}
|
|
33
38
|
}
|
|
39
|
+
|
|
40
|
+
async function loadBackendOS(): Promise<void> {
|
|
41
|
+
const response = await fetchFrom('/os');
|
|
42
|
+
const osType = await response.text() as OS.Type;
|
|
43
|
+
const isWindows = osType === 'Windows';
|
|
44
|
+
const isOSX = osType === 'OSX';
|
|
45
|
+
OS.backend.isOSX = isOSX;
|
|
46
|
+
OS.backend.isWindows = isWindows;
|
|
47
|
+
OS.backend.type = () => osType;
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
export async function preload(): Promise<void> {
|
|
51
|
+
await Promise.allSettled([
|
|
52
|
+
loadTranslations(),
|
|
53
|
+
loadBackendOS()
|
|
54
|
+
]);
|
|
55
|
+
}
|
|
@@ -46,7 +46,7 @@ export class QuickPickServiceImpl implements QuickPickService {
|
|
|
46
46
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
47
47
|
private items: Array<any> = [];
|
|
48
48
|
|
|
49
|
-
async show<T extends QuickPickItem>(items: Array<T | QuickPickSeparator>, options?: QuickPickOptions<T>): Promise<T> {
|
|
49
|
+
async show<T extends QuickPickItem>(items: Array<T | QuickPickSeparator>, options?: QuickPickOptions<T>): Promise<T | undefined> {
|
|
50
50
|
this.items = items;
|
|
51
51
|
const opts = Object.assign({}, options, {
|
|
52
52
|
onDidAccept: () => this.onDidAcceptEmitter.fire(),
|
|
@@ -56,7 +56,7 @@ export class QuickPickServiceImpl implements QuickPickService {
|
|
|
56
56
|
onDidHide: () => this.onDidHideEmitter.fire(),
|
|
57
57
|
onDidTriggerButton: (btn: QuickInputButtonHandle) => this.onDidTriggerButtonEmitter.fire(btn),
|
|
58
58
|
});
|
|
59
|
-
return this.quickInputService?.showQuickPick(this.items, opts);
|
|
59
|
+
return this.quickInputService?.showQuickPick<T>(this.items, opts);
|
|
60
60
|
}
|
|
61
61
|
|
|
62
62
|
hide(): void {
|
|
@@ -59,8 +59,8 @@ export class ResourceContextKey {
|
|
|
59
59
|
this.resourceFileName.set(resourceUri && resourceUri.path.base);
|
|
60
60
|
this.resourceExtname.set(resourceUri && resourceUri.path.ext);
|
|
61
61
|
this.resourceLangId.set(resourceUri && this.getLanguageId(resourceUri));
|
|
62
|
-
this.resourceDirName.set(resourceUri &&
|
|
63
|
-
this.resourcePath.set(resourceUri && resourceUri
|
|
62
|
+
this.resourceDirName.set(resourceUri && resourceUri.path.dir.fsPath());
|
|
63
|
+
this.resourcePath.set(resourceUri && resourceUri.path.fsPath());
|
|
64
64
|
}
|
|
65
65
|
|
|
66
66
|
protected getLanguageId(uri: URI | undefined): string | undefined {
|
package/src/browser/saveable.ts
CHANGED
|
@@ -37,7 +37,7 @@ export interface Saveable {
|
|
|
37
37
|
/**
|
|
38
38
|
* Creates a snapshot of the dirty state.
|
|
39
39
|
*/
|
|
40
|
-
createSnapshot?():
|
|
40
|
+
createSnapshot?(): Saveable.Snapshot;
|
|
41
41
|
/**
|
|
42
42
|
* Applies the given snapshot to the dirty state.
|
|
43
43
|
*/
|
|
@@ -56,6 +56,8 @@ export namespace Saveable {
|
|
|
56
56
|
*/
|
|
57
57
|
soft?: boolean
|
|
58
58
|
}
|
|
59
|
+
|
|
60
|
+
export type Snapshot = { value: string } | { read(): string | null };
|
|
59
61
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
60
62
|
export function isSource(arg: any): arg is SaveableSource {
|
|
61
63
|
return !!arg && ('saveable' in arg) && is(arg.saveable);
|
|
@@ -1418,6 +1418,7 @@ export class ApplicationShell extends Widget {
|
|
|
1418
1418
|
this.statusBar.removeElement(BOTTOM_PANEL_TOGGLE_ID);
|
|
1419
1419
|
} else {
|
|
1420
1420
|
const element: StatusBarEntry = {
|
|
1421
|
+
name: 'Toggle Bottom Panel',
|
|
1421
1422
|
text: '$(codicon-window)',
|
|
1422
1423
|
alignment: StatusBarAlignment.RIGHT,
|
|
1423
1424
|
tooltip: 'Toggle Bottom Panel',
|
|
@@ -38,7 +38,9 @@ export interface StatusBarEntry {
|
|
|
38
38
|
*/
|
|
39
39
|
text: string;
|
|
40
40
|
alignment: StatusBarAlignment;
|
|
41
|
+
name?: string;
|
|
41
42
|
color?: string;
|
|
43
|
+
backgroundColor?: string;
|
|
42
44
|
className?: string;
|
|
43
45
|
tooltip?: string;
|
|
44
46
|
command?: string;
|
|
@@ -195,7 +197,8 @@ export class StatusBarImpl extends ReactWidget implements StatusBar {
|
|
|
195
197
|
}
|
|
196
198
|
|
|
197
199
|
attrs.style = {
|
|
198
|
-
color: entry.color || this.color
|
|
200
|
+
color: entry.color || this.color,
|
|
201
|
+
backgroundColor: entry.backgroundColor
|
|
199
202
|
};
|
|
200
203
|
|
|
201
204
|
return attrs;
|
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
/********************************************************************************
|
|
2
|
+
* Copyright (C) 2022 TypeFox 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 WITH Classpath-exception-2.0
|
|
15
|
+
********************************************************************************/
|
|
16
|
+
|
|
17
|
+
.theia-select-component {
|
|
18
|
+
background-color: var(--theia-dropdown-background);
|
|
19
|
+
outline: var(--theia-dropdown-border) solid 1px;
|
|
20
|
+
outline-offset: -1px;
|
|
21
|
+
min-height: 23px;
|
|
22
|
+
min-width: 90px;
|
|
23
|
+
padding: 0px 8px;
|
|
24
|
+
display: flex;
|
|
25
|
+
align-items: center;
|
|
26
|
+
user-select: none;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
.theia-select-component .theia-select-component-label {
|
|
30
|
+
width: 100%;
|
|
31
|
+
color: var(--theia-dropdown-foreground);
|
|
32
|
+
white-space: nowrap;
|
|
33
|
+
text-overflow: ellipsis;
|
|
34
|
+
overflow: hidden;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
.theia-select-component:focus {
|
|
38
|
+
outline-color: var(--theia-focusBorder);
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
.theia-select-component-dropdown {
|
|
42
|
+
font-family: var(--theia-ui-font-family);
|
|
43
|
+
font-size: var(--theia-ui-font-size1);
|
|
44
|
+
color: var(--theia-foreground);
|
|
45
|
+
background-color: var(--theia-settings-dropdownBackground);
|
|
46
|
+
outline: var(--theia-focusBorder) solid 1px;
|
|
47
|
+
outline-offset: -1px;
|
|
48
|
+
user-select: none;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
.theia-select-component-dropdown .theia-select-component-option {
|
|
52
|
+
text-overflow: ellipsis;
|
|
53
|
+
overflow: hidden;
|
|
54
|
+
display: flex;
|
|
55
|
+
padding: 2px 5px;
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
.theia-select-component-dropdown .theia-select-component-description {
|
|
59
|
+
padding: 6px 5px;
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
.theia-select-component-dropdown .theia-select-component-description:first-child {
|
|
63
|
+
border-bottom: 1px solid var(--theia-editorWidget-border);
|
|
64
|
+
margin-bottom: 2px;
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
.theia-select-component-dropdown .theia-select-component-description:last-child {
|
|
68
|
+
border-top: 1px solid var(--theia-editorWidget-border);
|
|
69
|
+
margin-top: 2px;
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
.theia-select-component-dropdown .theia-select-component-option .theia-select-component-option-value {
|
|
73
|
+
width: 100%;
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
.theia-select-component-dropdown .theia-select-component-option .theia-select-component-option-detail {
|
|
77
|
+
padding-left: 4px;
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
.theia-select-component-dropdown .theia-select-component-option:not(.selected) .theia-select-component-option-detail {
|
|
81
|
+
color: var(--theia-textLink-foreground);
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
.theia-select-component-dropdown .theia-select-component-option.selected {
|
|
85
|
+
color: var(--theia-list-activeSelectionForeground);
|
|
86
|
+
background: var(--theia-list-activeSelectionBackground);
|
|
87
|
+
outline: var(--theia-focusBorder) solid 1px;
|
|
88
|
+
outline-offset: -1px;
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
.theia-select-component-dropdown .theia-select-component-separator {
|
|
92
|
+
width: 84px;
|
|
93
|
+
height: 1px;
|
|
94
|
+
margin: 3px 3px;
|
|
95
|
+
background: var(--theia-foreground);
|
|
96
|
+
}
|
|
@@ -116,12 +116,15 @@
|
|
|
116
116
|
.theia-TreeNode.theia-mod-not-selectable {
|
|
117
117
|
color: var(--theia-descriptionForeground);
|
|
118
118
|
}
|
|
119
|
+
|
|
119
120
|
.theia-TreeNode.theia-mod-not-selectable:hover {
|
|
120
121
|
background: none;
|
|
121
122
|
cursor: default;
|
|
122
123
|
}
|
|
123
124
|
|
|
124
125
|
.theia-TreeNodeSegment {
|
|
126
|
+
display: flex;
|
|
127
|
+
align-items: center;
|
|
125
128
|
flex-grow: 0;
|
|
126
129
|
user-select: none;
|
|
127
130
|
white-space: nowrap;
|
|
@@ -137,6 +140,7 @@
|
|
|
137
140
|
.theia-TreeNodeTail {
|
|
138
141
|
min-width: 1rem;
|
|
139
142
|
text-align: center;
|
|
143
|
+
justify-content: center;
|
|
140
144
|
}
|
|
141
145
|
|
|
142
146
|
.theia-TreeNodeSegment mark {
|
|
@@ -159,10 +163,12 @@
|
|
|
159
163
|
height: var(--theia-content-line-height);
|
|
160
164
|
border-right: var(--theia-border-width) solid transparent;
|
|
161
165
|
}
|
|
166
|
+
|
|
162
167
|
.theia-tree-node-indent.always,
|
|
163
168
|
.theia-TreeContainer:hover .theia-tree-node-indent.hover {
|
|
164
169
|
border-color: var(--theia-tree-inactiveIndentGuidesStroke);
|
|
165
170
|
}
|
|
171
|
+
|
|
166
172
|
.theia-tree-node-indent.active {
|
|
167
173
|
border-color: var(--theia-tree-indentGuidesStroke);
|
|
168
174
|
}
|
|
@@ -75,11 +75,11 @@
|
|
|
75
75
|
}
|
|
76
76
|
|
|
77
77
|
.p-Widget > .theia-view-container-part-header {
|
|
78
|
-
|
|
78
|
+
box-shadow: 0 1px 0 var(--theia-sideBarSectionHeader-border) inset;
|
|
79
79
|
}
|
|
80
80
|
|
|
81
81
|
.p-Widget.p-first-visible > .theia-view-container-part-header {
|
|
82
|
-
|
|
82
|
+
box-shadow: none;
|
|
83
83
|
}
|
|
84
84
|
|
|
85
85
|
.theia-view-container-part-header .theia-ExpansionToggle {
|
|
@@ -806,19 +806,31 @@ export class TreeWidget extends ReactWidget implements StatefulWidget {
|
|
|
806
806
|
return this.renderTailDecorationsForNode(node, props, tailDecorations);
|
|
807
807
|
}
|
|
808
808
|
|
|
809
|
-
protected renderTailDecorationsForNode(node: TreeNode, props: NodeProps, tailDecorations:
|
|
810
|
-
|
|
809
|
+
protected renderTailDecorationsForNode(node: TreeNode, props: NodeProps, tailDecorations: TreeDecoration.TailDecoration.AnyPartial[]): React.ReactNode {
|
|
810
|
+
let dotDecoration: TreeDecoration.TailDecoration.AnyPartial | undefined;
|
|
811
|
+
const otherDecorations: TreeDecoration.TailDecoration.AnyPartial[] = [];
|
|
812
|
+
tailDecorations.reverse().forEach(decoration => {
|
|
813
|
+
if (TreeDecoration.TailDecoration.isDotDecoration(decoration)) {
|
|
814
|
+
dotDecoration ||= decoration;
|
|
815
|
+
} else if (decoration.data || decoration.icon || decoration.iconClass) {
|
|
816
|
+
otherDecorations.push(decoration);
|
|
817
|
+
}
|
|
818
|
+
});
|
|
819
|
+
const decorationsToRender = dotDecoration ? [dotDecoration, ...otherDecorations] : otherDecorations;
|
|
811
820
|
return <React.Fragment>
|
|
812
|
-
{
|
|
813
|
-
const { tooltip } = decoration;
|
|
814
|
-
const
|
|
815
|
-
const color = (decoration as TreeDecoration.TailDecorationIcon).color;
|
|
821
|
+
{decorationsToRender.map((decoration, index) => {
|
|
822
|
+
const { tooltip, data, fontData, color, icon, iconClass } = decoration;
|
|
823
|
+
const iconToRender = icon ?? iconClass;
|
|
816
824
|
const className = [TREE_NODE_SEGMENT_CLASS, TREE_NODE_TAIL_CLASS].join(' ');
|
|
817
825
|
const style = fontData ? this.applyFontStyles({}, fontData) : color ? { color } : undefined;
|
|
818
|
-
const
|
|
819
|
-
|
|
826
|
+
const content = data ? data : iconToRender
|
|
827
|
+
? <span
|
|
828
|
+
key={node.id + 'icon' + index}
|
|
829
|
+
className={this.getIconClass(iconToRender, iconToRender === 'circle' ? [TreeDecoration.Styles.DECORATOR_SIZE_CLASS] : [])}
|
|
830
|
+
></span>
|
|
831
|
+
: '';
|
|
820
832
|
return <div key={node.id + className + index} className={className} style={style} title={tooltip}>
|
|
821
|
-
{content}{index !==
|
|
833
|
+
{content}{index !== decorationsToRender.length - 1 ? ',' : ''}
|
|
822
834
|
</div>;
|
|
823
835
|
})}
|
|
824
836
|
</React.Fragment>;
|
|
@@ -97,6 +97,20 @@ export namespace WidgetDecoration {
|
|
|
97
97
|
*/
|
|
98
98
|
readonly fontData?: FontData;
|
|
99
99
|
}
|
|
100
|
+
|
|
101
|
+
export namespace TailDecoration {
|
|
102
|
+
/**
|
|
103
|
+
* Combines all fields of all `TailDecoration` variants
|
|
104
|
+
*/
|
|
105
|
+
export type AnyPartial = Partial<TailDecoration & TailDecorationIcon & TailDecorationIconClass>;
|
|
106
|
+
/**
|
|
107
|
+
* Represents any permissible concrete `TailDecoration` variation.
|
|
108
|
+
*/
|
|
109
|
+
export type AnyConcrete = TailDecoration | TailDecorationIcon | TailDecorationIconClass;
|
|
110
|
+
export function isDotDecoration(decoration: AnyPartial): decoration is TailDecorationIcon {
|
|
111
|
+
return decoration.icon === 'circle';
|
|
112
|
+
}
|
|
113
|
+
}
|
|
100
114
|
export interface TailDecorationIcon extends BaseTailDecoration {
|
|
101
115
|
/**
|
|
102
116
|
* This should be the name of the Font Awesome icon with out the `fa fa-` prefix, just the name, for instance `paw`.
|