-
Notifications
You must be signed in to change notification settings - Fork 5
Add a setting for the fields visibility #14
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,14 @@ | ||
{ | ||
"title": "Secrets manager", | ||
"description": "The secrets manager settings", | ||
"type": "object", | ||
"properties": { | ||
"ShowSecretFields": { | ||
"type": "boolean", | ||
"title": "Show secret fields", | ||
"description": "Whether to show the secret fields in the UI or not", | ||
"default": false | ||
} | ||
}, | ||
"additionalProperties": false | ||
} |
Original file line number | Diff line number | Diff line change | ||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|
|
@@ -2,9 +2,12 @@ import { | |||||||||||
JupyterFrontEnd, | ||||||||||||
JupyterFrontEndPlugin | ||||||||||||
} from '@jupyterlab/application'; | ||||||||||||
import { ISettingRegistry } from '@jupyterlab/settingregistry'; | ||||||||||||
|
||||||||||||
import { SecretsManager } from './manager'; | ||||||||||||
import { ISecretsManager } from './token'; | ||||||||||||
import { InMemoryConnector } from './connectors'; | ||||||||||||
import { PageConfig } from '@jupyterlab/coreutils'; | ||||||||||||
|
||||||||||||
/** | ||||||||||||
* A basic secret connector extension, that should be disabled to provide a new | ||||||||||||
|
@@ -23,18 +26,58 @@ const inMemoryConnector: JupyterFrontEndPlugin<void> = { | |||||||||||
/** | ||||||||||||
* The secret manager extension. | ||||||||||||
*/ | ||||||||||||
const manager: JupyterFrontEndPlugin<ISecretsManager> = { | ||||||||||||
const managerPlugin: JupyterFrontEndPlugin<ISecretsManager> = { | ||||||||||||
id: 'jupyter-secrets-manager:manager', | ||||||||||||
description: 'A JupyterLab extension to manage secrets.', | ||||||||||||
autoStart: true, | ||||||||||||
provides: ISecretsManager, | ||||||||||||
activate: (app: JupyterFrontEnd): ISecretsManager => { | ||||||||||||
console.log('JupyterLab extension jupyter-secrets-manager is activated!'); | ||||||||||||
return new SecretsManager(); | ||||||||||||
optional: [ISettingRegistry], | ||||||||||||
activate: ( | ||||||||||||
app: JupyterFrontEnd, | ||||||||||||
settingRegistry: ISettingRegistry | ||||||||||||
): ISecretsManager => { | ||||||||||||
// Check if the fields are hidden from page config. | ||||||||||||
let showSecretFieldsConfig = true; | ||||||||||||
if (PageConfig.getOption('secretsManager-showFields') === 'false') { | ||||||||||||
showSecretFieldsConfig = false; | ||||||||||||
} | ||||||||||||
|
||||||||||||
const manager = new SecretsManager({ | ||||||||||||
showSecretFields: showSecretFieldsConfig | ||||||||||||
}); | ||||||||||||
|
||||||||||||
settingRegistry | ||||||||||||
.load(managerPlugin.id) | ||||||||||||
.then(settings => { | ||||||||||||
// If the fields are hidden from the manager, remove the setting. | ||||||||||||
if (!showSecretFieldsConfig) { | ||||||||||||
delete settings.schema.properties?.['ShowSecretFields']; | ||||||||||||
return; | ||||||||||||
} | ||||||||||||
Comment on lines
+53
to
+56
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Remove the visibility setting from the schema if it locked. |
||||||||||||
|
||||||||||||
// Otherwise listen to it to update the field visibility. | ||||||||||||
const updateFieldVisibility = () => { | ||||||||||||
const showSecretField = | ||||||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Do you think this is necessary ? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. indeed! |
||||||||||||
settings.get('ShowSecretFields').composite ?? false; | ||||||||||||
manager.secretFieldsVisibility = showSecretField as boolean; | ||||||||||||
}; | ||||||||||||
|
||||||||||||
settings.changed.connect(() => updateFieldVisibility()); | ||||||||||||
updateFieldVisibility(); | ||||||||||||
}) | ||||||||||||
.catch(reason => { | ||||||||||||
console.error( | ||||||||||||
`Failed to load settings for ${managerPlugin.id}`, | ||||||||||||
reason | ||||||||||||
); | ||||||||||||
}); | ||||||||||||
|
||||||||||||
console.debug('JupyterLab extension jupyter-secrets-manager is activated!'); | ||||||||||||
return manager; | ||||||||||||
} | ||||||||||||
}; | ||||||||||||
|
||||||||||||
export * from './connectors'; | ||||||||||||
export * from './manager'; | ||||||||||||
export * from './token'; | ||||||||||||
export default [inMemoryConnector, manager]; | ||||||||||||
export default [inMemoryConnector, managerPlugin]; |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -8,17 +8,29 @@ import { | |
ISecretsList, | ||
ISecretsManager | ||
} from './token'; | ||
import { ISignal, Signal } from '@lumino/signaling'; | ||
|
||
interface IOptions { | ||
showSecretFields?: boolean; | ||
} | ||
|
||
/** | ||
* The default secrets manager. | ||
*/ | ||
export class SecretsManager implements ISecretsManager { | ||
/** | ||
* the secrets manager constructor. | ||
* The secrets manager constructor. | ||
*/ | ||
constructor() { | ||
constructor(options: IOptions) { | ||
this._storing = new PromiseDelegate<void>(); | ||
this._storing.resolve(); | ||
Private.setSecretFieldsVisibility(options.showSecretFields ?? false); | ||
|
||
// If the secret fields are hidden from constructor, this setting comes from | ||
// PageConfig, we need to lock the fields visibility. | ||
if (options.showSecretFields === false) { | ||
Private.lockFieldsVisibility(); | ||
} | ||
Comment on lines
+29
to
+33
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Lock the visibility setting if it is explicitly false at startup (coming from page config) |
||
} | ||
|
||
/** | ||
|
@@ -33,14 +45,44 @@ export class SecretsManager implements ISecretsManager { | |
this._ready.resolve(); | ||
} | ||
|
||
/** | ||
* A promise that resolves when the connector is set. | ||
*/ | ||
get ready(): Promise<void> { | ||
return this._ready.promise; | ||
} | ||
|
||
/** | ||
* A promise that locks the connector access during storage. | ||
*/ | ||
protected get storing(): Promise<void> { | ||
return this._storing.promise; | ||
} | ||
|
||
/** | ||
* A signal emitting when the field visibility setting has changed. | ||
*/ | ||
get fieldVisibilityChanged(): ISignal<this, boolean> { | ||
return this._fieldsVisibilityChanged; | ||
} | ||
|
||
/** | ||
* Get the visibility of the secret fields. | ||
*/ | ||
get secretFieldsVisibility(): boolean { | ||
return Private.getSecretFieldsVisibility(); | ||
} | ||
|
||
/** | ||
* Set the visibility of the secret fields. | ||
* The visibility cannot be set if it is locked (from page config). | ||
*/ | ||
set secretFieldsVisibility(value: boolean) { | ||
if (Private.setSecretFieldsVisibility(value)) { | ||
this._fieldsVisibilityChanged.emit(Private.getSecretFieldsVisibility()); | ||
} | ||
} | ||
|
||
/** | ||
* Get a secret given its namespace and ID. | ||
*/ | ||
|
@@ -179,6 +221,7 @@ export class SecretsManager implements ISecretsManager { | |
|
||
private _ready = new PromiseDelegate<void>(); | ||
private _storing: PromiseDelegate<void>; | ||
private _fieldsVisibilityChanged = new Signal<this, boolean>(this); | ||
} | ||
|
||
/** | ||
|
@@ -293,7 +336,7 @@ namespace Private { | |
} | ||
|
||
/** | ||
* Actually fetch the secret from the connector. | ||
* Fetch the secret from the connector. | ||
*/ | ||
export async function get(id: string): Promise<ISecret | undefined> { | ||
if (!connector?.fetch) { | ||
|
@@ -303,7 +346,7 @@ namespace Private { | |
} | ||
|
||
/** | ||
* Actually list the secret from the connector. | ||
* List the secret from the connector. | ||
*/ | ||
export async function list( | ||
namespace: string | ||
|
@@ -314,7 +357,7 @@ namespace Private { | |
return connector.list(namespace); | ||
} | ||
/** | ||
* Actually save the secret using the connector. | ||
* Save the secret using the connector. | ||
*/ | ||
export async function set(id: string, secret: ISecret): Promise<any> { | ||
if (!connector?.save) { | ||
|
@@ -324,7 +367,7 @@ namespace Private { | |
} | ||
|
||
/** | ||
* Actually remove the secrets using the connector. | ||
* Remove the secrets using the connector. | ||
*/ | ||
export async function remove(id: string): Promise<void> { | ||
if (!connector?.remove) { | ||
|
@@ -333,6 +376,32 @@ namespace Private { | |
return connector.remove(id); | ||
} | ||
|
||
/** | ||
* Lock the fields visibility value. | ||
*/ | ||
let fieldsVisibilityLocked = false; | ||
export function lockFieldsVisibility() { | ||
fieldsVisibilityLocked = true; | ||
} | ||
|
||
/** | ||
* Get/set the fields visibility. | ||
*/ | ||
let secretFieldsVisibility = false; | ||
export function getSecretFieldsVisibility(): boolean { | ||
return secretFieldsVisibility; | ||
} | ||
export function setSecretFieldsVisibility(value: boolean): boolean { | ||
if (!fieldsVisibilityLocked && value !== secretFieldsVisibility) { | ||
secretFieldsVisibility = value; | ||
return true; | ||
} | ||
return false; | ||
} | ||
Comment on lines
+394
to
+400
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Do not update the visibility if locked. |
||
|
||
/** | ||
* The secret path type. | ||
*/ | ||
export type SecretPath = { | ||
namespace: string; | ||
id: string; | ||
|
Uh oh!
There was an error while loading. Please reload this page.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Read the page config and setup the fields visibility at instantiation if required, to lock the setting.