plugins/graphiql: add storage buckets to separate storage for different endpoints
This commit is contained in:
@@ -19,9 +19,11 @@ import { Tabs, Tab, makeStyles } from '@material-ui/core';
|
||||
import { Page, pageTheme, Content, Header, HeaderLabel } from '@backstage/core';
|
||||
import 'graphiql/graphiql.css';
|
||||
import GraphiQL from 'graphiql';
|
||||
import { StorageBucket } from 'lib/storage';
|
||||
|
||||
const tabs = [
|
||||
{
|
||||
id: 'gitlab',
|
||||
title: 'GitLab',
|
||||
fetcher: async (params: any) => {
|
||||
const res = await fetch('https://gitlab.com/api/graphql', {
|
||||
@@ -33,6 +35,7 @@ const tabs = [
|
||||
},
|
||||
},
|
||||
{
|
||||
id: 'countries',
|
||||
title: 'Countries',
|
||||
fetcher: async (params: any) => {
|
||||
const res = await fetch('https://countries.trevorblades.com/', {
|
||||
@@ -59,6 +62,9 @@ export const GraphiQLPage: FC<{}> = () => {
|
||||
const classes = useStyles();
|
||||
const [tabIndex, setTabIndex] = useState(0);
|
||||
|
||||
const { id, fetcher } = tabs[tabIndex];
|
||||
const storage = StorageBucket.forLocalStorage(`plugin/graphiql/data/${id}`);
|
||||
|
||||
return (
|
||||
<Page theme={pageTheme.tool}>
|
||||
<Header title="GraphiQL">
|
||||
@@ -71,7 +77,7 @@ export const GraphiQLPage: FC<{}> = () => {
|
||||
<Tab key={index} label={title} value={index} />
|
||||
))}
|
||||
</Tabs>
|
||||
<GraphiQL key={tabIndex} fetcher={tabs[tabIndex].fetcher} />
|
||||
<GraphiQL key={tabIndex} fetcher={fetcher} storage={storage} />
|
||||
</Content>
|
||||
</Page>
|
||||
);
|
||||
|
||||
@@ -0,0 +1,30 @@
|
||||
/*
|
||||
* Copyright 2020 Spotify AB
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import { StorageBucket } from './StorageBucket';
|
||||
|
||||
describe('StorageBucket', () => {
|
||||
it('should forbid access to unknown keys', () => {
|
||||
const bucket = StorageBucket.forStorage(localStorage, 'hello');
|
||||
|
||||
expect(() => {
|
||||
bucket['dunno-this-one'] = 'nope';
|
||||
}).toThrow('Direct property access is not allowed for StorageBuckets');
|
||||
expect(() => {
|
||||
return bucket['dunno-this-one'];
|
||||
}).toThrow('Direct property access is not allowed for StorageBuckets');
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,102 @@
|
||||
/*
|
||||
* Copyright 2020 Spotify AB
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
type BucketData = { [key in string]: string };
|
||||
|
||||
export class StorageBucket implements Storage {
|
||||
private static noPropAccessProxyHandler: ProxyHandler<StorageBucket> = {
|
||||
get(target, prop) {
|
||||
if (prop in target) {
|
||||
return target[prop as any];
|
||||
}
|
||||
throw new Error(
|
||||
'Direct property access is not allowed for StorageBuckets',
|
||||
);
|
||||
},
|
||||
set() {
|
||||
throw new Error(
|
||||
'Direct property access is not allowed for StorageBuckets',
|
||||
);
|
||||
},
|
||||
};
|
||||
|
||||
static forStorage(storage: Storage, bucket: string) {
|
||||
const storageBucket = new StorageBucket(storage, bucket);
|
||||
return new Proxy(storageBucket, StorageBucket.noPropAccessProxyHandler);
|
||||
}
|
||||
|
||||
static forLocalStorage(bucket: string): StorageBucket {
|
||||
return StorageBucket.forStorage(localStorage, bucket);
|
||||
}
|
||||
|
||||
private constructor(
|
||||
private readonly storage: Storage,
|
||||
private readonly bucket: string,
|
||||
) {}
|
||||
|
||||
[name: string]: any;
|
||||
|
||||
get length(): number {
|
||||
throw new Error('Method not implemented.');
|
||||
}
|
||||
|
||||
clear(): void {
|
||||
this.write({});
|
||||
}
|
||||
|
||||
getItem(key: string): string | null {
|
||||
return this.read()?.[key] ?? null;
|
||||
}
|
||||
|
||||
key(): never {
|
||||
throw new Error('Method not implemented.');
|
||||
}
|
||||
|
||||
removeItem(key: string): void {
|
||||
const data = this.read();
|
||||
if (!data) {
|
||||
return;
|
||||
}
|
||||
|
||||
const deleted = delete data[key];
|
||||
if (deleted) {
|
||||
this.write(data);
|
||||
}
|
||||
}
|
||||
|
||||
setItem(key: string, value: string): void {
|
||||
const data = this.read() ?? {};
|
||||
data[key] = value;
|
||||
this.write(data);
|
||||
}
|
||||
|
||||
private read(): BucketData | undefined {
|
||||
const bucketValue = this.storage.getItem(this.bucket);
|
||||
if (!bucketValue) {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
try {
|
||||
return JSON.parse(bucketValue);
|
||||
} catch {
|
||||
return undefined;
|
||||
}
|
||||
}
|
||||
|
||||
private write(data: BucketData) {
|
||||
this.storage.setItem(this.bucket, JSON.stringify(data));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,17 @@
|
||||
/*
|
||||
* Copyright 2020 Spotify AB
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
export * from './StorageBucket';
|
||||
Reference in New Issue
Block a user