Skip to content

Commit 13ea319

Browse files
author
Arnold Trakhtenberg
authored
Merge pull request #32 from launchdarkly/2.2.1
Release 2.2.1
2 parents 3b5e6d7 + a3f9cdf commit 13ea319

File tree

6 files changed

+77
-25
lines changed

6 files changed

+77
-25
lines changed

CHANGELOG.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,12 @@
22

33
All notable changes to the "launchdarkly" extension will be documented in this file.
44

5+
## [2.2.1] - 2020-02-19
6+
7+
### Added
8+
9+
- The hover display surfaces the feature flag's name
10+
511
## [2.2.0] - 2020-01-06
612

713
### Added

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
"name": "launchdarkly",
33
"displayName": "LaunchDarkly",
44
"description": "View LaunchDarkly feature flags in your editor.",
5-
"version": "2.2.0",
5+
"version": "2.2.1",
66
"publisher": "launchdarkly",
77
"engines": {
88
"vscode": "^1.34.0"

src/flagStore.ts

Lines changed: 24 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ import StreamProcessor = require('launchdarkly-node-server-sdk/streaming');
55
import Requestor = require('launchdarkly-node-server-sdk/requestor');
66
import { debounce } from 'lodash';
77

8-
import { FlagConfiguration } from './models';
8+
import { Flag, FlagConfiguration, FlagWithConfiguration } from './models';
99
import { Configuration } from './configuration';
1010
import { LaunchDarklyAPI } from './api';
1111

@@ -15,6 +15,8 @@ const DATA_KIND = { namespace: 'features' };
1515
export class FlagStore {
1616
private readonly config: Configuration;
1717
private readonly store: LDFeatureStore;
18+
private readonly flagMetadata: { [key: string]: Flag } = {};
19+
1820
private readonly api: LaunchDarklyAPI;
1921
private readonly streamingConfigOptions = ['accessToken', 'baseUri', 'streamUri', 'project', 'env'];
2022
private updateProcessor: LDStreamProcessor;
@@ -114,6 +116,27 @@ export class FlagStore {
114116
};
115117
}
116118

119+
getFeatureFlag(key: string): Promise<FlagWithConfiguration | null> {
120+
let flag = this.flagMetadata[key];
121+
return new Promise((resolve, reject) => {
122+
this.store.get(DATA_KIND, key, async (res: FlagConfiguration) => {
123+
if (!res) {
124+
resolve(null);
125+
}
126+
if (!flag || flag.environments[this.config.env].version < res.version) {
127+
try {
128+
flag = await this.api.getFeatureFlag(this.config.project, key, this.config.env);
129+
this.flagMetadata[key] = flag;
130+
resolve({ flag, config: res });
131+
} catch (e) {
132+
console.error(`Could not retrieve feature flag metadata for ${key}: ${e}`);
133+
reject(e);
134+
}
135+
}
136+
});
137+
});
138+
}
139+
117140
allFlags(): Promise<FlagConfiguration[]> {
118141
return new Promise(resolve => {
119142
this.store.all(DATA_KIND, resolve);

src/models.ts

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ export class Project extends Resource {
1010

1111
export class Environment extends Resource {
1212
apiKey: string;
13+
version: number;
1314
_site: { href: string };
1415
}
1516

@@ -26,4 +27,10 @@ export class FlagConfiguration {
2627
targets: any;
2728
rules: Array<any>;
2829
on: boolean;
30+
version: number;
31+
}
32+
33+
export class FlagWithConfiguration {
34+
flag: Flag;
35+
config: FlagConfiguration;
2936
}

src/providers.ts

Lines changed: 25 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ import { kebabCase } from 'lodash';
2020
import { Configuration } from './configuration';
2121
import { ConfigurationMenu } from './configurationMenu';
2222
import { LaunchDarklyAPI } from './api';
23-
import { Environment, FlagConfiguration } from './models';
23+
import { Environment, Flag, FlagConfiguration } from './models';
2424
import { FlagStore } from './flagStore';
2525

2626
const STRING_DELIMETERS = ['"', "'", '`'];
@@ -80,13 +80,13 @@ export function register(ctx: ExtensionContext, config: Configuration, flagStore
8080
}
8181

8282
try {
83-
await openFlagInBrowser(config, flagKey, api);
83+
await openFlagInBrowser(config, flagKey, flagStore);
8484
} catch (err) {
8585
let errMsg = `Encountered an unexpected error retrieving the flag ${flagKey}`;
8686
if (err.statusCode == 404) {
8787
// Try resolving the flag key to kebab case
8888
try {
89-
await openFlagInBrowser(config, kebabCase(flagKey), api);
89+
await openFlagInBrowser(config, kebabCase(flagKey), flagStore);
9090
return;
9191
} catch (err) {
9292
if (err.statusCode == 404) {
@@ -113,13 +113,18 @@ class LaunchDarklyHoverProvider implements HoverProvider {
113113
public provideHover(document: TextDocument, position: Position): Thenable<Hover> {
114114
return new Promise(async (resolve, reject) => {
115115
if (this.config.enableHover) {
116-
const flags = await this.flagStore.allFlags();
117116
let candidate = document.getText(document.getWordRangeAtPosition(position, FLAG_KEY_REGEX));
118-
let flag = flags[candidate] || flags[kebabCase(candidate)];
119-
if (flag) {
120-
let hover = generateHoverString(flag);
121-
resolve(new Hover(hover));
122-
return;
117+
try {
118+
let data =
119+
(await this.flagStore.getFeatureFlag(candidate)) ||
120+
(await this.flagStore.getFeatureFlag(kebabCase(candidate)));
121+
if (data) {
122+
let hover = generateHoverString(data.flag, data.config);
123+
resolve(new Hover(hover));
124+
return;
125+
}
126+
} catch (e) {
127+
reject(e);
123128
}
124129
}
125130
reject();
@@ -154,8 +159,8 @@ class LaunchDarklyCompletionItemProvider implements CompletionItemProvider {
154159
}
155160
}
156161

157-
const openFlagInBrowser = async (config: Configuration, flagKey: string, api: LaunchDarklyAPI) => {
158-
const flag = await api.getFeatureFlag(config.project, flagKey, config.env);
162+
const openFlagInBrowser = async (config: Configuration, flagKey: string, flagStore: FlagStore) => {
163+
const { flag } = await flagStore.getFeatureFlag(flagKey);
159164

160165
// Default to first environment
161166
let env: Environment = Object.values(flag.environments)[0];
@@ -174,19 +179,20 @@ const openFlagInBrowser = async (config: Configuration, flagKey: string, api: La
174179
opn(url.resolve(config.baseUri, sitePath));
175180
};
176181

177-
export function generateHoverString(flag: FlagConfiguration) {
182+
export function generateHoverString(flag: Flag, c: FlagConfiguration) {
178183
return `**LaunchDarkly feature flag**\n
179-
Key: ${flag.key}
180-
Enabled: ${flag.on}
181-
Default variation: ${JSON.stringify(flag.variations[flag.fallthrough.variation])}
182-
Off variation: ${JSON.stringify(flag.variations[flag.offVariation])}
183-
${plural(flag.prerequisites.length, 'prerequisite', 'prerequisites')}
184+
Name: ${flag.name}
185+
Key: ${c.key}
186+
Enabled: ${c.on}
187+
Default variation: ${JSON.stringify(c.variations[c.fallthrough.variation])}
188+
Off variation: ${JSON.stringify(c.variations[c.offVariation])}
189+
${plural(c.prerequisites.length, 'prerequisite', 'prerequisites')}
184190
${plural(
185-
flag.targets.reduce((acc, curr) => acc + curr.values.length, 0),
191+
c.targets.reduce((acc, curr) => acc + curr.values.length, 0),
186192
'user target',
187193
'user targets',
188194
)}
189-
${plural(flag.rules.length, 'rule', 'rules')}`;
195+
${plural(c.rules.length, 'rule', 'rules')}`;
190196
}
191197

192198
function plural(count: number, singular: string, plural: string) {

test/providers.test.ts

Lines changed: 14 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,18 @@
11
import * as assert from 'assert';
2-
import * as providers from '../src/providers';
32
import * as path from 'path';
43
import * as vscode from 'vscode';
54

6-
const flag = {
5+
import * as providers from '../src/providers';
6+
import { Flag, FlagConfiguration } from '../src/models';
7+
8+
const flag: Flag = {
9+
name: "Test",
10+
key: "test",
11+
tags: [],
12+
environments: null,
13+
}
14+
15+
const flagConfig: FlagConfiguration = {
716
key: 'test',
817
on: true,
918
variations: ['SomeVariation', { thisIsJson: 'AnotherVariation' }],
@@ -14,15 +23,16 @@ const flag = {
1423
prerequisites: ['something'],
1524
targets: [{ values: ['user', 'anotheruser'] }, { values: ['someotheruser'] }],
1625
rules: [],
26+
version: 1,
1727
};
1828

1929
let testPath = path.join(__dirname, '..', '..', 'test');
2030

2131
suite('provider utils tests', () => {
2232
test('generateHoverString', () => {
2333
assert.equal(
24-
`**LaunchDarkly feature flag**\n\n\tKey: test\n\tEnabled: true\n\tDefault variation: "SomeVariation"\n\tOff variation: {"thisIsJson":"AnotherVariation"}\n\t1 prerequisite\n\t3 user targets\n\t0 rules`,
25-
providers.generateHoverString(flag),
34+
`**LaunchDarkly feature flag**\n\n\tName: Test\n\tKey: test\n\tEnabled: true\n\tDefault variation: "SomeVariation"\n\tOff variation: {"thisIsJson":"AnotherVariation"}\n\t1 prerequisite\n\t3 user targets\n\t0 rules`,
35+
providers.generateHoverString(flag, flagConfig),
2636
);
2737
});
2838

0 commit comments

Comments
 (0)