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
6 changes: 3 additions & 3 deletions .circleci/config.yml
Original file line number Diff line number Diff line change
Expand Up @@ -102,7 +102,7 @@ workflows:
arch: amd64
matrix:
parameters:
tag: ['1.10.0b0', '1.9.0b0', '1.8.0b0', '1.7.0b0']
tag: ['1.11.0b1', '1.10.0b0', '1.9.0b0', '1.8.0b0']
# Publish for linux/arm64
- devcontainer-publish-arm64:
filters:
Expand All @@ -112,7 +112,7 @@ workflows:
arch: arm64
matrix:
parameters:
tag: ['1.10.0b0', '1.9.0b0', '1.8.0b0', '1.7.0b0']
tag: ['1.11.0b1', '1.10.0b0', '1.9.0b0', '1.8.0b0']
# Manifest they two and push to registry
- devcontainer-manifest:
requires:
Expand All @@ -124,4 +124,4 @@ workflows:
- main
matrix:
parameters:
tag: ['1.10.0b0', '1.9.0b0', '1.8.0b0', '1.7.0b0']
tag: ['1.11.0b1', '1.10.0b0', '1.9.0b0', '1.8.0b0']
1 change: 1 addition & 0 deletions .eslintrc.cjs
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ module.exports = {
rules: {
// let's bypass them
'promise/always-return': 'off',
'@typescript-eslint/ban-ts-comment': 'warn',

// common pitfalls
eqeqeq: 'error',
Expand Down
2 changes: 1 addition & 1 deletion packages/secretnote-scql/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@alipay/secretnote-scql",
"version": "0.0.50",
"version": "0.0.51",
"license": "Apache-2.0",
"author": "[email protected]",
"repository": "https://github.com/secretflow/secretnote/tree/main/packages/secretnote",
Expand Down
2 changes: 1 addition & 1 deletion packages/secretnote-scql/src/utils/error.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ export function genericErrorHandler(
reThrow?: boolean;
} = {},
) {
// eslint-disable-next-line no-console
console.error(e);
const { passthrough } = options;
let { silent, reThrow } = options;
Expand All @@ -23,7 +24,6 @@ export function genericErrorHandler(
if (!silent) {
message.error(e?.message || e.toString());
}
// eslint-disable-next-line no-console
if (reThrow) {
throw e;
}
Expand Down
6 changes: 3 additions & 3 deletions packages/secretnote-sf/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@alipay/secretnote-sf",
"version": "0.0.50",
"version": "0.0.51",
"license": "Apache-2.0",
"author": "[email protected]",
"repository": "https://github.com/secretflow/secretnote/tree/main/packages/secretnote",
Expand All @@ -14,8 +14,8 @@
"types": "dist/index.d.ts",
"scripts": {
"prepare": "pnpm run build:component",
"build:component": "tsup src/index.tsx --inject react-shim.js",
"dev": "tsup src/index.tsx --watch --inject react-shim.js",
"build:component": "tsup src/index.ts --inject react-shim.js",
"dev": "tsup src/index.ts --watch --inject react-shim.js",
"lint:eslint": "eslint . --ext ts,tsx",
"typecheck:tsc": "tsc -p tsconfig.json --noEmit",
"pb": "pnpm publish --no-git-checks --filter @secretflow/secretnote-sf"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,6 @@ export function Editor({
onUpdate(e.editor);
debouncedUpdates(e);
},
autofocus: 'end',
});

// Hydrate the editor with the content from localStorage.
Expand Down
6 changes: 5 additions & 1 deletion packages/secretnote-sf/src/components/ribbon/index.less
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,12 @@
}

.secretnote-ribbon-popover {
.title {
.mb-2 {
margin-bottom: 8px;
}

.title {
margin-bottom: 6px;
color: var(--mana-secretnote-text-color);
}

Expand Down
35 changes: 20 additions & 15 deletions packages/secretnote-sf/src/components/ribbon/index.tsx
Original file line number Diff line number Diff line change
@@ -1,12 +1,14 @@
// This is the ribbon on the top-right corner of each code cell used for selecting parties.

import { l10n } from '@difizen/mana-l10n';
import { Badge, Popover, Space, Tag } from 'antd';
import React from 'react';
import './index.less';

interface RibbonProps {
children: React.ReactNode;
items: { label: string; key: string }[];
value: string[];
items: { label: string; key: string }[]; // selectable parties that are already added nodes
value: string[]; // selected parties that is saved in the metadata of the cell execution
onChange?: (value: string[]) => void;
readonly?: boolean;
}
Expand Down Expand Up @@ -44,20 +46,23 @@ function Ribbon(props: RibbonProps) {
overlayClassName="secretnote-ribbon-popover"
content={
<>
<div className="title">{l10n.t('请选择要执行该代码的节点列表')}:</div>
<div className="title">{l10n.t('请选择要执行该代码的节点列表')}</div>
<Space size={[0, 8]} wrap>
{items.map((item) => (
<CheckableTag
style={{
userSelect: 'none',
}}
key={item.key}
checked={value.includes(item.key)}
onChange={(checked) => handleChange(item.key, checked)}
>
{item.label}
</CheckableTag>
))}
{items.length
? items.map((item) => (
<CheckableTag
style={{
userSelect: 'none',
border: '1px solid #d9d9d9',
}}
key={item.key}
checked={value.includes(item.key)}
onChange={(checked) => handleChange(item.key, checked)}
>
{item.label}
</CheckableTag>
))
: l10n.t('还未拉起任何节点')}
</Space>
</>
}
Expand Down
31 changes: 16 additions & 15 deletions packages/secretnote-sf/src/modules/editor/cell/view.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -37,20 +37,20 @@ import { compareDateString, isReadonly } from '@/utils';

const SecretNoteCodeCellComponent = forwardRef<HTMLDivElement>((props, ref) => {
const instance = useInject<SecretNoteCodeCellView>(ViewInstance);
const { partyList, parties } = instance;
const { allParties, cellParties } = instance;
const { readonly } = instance;

return (
<div className={instance.className} ref={ref} tabIndex={10} onBlur={instance.blur}>
<Ribbon
readonly={readonly}
// under readonly mode, we don't have corresponding servers in partyList
// under readonly mode, we don't have corresponding servers in allParties
// just show parties recorded in the cell metadata
items={(readonly ? parties : partyList).map((name) => ({
items={(readonly ? cellParties : allParties).map((name) => ({
label: name,
key: name,
}))}
value={parties}
value={cellParties}
onChange={(val) => {
!readonly && instance.onPartiesChange(val);
}}
Expand All @@ -72,10 +72,10 @@ export class SecretNoteCodeCellView extends JupyterCodeCellView {

view = SecretNoteCodeCellComponent;

@prop() parties: string[] = [];
@prop() cellParties: string[] = [];
@prop() readonly = false;

get partyList() {
get allParties() {
return this.serverManager.servers
.filter((s) => s.status === ServerStatus.Succeeded)
.map((server) => server.name);
Expand All @@ -94,7 +94,7 @@ export class SecretNoteCodeCellView extends JupyterCodeCellView {
this.serverManager = serverManager;
this.kernelManager = kernelManager;
this.readonly = isReadonly(configService);
this.parties = this.getInitialParties();
this.cellParties = this.getInitialParties();
}

/**
Expand All @@ -114,7 +114,7 @@ export class SecretNoteCodeCellView extends JupyterCodeCellView {
return (
server &&
server.status === ServerStatus.Succeeded &&
this.parties.includes(server.name)
this.cellParties.includes(server.name)
);
});
}
Expand Down Expand Up @@ -258,7 +258,7 @@ export class SecretNoteCodeCellView extends JupyterCodeCellView {
* Handle the change of parties user selected on the right-top corner of the cell.
*/
onPartiesChange(parties: string[]) {
this.parties = parties;
this.cellParties = parties;
this.savePartiesToMeta(parties);
lastParties = parties;
}
Expand All @@ -275,23 +275,24 @@ export class SecretNoteCodeCellView extends JupyterCodeCellView {
if (execution && execution.parties) {
try {
const parties: string[] = JSON.parse(execution.parties as string);
return this.readonly
? parties
: // filter out parties that are not in the server list
parties.filter((p) => this.partyList.includes(p));
if (this.readonly) {
return parties;
}
// filter out parties that are not in the server list
return parties.filter((p) => this.allParties.includes(p));
} catch (e) {
return [];
}
} else if (lastParties.length > 0) {
return lastParties; // load parties from previous cell settings
}
return this.partyList;
return this.allParties;
}

/**
* Save the parties user selected to the cell model metadata.
*/
savePartiesToMeta(parties = this.parties) {
savePartiesToMeta(parties = this.cellParties) {
const execution = this.model.metadata.execution as ExecutionMeta;
if (execution) {
execution.parties = JSON.stringify(parties);
Expand Down
Original file line number Diff line number Diff line change
@@ -1,42 +1,76 @@
import type { NotebookModel, NotebookOption } from '@difizen/libro-jupyter';
import { ContentContribution } from '@difizen/libro-jupyter';
import type { ICell, NotebookModel, NotebookOption } from '@difizen/libro-jupyter';
import { ContentContribution, isCode } from '@difizen/libro-jupyter';
import { URI, inject, singleton } from '@difizen/mana-app';
import { l10n } from '@difizen/mana-l10n';
import { message } from 'antd';
import { uniq } from 'lodash-es';

import { SecretNoteConfigService } from '@/modules/config';
import type { SecretNoteModel } from '@/modules/editor';
import { NotebookFileService } from '@/modules/notebook';
import { genericErrorHandler, isReadonly, jsonParseSafe } from '@/utils';

@singleton({ contrib: ContentContribution })
export class SecretNoteContentContribution implements ContentContribution {
protected readonly notebookFileService: NotebookFileService;
protected readonly configService: SecretNoteConfigService;

constructor(@inject(NotebookFileService) notebookFileService: NotebookFileService) {
constructor(
@inject(NotebookFileService) notebookFileService: NotebookFileService,
@inject(SecretNoteConfigService) configService: SecretNoteConfigService,
) {
this.notebookFileService = notebookFileService;
this.configService = configService;
}

canHandle = () => {
return 3;
};

async loadContent(options: NotebookOption, model: NotebookModel) {
const secretNoteModel = model as SecretNoteModel;
async loadContent(options: NotebookOption, _model: NotebookModel) {
const model = _model as SecretNoteModel;
const fileUri = new URI(options.resource);
const filePath = fileUri.path.toString();
const currentFileContents = await this.notebookFileService.getFile(filePath);

if (currentFileContents) {
currentFileContents.content.nbformat_minor = 5;
secretNoteModel.currentFileContents = currentFileContents;
model.currentFileContents = currentFileContents;
// use file path as id, will be passed to editor and lsp
// @see https://github.com/difizen/libro/commit/b91cd7588ba4adcb3ca83f241fe42471b30cdc26#diff-32d01fca78d40feed75dcc29437fae22f74ebe33ec16ee11fde7c6c220bedbdbR23
secretNoteModel.id = secretNoteModel.filePath = currentFileContents.path;
model.id = model.filePath = currentFileContents.path;

/* eslint-disable-next-line @typescript-eslint/ban-ts-comment */
// @ts-ignore
if (!secretNoteModel.quickEditMode && !secretNoteModel.readOnly) {
secretNoteModel.startKernelConnection();
if (!model.quickEditMode && !model.readOnly) {
model.startKernelConnection();
}

return secretNoteModel.currentFileContents.content;
const { content } = model.currentFileContents;
// collect all parties in execution metadata and hint the user if possible
try {
if (!isReadonly(this.configService)) {
const requiredParties = uniq(
content?.cells
.map((v: ICell) =>
// @ts-ignore
isCode(v) ? jsonParseSafe(v?.metadata?.execution?.parties, []) : [],
)
.flat() as string[],
);
requiredParties.length &&
message.info(
l10n.t(
`当前 Notebook 需要参与方 {0} 执行,添加完成后请刷新页面`,
requiredParties.join(', '),
),
5,
);
}
} catch (e) {
genericErrorHandler(e, { silent: true });
}

return content;
}
}
}
9 changes: 9 additions & 0 deletions packages/secretnote-sf/src/pages/sf-preview/index.less
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
.secretnote-sf-preview-container {
.mana-view-container {
> .libro-view {
> .libro-view-top {
display: none;
}
}
}
}
9 changes: 5 additions & 4 deletions packages/secretnote-sf/src/pages/sf-preview/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -12,20 +12,21 @@ import {
} from '@/modules/preview';
import { ThemeModule } from '@/modules/theme';
import { ToolbarModule } from '@/modules/toolbar';
import { useRunOnce } from '@/utils/hook';

import '@/lang';
import { useRunOnce } from '@/utils/hook';
import '../../override.less';
import './index.less';

export interface ISecretNotePreviewProps {
fileURL?: string; // file URL of the notebook to preview
readonly?: boolean; // whether the app is running in readonly mode
}

const App = (props: ISecretNotePreviewProps): JSX.Element => {
useRunOnce(() =>
localStorage.setItem(SecretNoteConfigLocalStorageKey, JSON.stringify(props)),
);
useRunOnce(() => {
localStorage.setItem(SecretNoteConfigLocalStorageKey, JSON.stringify(props));
});

return (
<ManaComponents.Application
Expand Down
2 changes: 1 addition & 1 deletion packages/secretnote-sf/src/pages/sf-workspace/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -15,10 +15,10 @@ import { ThemeModule } from '@/modules/theme';
import { ToolbarModule } from '@/modules/toolbar';
import { SnippetModule } from '@/modules/toolbar/snippet';
import { WelcomeModule } from '@/modules/welcome';
import { useRunOnce } from '@/utils/hook';
// import { ComponentCellModule } from '@/modules/component-cell'

import '@/lang';
import { useRunOnce } from '@/utils/hook';
import '../../override.less';

export interface ISecretNoteWorkspaceProps {
Expand Down
11 changes: 11 additions & 0 deletions packages/secretnote-sf/src/utils/array-object.ts
Original file line number Diff line number Diff line change
Expand Up @@ -40,3 +40,14 @@ export function pickExcept<T extends object, K extends keyof T>(obj: T, keys: K[
Object.keys(obj).filter((k) => !keys.includes(k as K)),
) as Omit<T, K>;
}

/**
* JSON parse with fallback.
*/
export function jsonParseSafe(json: string, fallback: any = {}) {
try {
return JSON.parse(json);
} catch (e) {
return fallback;
}
}
Loading