Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 10 additions & 0 deletions dataproc_jupyter_plugin/handlers.py
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,16 @@ class DataprocPluginConfig(SingletonConfigurable):
config=True,
help="Enable integration with BigQuery in JupyterLab",
)
enable_cloud_storage_integration = Bool(
False,
config=True,
help="Enable integration with gcs in JupyterLab",
)
enable_metastore_integration = Bool(
False,
config=True,
help="Enable integration with metastore in JupyterLab",
)


class SettingsHandler(APIHandler):
Expand Down
6 changes: 0 additions & 6 deletions schema/plugin.json
Original file line number Diff line number Diff line change
Expand Up @@ -21,12 +21,6 @@
},
"type": "object",
"properties": {
"previewEnabled": {
"type": "boolean",
"title": "Enable Preview Features",
"description": "Whether or not preview features such as the DPMS explorer and GCS browser are enabled.",
"default": true
},
"bqRegion": {
"type": "string",
"title": "Set the BQ Region",
Expand Down
162 changes: 99 additions & 63 deletions src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@ import { ISettingRegistry } from '@jupyterlab/settingregistry';
import { IDocumentManager } from '@jupyterlab/docmanager';
import { GCSDrive } from './gcs/gcsDrive';
import { GcsBrowserWidget } from './gcs/gcsBrowserWidget';
import { DataprocLoggingService } from './utils/loggingService';
import { DataprocLoggingService, LOG_LEVEL } from './utils/loggingService';
import { NotebookScheduler } from './scheduler/notebookScheduler';
import pythonLogo from '../third_party/icons/python_logo.svg';
import NotebookTemplateService from './notebookTemplates/notebookTemplatesService';
Expand Down Expand Up @@ -151,28 +151,27 @@ const extension: JupyterFrontEndPlugin<void> = {
localStorage.removeItem('notebookValue');
});
interface SettingsResponse {
enable_metastore_integration?: boolean;
enable_cloud_storage_integration?: boolean;
enable_bigquery_integration?: boolean;
}
let bqFeature: SettingsResponse = await requestAPI('settings');
// START -- Enable Preview Features.
const settings = await settingRegistry.load(PLUGIN_ID);

// The current value of whether or not preview features are enabled.
let previewEnabled = settings.get('previewEnabled').composite as boolean;
let panelDpms: Panel | undefined,
panelGcs: Panel | undefined,
panelDatasetExplorer: Panel | undefined;
let gcsDrive: GCSDrive | undefined;
settings.changed.connect(() => {
onPreviewEnabledChanged();
});

// Capture the signal
eventEmitter.on('dataprocConfigChange', (message: string) => {
checkAllApisEnabled();
if (bqFeature.enable_bigquery_integration) {
loadBigQueryWidget('');
}
onSidePanelEnabled();
});

const checkAllApisEnabled = async () => {
Expand Down Expand Up @@ -262,84 +261,121 @@ const extension: JupyterFrontEndPlugin<void> = {
* Handler for when the Jupyter Lab theme changes.
*/
const onThemeChanged = () => {
if (!panelDpms || !panelGcs) return;
if (!panelDpms && !panelGcs && !panelDatasetExplorer) return;
const isLightTheme = themeManager.theme
? themeManager.isLight(themeManager.theme)
: true;
if (isLightTheme) {
panelDpms.title.icon = iconDpms;
if (bqFeature.enable_metastore_integration && panelDpms) {
panelDpms.title.icon = iconDpms;
}
if (bqFeature.enable_bigquery_integration && panelDatasetExplorer) {
panelDatasetExplorer.title.icon = iconDatasetExplorer;
}
panelGcs.title.icon = iconStorage;
if (bqFeature.enable_cloud_storage_integration && panelGcs) {
panelGcs.title.icon = iconStorage;
}
} else {
panelDpms.title.icon = iconDpmsDark;
if (bqFeature.enable_metastore_integration && panelDpms) {
panelDpms.title.icon = iconDpmsDark;
}
if (bqFeature.enable_bigquery_integration && panelDatasetExplorer) {
panelDatasetExplorer.title.icon = iconDatasetExplorerDark;
}
panelGcs.title.icon = iconStorageDark;
if (bqFeature.enable_cloud_storage_integration && panelGcs) {
panelGcs.title.icon = iconStorageDark;
}
}
};
themeManager.themeChanged.connect(onThemeChanged);

/**
* Helper method for when the preview flag gets updated. This reads the
* previewEnabled flag and hides or shows the GCS browser or DPMS explorer
* as necessary.
* Enables and disables the side panel sections DPMS, GCS and Datasset Explorer based on the flags.
*/
const onPreviewEnabledChanged = () => {
previewEnabled = settings.get('previewEnabled').composite as boolean;
if (!previewEnabled) {
// Preview was disabled, tear everything down.
panelDpms?.dispose();
panelDatasetExplorer?.dispose();
panelGcs?.dispose();
gcsDrive?.dispose();
panelDpms = undefined;
panelDatasetExplorer = undefined;
panelGcs = undefined;
gcsDrive = undefined;
} else {
// Preview was enabled, (re)create DPMS and GCS.
if (!panelDpms && !panelGcs) {
panelDpms = new Panel();
panelDpms.id = 'dpms-tab';
panelDpms.title.caption = 'Dataset Explorer - DPMS';
panelDpms.addWidget(new dpmsWidget(app as JupyterLab, themeManager));
if (bqFeature.enable_bigquery_integration && !panelDatasetExplorer) {
panelDatasetExplorer = new Panel();
panelDatasetExplorer.id = 'dataset-explorer-tab';
panelDatasetExplorer.title.caption = 'Dataset Explorer - BigQuery';
panelDatasetExplorer.addWidget(
new BigQueryWidget(
app as JupyterLab,
settingRegistry as ISettingRegistry,
bqFeature.enable_bigquery_integration as boolean,
themeManager
)
);
}
panelGcs = new Panel();
panelGcs.id = 'GCS-bucket-tab';
panelGcs.title.caption = 'Google Cloud Storage';
gcsDrive = new GCSDrive();
documentManager.services.contents.addDrive(gcsDrive);
panelGcs.addWidget(
new GcsBrowserWidget(gcsDrive, factory as IFileBrowserFactory)
);
// Update the icons.
onThemeChanged();
app.shell.add(panelGcs, 'left', { rank: 1002 });
if (bqFeature.enable_bigquery_integration && panelDatasetExplorer) {
app.shell.add(panelDatasetExplorer, 'left', { rank: 1000 });
}
app.shell.add(panelDpms, 'left', { rank: 1001 });
const onSidePanelEnabled = async () => {
const toBoolean = (value: any): boolean => {
if (typeof value === 'boolean') return value;
if (typeof value === 'string') {
const lowercased = value.toLowerCase().trim();
return lowercased === 'true' || lowercased === '1';
}
return false;
};

// Convert configuration values to boolean
const enableBigQuery = toBoolean(bqFeature.enable_bigquery_integration);
const enableCloudStorage = toBoolean(
bqFeature.enable_cloud_storage_integration
);
const enableMetastore = toBoolean(bqFeature.enable_metastore_integration);

// Clear any existing panels first
panelDatasetExplorer?.dispose();
panelDatasetExplorer = undefined;

panelGcs?.dispose();
gcsDrive?.dispose();
panelGcs = undefined;
gcsDrive = undefined;

panelDpms?.dispose();
panelDpms = undefined;

// Reinitialize panels based on individual flags
if (enableBigQuery) {
panelDatasetExplorer = new Panel();
panelDatasetExplorer.id = 'dataset-explorer-tab';
panelDatasetExplorer.title.caption = 'Dataset Explorer - BigQuery';
panelDatasetExplorer.title.className = 'panel-icons-custom-style';
panelDatasetExplorer.addWidget(
new BigQueryWidget(
app as JupyterLab,
settingRegistry as ISettingRegistry,
bqFeature.enable_bigquery_integration as boolean,
themeManager
)
);
onThemeChanged();
app.shell.add(panelDatasetExplorer, 'left', { rank: 1000 });
DataprocLoggingService.log(
'Bigquery dataset explorer is enabled',
LOG_LEVEL.INFO
);
}
};

onPreviewEnabledChanged();
// END -- Enable Preview Features.
if (enableMetastore) {
panelDpms = new Panel();
panelDpms.id = 'dpms-tab';
panelDpms.title.caption = 'Dataset Explorer - DPMS';
panelDpms.title.className = 'panel-icons-custom-style';
panelDpms.addWidget(new dpmsWidget(app as JupyterLab, themeManager));
onThemeChanged();
app.shell.add(panelDpms, 'left', { rank: 1001 });
DataprocLoggingService.log(
'Metastore is enabled',
LOG_LEVEL.INFO
);
}

if (enableCloudStorage) {
panelGcs = new Panel();
panelGcs.id = 'GCS-bucket-tab';
panelGcs.title.caption = 'Google Cloud Storage';
panelGcs.title.className = 'panel-icons-custom-style';
gcsDrive = new GCSDrive();
documentManager.services.contents.addDrive(gcsDrive);
panelGcs.addWidget(
new GcsBrowserWidget(gcsDrive, factory as IFileBrowserFactory)
);
onThemeChanged();
app.shell.add(panelGcs, 'left', { rank: 1002 });
DataprocLoggingService.log(
'Cloud storage is enabled',
LOG_LEVEL.INFO
);
}
};
onSidePanelEnabled();

app.docRegistry.addWidgetExtension(
'Notebook',
Expand Down
34 changes: 24 additions & 10 deletions style/base.css
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,8 @@
}

/*Changing Icon for category with image add python bigquery*/
.favyox6 svg[data-icon='launcher:python-bigquery-logo-icon'], .f1hgkb35 svg[data-icon='launcher:python-bigquery-logo-icon'] {
.favyox6 svg[data-icon='launcher:python-bigquery-logo-icon'],
.f1hgkb35 svg[data-icon='launcher:python-bigquery-logo-icon'] {
content-visibility: hidden;
display: block;
height: 32px;
Expand All @@ -25,7 +26,8 @@
}

/*Changing Icon for category with image add runtime*/
.favyox6 svg[data-icon='launcher:add-runtime-icon'], .f1hgkb35 svg[data-icon='launcher:add-runtime-icon'] {
.favyox6 svg[data-icon='launcher:add-runtime-icon'],
.f1hgkb35 svg[data-icon='launcher:add-runtime-icon'] {
content-visibility: hidden;
display: block;
height: 32px;
Expand All @@ -35,7 +37,8 @@
}

/*Changing Icon for category with image pyspark*/
.favyox6 svg[data-icon='launcher:pyspark-logo-icon'], .f1hgkb35 svg[data-icon='launcher:pyspark-logo-icon'] {
.favyox6 svg[data-icon='launcher:pyspark-logo-icon'],
.f1hgkb35 svg[data-icon='launcher:pyspark-logo-icon'] {
content-visibility: hidden;
display: block;
height: 32px;
Expand All @@ -45,7 +48,8 @@
}

/*Changing Icon for category with image cluster*/
.favyox6 svg[data-icon='launcher:clusters-icon'], .f1hgkb35 svg[data-icon='launcher:clusters-icon'] {
.favyox6 svg[data-icon='launcher:clusters-icon'],
.f1hgkb35 svg[data-icon='launcher:clusters-icon'] {
content-visibility: hidden;
display: block;
height: 32px;
Expand All @@ -55,7 +59,8 @@
}

/*Changing Icon for category with image python*/
.favyox6 svg[data-icon='launcher:python-logo-icon'], .f1hgkb35 svg[data-icon='launcher:python-logo-icon'] {
.favyox6 svg[data-icon='launcher:python-logo-icon'],
.f1hgkb35 svg[data-icon='launcher:python-logo-icon'] {
content-visibility: hidden;
display: block;
height: 32px;
Expand All @@ -65,7 +70,8 @@
}

/*Changing Icon for category with image sparkR*/
.favyox6 svg[data-icon='launcher:sparkr-logo-icon'], .f1hgkb35 svg[data-icon='launcher:sparkr-logo-icon'] {
.favyox6 svg[data-icon='launcher:sparkr-logo-icon'],
.f1hgkb35 svg[data-icon='launcher:sparkr-logo-icon'] {
content-visibility: hidden;
display: block;
height: 32px;
Expand All @@ -75,7 +81,8 @@
}

/*Changing Icon for category with image scala*/
.favyox6 svg[data-icon='launcher:scala-logo-icon'], .f1hgkb35 svg[data-icon='launcher:scala-logo-icon'] {
.favyox6 svg[data-icon='launcher:scala-logo-icon'],
.f1hgkb35 svg[data-icon='launcher:scala-logo-icon'] {
content-visibility: hidden;
display: block;
height: 32px;
Expand Down Expand Up @@ -203,13 +210,16 @@ body[data-jp-theme-name='JupyterLab Dark'] .color-icon path {
body[data-jp-theme-name='JupyterLab Dark'] .filter-section-part {
color: var(--jp-ui-font-color0);
}
body[data-jp-theme-name='JupyterLab Dark'] .schema-table th, body[data-jp-theme-name='JupyterLab Dark'] .big-query-schema-table th {
body[data-jp-theme-name='JupyterLab Dark'] .schema-table th,
body[data-jp-theme-name='JupyterLab Dark'] .big-query-schema-table th {
background-color: var(--jp-layout-color2);
}
body[data-jp-theme-name='JupyterLab Dark'] .accordion-row-parent-header{
body[data-jp-theme-name='JupyterLab Dark'] .accordion-row-parent-header {
background: var(--jp-border-color3);
}
body[data-jp-theme-name='JupyterLab Dark'] .logo-alignment-style-accordion path{
body[data-jp-theme-name='JupyterLab Dark']
.logo-alignment-style-accordion
path {
fill: var(--jp-ui-font-color1);
}

Expand All @@ -232,3 +242,7 @@ body[data-jp-theme-name='JupyterLab Dark'] .job-cancel-button-style:hover {
.css-uqjlkp-MuiFormControl-root-MuiTextField-root .MuiInputBase-root input {
height: 21px;
}
.panel-icons-custom-style {
display: flex;
align-items: center;
}
Loading