Skip to content

Commit b2b4ea1

Browse files
Filter out IDEs on the backend (#17324)
1 parent 450dc2b commit b2b4ea1

File tree

8 files changed

+153
-108
lines changed

8 files changed

+153
-108
lines changed

components/dashboard/src/components/SelectIDEComponent.tsx

Lines changed: 5 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -5,11 +5,10 @@
55
*/
66

77
import { IDEOption, IDEOptions } from "@gitpod/gitpod-protocol/lib/ide-protocol";
8-
import { useCallback, useContext, useEffect, useState } from "react";
8+
import { useCallback, useEffect, useState } from "react";
99
import { getGitpodService } from "../service/service";
1010
import { DropDown2, DropDown2Element } from "./DropDown2";
1111
import Editor from "../icons/Editor.svg";
12-
import { FeatureFlagContext } from "../contexts/FeatureFlagContext";
1312

1413
interface SelectIDEComponentProps {
1514
selectedIdeOption?: string;
@@ -18,15 +17,12 @@ interface SelectIDEComponentProps {
1817
setError?: (error?: string) => void;
1918
}
2019

21-
function filteredIdeOptions(ideOptions: IDEOptions, experimentalTurnedOn: boolean) {
22-
return IDEOptions.asArray(ideOptions)
23-
.filter((x) => !x.hidden)
24-
.filter((x) => (x.experimental ? experimentalTurnedOn : true));
20+
function filteredIdeOptions(ideOptions: IDEOptions) {
21+
return IDEOptions.asArray(ideOptions).filter((x) => !x.hidden);
2522
}
2623

2724
export default function SelectIDEComponent(props: SelectIDEComponentProps) {
2825
const [ideOptions, setIdeOptions] = useState<IDEOptions>();
29-
const { experimentalIdes } = useContext(FeatureFlagContext);
3026

3127
useEffect(() => {
3228
getGitpodService().server.getIDEOptions().then(setIdeOptions);
@@ -36,7 +32,7 @@ export default function SelectIDEComponent(props: SelectIDEComponentProps) {
3632
if (!ideOptions) {
3733
return [];
3834
}
39-
const options = filteredIdeOptions(ideOptions, experimentalIdes);
35+
const options = filteredIdeOptions(ideOptions);
4036
const result: DropDown2Element[] = [];
4137
for (const ide of options.filter((ide) =>
4238
`${ide.label}${ide.title}${ide.notes}${ide.id}`.toLowerCase().includes(search.toLowerCase()),
@@ -57,7 +53,7 @@ export default function SelectIDEComponent(props: SelectIDEComponentProps) {
5753
}
5854
return result;
5955
},
60-
[experimentalIdes, ideOptions, props.useLatest],
56+
[ideOptions, props.useLatest],
6157
);
6258
const internalOnSelectionChange = (id: string) => {
6359
const { ide, useLatest } = parseId(id);

components/dashboard/src/contexts/FeatureFlagContext.tsx

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,6 @@ const defaultFeatureFlags = {
2929
userGitAuthProviders: false,
3030
newSignupFlow: false,
3131
linkedinConnectionForOnboarding: false,
32-
experimentalIdes: false,
3332
};
3433

3534
const FeatureFlagContext = createContext<FeatureFlagsType>(defaultFeatureFlags);
@@ -48,7 +47,6 @@ const FeatureFlagContextProvider: React.FC = ({ children }) => {
4847
const [userGitAuthProviders, setUserGitAuthProviders] = useState<boolean>(false);
4948
const [newSignupFlow, setNewSignupFlow] = useState<boolean>(false);
5049
const [linkedinConnectionForOnboarding, setLinkedinConnectionForOnboarding] = useState<boolean>(false);
51-
const [experimentalIdes, setExperimentalIdes] = useState<boolean>(false);
5250

5351
useEffect(() => {
5452
if (!user) return;
@@ -67,7 +65,6 @@ const FeatureFlagContextProvider: React.FC = ({ children }) => {
6765
userGitAuthProviders: { defaultValue: false, setter: setUserGitAuthProviders },
6866
newSignupFlow: { defaultValue: false, setter: setNewSignupFlow },
6967
linkedinConnectionForOnboarding: { defaultValue: false, setter: setLinkedinConnectionForOnboarding },
70-
experimentalIdes: { defaultValue: false, setter: setExperimentalIdes },
7168
};
7269

7370
for (const [flagName, config] of Object.entries(featureFlags)) {
@@ -115,7 +112,6 @@ const FeatureFlagContextProvider: React.FC = ({ children }) => {
115112
userGitAuthProviders,
116113
newSignupFlow,
117114
linkedinConnectionForOnboarding,
118-
experimentalIdes,
119115
};
120116
}, [
121117
enablePersonalAccessTokens,
@@ -127,7 +123,6 @@ const FeatureFlagContextProvider: React.FC = ({ children }) => {
127123
startWithOptions,
128124
usePublicApiWorkspacesService,
129125
userGitAuthProviders,
130-
experimentalIdes,
131126
]);
132127

133128
return <FeatureFlagContext.Provider value={flags}>{children}</FeatureFlagContext.Provider>;

components/ide-service-api/go/ide.pb.go

Lines changed: 91 additions & 78 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

components/ide-service-api/ide.proto

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,9 @@ service IDEService {
1818
}
1919
}
2020

21-
message GetConfigRequest {}
21+
message GetConfigRequest {
22+
User user = 1;
23+
}
2224

2325
message GetConfigResponse {
2426
string content = 1;

components/ide-service-api/typescript/src/ide.pb.ts

Lines changed: 15 additions & 6 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

components/ide-service/pkg/server/server.go

Lines changed: 33 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,7 @@ type IDEServiceServer struct {
3636
parsedIDEConfigContent string
3737
ideConfig *config.IDEConfig
3838
ideConfigFileName string
39-
experiemntsClient experiments.Client
39+
experimentsClient experiments.Client
4040

4141
api.UnimplementedIDEServiceServer
4242
}
@@ -87,7 +87,7 @@ func New(cfg *config.ServiceConfiguration) *IDEServiceServer {
8787
s := &IDEServiceServer{
8888
config: cfg,
8989
ideConfigFileName: fn,
90-
experiemntsClient: experiments.NewClient(),
90+
experimentsClient: experiments.NewClient(),
9191
}
9292
return s
9393
}
@@ -97,9 +97,37 @@ func (s *IDEServiceServer) register(grpcServer *grpc.Server) {
9797
}
9898

9999
func (s *IDEServiceServer) GetConfig(ctx context.Context, req *api.GetConfigRequest) (*api.GetConfigResponse, error) {
100-
return &api.GetConfigResponse{
101-
Content: s.parsedIDEConfigContent,
102-
}, nil
100+
configCatClient := experiments.NewClient()
101+
attributes := experiments.Attributes{
102+
UserID: req.User.Id,
103+
UserEmail: req.User.GetEmail(),
104+
}
105+
106+
experimentalIdesEnabled := configCatClient.GetBoolValue(ctx, "experimentalIdes", false, attributes)
107+
108+
if experimentalIdesEnabled {
109+
// We can return everything
110+
return &api.GetConfigResponse{
111+
Content: s.parsedIDEConfigContent,
112+
}, nil
113+
} else {
114+
for key, ide := range s.ideConfig.IdeOptions.Options {
115+
if ide.Experimental && !experimentalIdesEnabled {
116+
delete(s.ideConfig.IdeOptions.Options, key)
117+
}
118+
}
119+
120+
parsedConfig, err := json.Marshal(s.ideConfig)
121+
if err != nil {
122+
log.WithError(err).Error("cannot marshal ide config")
123+
return nil, err
124+
}
125+
s.parsedIDEConfigContent = string(parsedConfig)
126+
127+
return &api.GetConfigResponse{
128+
Content: s.parsedIDEConfigContent,
129+
}, nil
130+
}
103131
}
104132

105133
func (s *IDEServiceServer) readIDEConfig(ctx context.Context, isInit bool) {

components/server/src/ide-service.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -34,10 +34,10 @@ export class IDEService {
3434

3535
private cacheConfig?: IDEConfig;
3636

37-
async getIDEConfig(): Promise<IDEConfig> {
37+
async getIDEConfig(request: { user: { id: string; email?: string } }): Promise<IDEConfig> {
3838
try {
39-
let resp = await this.ideService.getConfig({});
40-
let config: IDEConfig = JSON.parse(resp.content);
39+
const response = await this.ideService.getConfig(request);
40+
const config: IDEConfig = JSON.parse(response.content);
4141
this.cacheConfig = config;
4242
return config;
4343
} catch (e) {

components/server/src/workspace/gitpod-server-impl.ts

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3327,7 +3327,9 @@ export class GitpodServerImpl implements GitpodServerWithTracing, Disposable {
33273327
}
33283328

33293329
async getIDEOptions(ctx: TraceContext): Promise<IDEOptions> {
3330-
const ideConfig = await this.ideService.getIDEConfig();
3330+
const user = this.checkUser("identifyUser");
3331+
const email = User.getPrimaryEmail(user);
3332+
const ideConfig = await this.ideService.getIDEConfig({ user: { id: user.id, email } });
33313333
return ideConfig.ideOptions;
33323334
}
33333335

0 commit comments

Comments
 (0)