Skip to content

Commit aa07984

Browse files
authored
Include feature flags for all plugins using src attributes (#6304)
Updates individual HTML elements to include client feature flags as query parameters on their src attributes. Validated via a local tensorboard that the requests generated from these elements include the client feature flags as query parameters.
1 parent 356529f commit aa07984

File tree

10 files changed

+70
-38
lines changed

10 files changed

+70
-38
lines changed

tensorboard/components/tf_backend/router.ts

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,8 @@ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
1212
See the License for the specific language governing permissions and
1313
limitations under the License.
1414
==============================================================================*/
15+
import {FEATURE_FLAGS_QUERY_STRING_NAME} from '../../webapp/feature_flag/http/const';
16+
import {getFeatureFlagsToSendToServer} from '../tf_feature_flags/feature-flags';
1517
import {ExperimentId} from './type';
1618
import {QueryParams} from './urlPathHelpers';
1719

@@ -25,6 +27,11 @@ export interface Router {
2527
route: string,
2628
params?: URLSearchParams
2729
) => string;
30+
pluginRouteForSrc: (
31+
pluginName: string,
32+
route: string,
33+
params?: URLSearchParams
34+
) => string;
2835
pluginsListing: () => string;
2936
runs: () => string;
3037
runsForExperiment: (id: ExperimentId) => string;
@@ -64,6 +71,24 @@ export function createRouter(
6471
params
6572
);
6673
},
74+
pluginRouteForSrc: (
75+
pluginName: string,
76+
route: string,
77+
params: URLSearchParams = new URLSearchParams()
78+
): string => {
79+
const featureFlags = getFeatureFlagsToSendToServer();
80+
if (Object.keys(featureFlags).length > 0) {
81+
params.append(
82+
FEATURE_FLAGS_QUERY_STRING_NAME,
83+
JSON.stringify(featureFlags)
84+
);
85+
}
86+
return createDataPath(
87+
dataDir + '/plugin',
88+
`/${pluginName}${route}`,
89+
params
90+
);
91+
},
6792
pluginsListing: () =>
6893
createDataPath(
6994
dataDir,

tensorboard/plugins/audio/tf_audio_dashboard/tf-audio-loader.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -261,7 +261,7 @@ class _TfAudioLoader
261261
// the browser to reload the audio when the URL changes. The
262262
// backend doesn't care about the value.
263263
searchParam.append('ts', String(audioMetadata.wall_time));
264-
const url = getRouter().pluginRoute(
264+
const url = getRouter().pluginRouteForSrc(
265265
'audio',
266266
'/individualAudio',
267267
searchParam

tensorboard/plugins/custom_scalar/tf_custom_scalar_dashboard/tf-custom-scalar-margin-chart-card.ts

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -469,12 +469,13 @@ class _TfCustomScalarMarginChartCard
469469
}
470470
_downloadDataUrl(_nameToDataSeries, dataSeriesName) {
471471
const dataSeries = _nameToDataSeries[dataSeriesName];
472-
const getVars = {
472+
const getVars = new URLSearchParams({
473473
tag: dataSeries.getTag(),
474474
run: dataSeries.getRun(),
475-
};
476-
return addParams(
477-
getRouter().pluginRoute('custom_scalars', '/download_data'),
475+
});
476+
return getRouter().pluginRouteForSrc(
477+
'custom_scalars',
478+
'/download_data',
478479
getVars
479480
);
480481
}

tensorboard/plugins/custom_scalar/tf_custom_scalar_dashboard/tf-custom-scalar-multi-line-chart-card.ts

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -306,12 +306,13 @@ class _TfCustomScalarMultiLineChartCard
306306

307307
_downloadDataUrl(nameToSeries, dataSeriesName) {
308308
const dataSeries = nameToSeries[dataSeriesName];
309-
const getVars = {
309+
const getVars = new URLSearchParams({
310310
tag: dataSeries.getTag(),
311311
run: dataSeries.getRun(),
312-
};
313-
return addParams(
314-
getRouter().pluginRoute('custom_scalars', '/download_data'),
312+
});
313+
return getRouter().pluginRouteForSrc(
314+
'custom_scalars',
315+
'/download_data',
315316
getVars
316317
);
317318
}

tensorboard/plugins/graph/tf_graph_dashboard/tf-graph-dashboard.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -394,7 +394,7 @@ class TfGraphDashboard extends LegacyElementMixin(PolymerElement) {
394394
);
395395
}
396396
_graphUrl(run, limitAttrSize, largeAttrsKey) {
397-
return getRouter().pluginRoute(
397+
return getRouter().pluginRouteForSrc(
398398
'graphs',
399399
'/graph',
400400
new URLSearchParams({

tensorboard/plugins/graph/tf_graph_loader/tf-graph-dashboard-loader.ts

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -122,7 +122,11 @@ class TfGraphDashboardLoader extends LegacyElementMixin(PolymerElement) {
122122
)
123123
);
124124
if (tag) params.set('tag', tag);
125-
const graphPath = getRouter().pluginRoute('graphs', '/graph', params);
125+
const graphPath = getRouter().pluginRouteForSrc(
126+
'graphs',
127+
'/graph',
128+
params
129+
);
126130
return this._fetchAndConstructHierarchicalGraph(graphPath).then(() => {
127131
this._graphRunTag = {run, tag};
128132
});
@@ -151,7 +155,7 @@ class TfGraphDashboardLoader extends LegacyElementMixin(PolymerElement) {
151155
const params = new URLSearchParams();
152156
params.set('tag', tag!);
153157
params.set('run', run);
154-
const metadataPath = getRouter().pluginRoute(
158+
const metadataPath = getRouter().pluginRouteForSrc(
155159
'graphs',
156160
'/run_metadata',
157161
params

tensorboard/plugins/hparams/tf_hparams_backend/tf-hparams-backend.ts

Lines changed: 17 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -16,38 +16,36 @@ import {
1616
HttpMethodType,
1717
RequestOptions,
1818
} from '../../../components/tf_backend/requestManager';
19+
import {getRouter} from '../../../components/tf_backend/router';
1920

2021
/* A 'tf-hparams-backend' encapsulates sending HParams API requests to the
2122
backend.
2223
Any implementation with the same public interface can be passed to
2324
tf-hparams-main as the 'backend' property.
2425
*/
2526
export class Backend {
26-
private _apiUrl: any;
2727
private _requestManager: any;
2828
private _useHttpGet: any;
2929

3030
// Constructs a backend that uses the given tf_backend.requestManager to
31-
// send requests. The apiUrl parameter should denote the base
32-
// url to use. If useHttpGet is true uses HTTP GET to send a request
31+
// send requests. If useHttpGet is true uses HTTP GET to send a request
3332
// otherwise uses HTTP POST. See tensorboard/plugins/hparams/http_api.md
3433
// for details on how the requests and responses are encoded in each
3534
// scheme (GET or POST).
36-
constructor(apiUrl, requestManager, useHttpGet = true) {
37-
this._apiUrl = apiUrl;
35+
constructor(requestManager, useHttpGet = true) {
3836
this._requestManager = requestManager;
3937
this._useHttpGet = useHttpGet;
4038
}
4139
// In the API methods below, 'request' should be a JSON translated request
4240
// protocol buffer and the response is a JSON translated response protocol
4341
// buffer. See api.proto for the details.
4442
getExperiment(experimentRequest) {
45-
return this._sendRequest('experiment', experimentRequest);
43+
return this._sendRequest('/experiment', experimentRequest);
4644
}
4745
getDownloadUrl(format, listSessionGroupsRequest, columnsVisibility) {
48-
return (
49-
this._apiUrl +
50-
'/download_data?' +
46+
return getRouter().pluginRouteForSrc(
47+
'hparams',
48+
'/download_data',
5149
new URLSearchParams({
5250
format: format,
5351
columnsVisibility: JSON.stringify(columnsVisibility),
@@ -56,17 +54,21 @@ export class Backend {
5654
);
5755
}
5856
listSessionGroups(listSessionGroupsRequest) {
59-
return this._sendRequest('session_groups', listSessionGroupsRequest);
57+
return this._sendRequest('/session_groups', listSessionGroupsRequest);
6058
}
6159
listMetricEvals(listMetricEvalsRequest) {
62-
return this._sendRequest('metric_evals', listMetricEvalsRequest);
60+
return this._sendRequest('/metric_evals', listMetricEvalsRequest);
6361
}
6462
// ---- Private methods below -------------------------------------------
6563
_sendRequest(methodName, request_proto) {
6664
if (this._useHttpGet) {
67-
const encodedRequest = encodeURIComponent(JSON.stringify(request_proto));
68-
const url =
69-
this._apiUrl + '/' + methodName + '?request=' + encodedRequest;
65+
const url = getRouter().pluginRoute(
66+
'hparams',
67+
methodName,
68+
new URLSearchParams({
69+
request: JSON.stringify(request_proto),
70+
})
71+
);
7072
return this._requestManager.request(url);
7173
}
7274
/* Use POST */
@@ -75,7 +77,7 @@ export class Backend {
7577
requestOptions.methodType = HttpMethodType.POST;
7678
requestOptions.contentType = 'text/plain';
7779
requestOptions.body = JSON.stringify(request_proto);
78-
const url = this._apiUrl + '/' + methodName;
80+
const url = getRouter().pluginRoute('hparams', methodName);
7981
return this._requestManager.requestWithOptions(url, requestOptions);
8082
}
8183
}

tensorboard/plugins/hparams/tf_hparams_dashboard/tf-hparams-dashboard.ts

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,6 @@ const inColab =
2525
new URLSearchParams(window.location.search).get('tensorboardColab') ===
2626
'true';
2727

28-
const PLUGIN_NAME = 'hparams';
2928
@customElement('tf-hparams-dashboard')
3029
class TfHparamsDashboard extends LegacyElementMixin(PolymerElement) {
3130
static readonly template = html`
@@ -42,9 +41,6 @@ class TfHparamsDashboard extends LegacyElementMixin(PolymerElement) {
4241
type: Object,
4342
})
4443
_backend = new tf_hparams_backend.Backend(
45-
/* apiUrl= */ tf_backend
46-
.getRouter()
47-
.pluginRoute(/* pluginName= */ PLUGIN_NAME, /* route= */ ''),
4844
new tf_backend.RequestManager(),
4945
/* Use GETs if we're running in colab (due to b/126387106).
5046
Otherwise use POSTs. */

tensorboard/plugins/image/tf_image_dashboard/tf-image-loader.ts

Lines changed: 9 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,6 @@ import {LegacyElementMixin} from '../../../components/polymer/legacy_element_mix
2020
import {Canceller} from '../../../components/tf_backend/canceller';
2121
import {RequestManager} from '../../../components/tf_backend/requestManager';
2222
import {getRouter} from '../../../components/tf_backend/router';
23-
import {addParams} from '../../../components/tf_backend/urlPathHelpers';
2423
import '../../../components/tf_card_heading/tf-card-heading';
2524
import '../../../components/tf_card_heading/tf-card-heading-style';
2625
import {formatDate} from '../../../components/tf_card_heading/util';
@@ -293,12 +292,12 @@ class TfImageLoader extends LegacyElementMixin(PolymerElement) {
293292
return;
294293
}
295294
this._metadataCanceller.cancelAll();
296-
const router = getRouter();
297-
const url = addParams(router.pluginRoute('images', '/images'), {
295+
const searchParams = new URLSearchParams({
298296
tag: this.tag,
299297
run: this.run,
300298
sample: this.sample as any,
301299
});
300+
const url = getRouter().pluginRoute('images', '/images', searchParams);
302301
const updateSteps = this._metadataCanceller.cancellable((result) => {
303302
if (result.cancelled) {
304303
return;
@@ -311,12 +310,16 @@ class TfImageLoader extends LegacyElementMixin(PolymerElement) {
311310
this.requestManager.request(url).then(updateSteps);
312311
}
313312
_createStepDatum(imageMetadata) {
314-
let url = getRouter().pluginRoute('images', '/individualImage');
313+
const searchParams = new URLSearchParams(imageMetadata.query);
315314
// Include wall_time just to disambiguate the URL and force
316315
// the browser to reload the image when the URL changes. The
317316
// backend doesn't care about the value.
318-
url = addParams(url, {ts: imageMetadata.wall_time});
319-
url += '&' + imageMetadata.query;
317+
searchParams.append('ts', imageMetadata.wall_time);
318+
let url = getRouter().pluginRouteForSrc(
319+
'images',
320+
'/individualImage',
321+
searchParams
322+
);
320323
return {
321324
// The wall time within the metadata is in seconds. The Date
322325
// constructor accepts a time in milliseconds, so we multiply by 1000.

tensorboard/plugins/scalar/tf_scalar_dashboard/tf-scalar-card.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -267,7 +267,7 @@ export class TfScalarCard extends PolymerElement {
267267

268268
@property({type: Object})
269269
getDataLoadUrl: Function = ({tag, run}) => {
270-
return getRouter().pluginRoute(
270+
return getRouter().pluginRouteForSrc(
271271
'scalars',
272272
'/scalars',
273273
new URLSearchParams({tag, run})

0 commit comments

Comments
 (0)