js-base64#decode TypeScript Examples

The following examples show how to use js-base64#decode. You can vote up the ones you like or vote down the ones you don't like, and go to the original project or source file by following the links above each example. You may check out the related API usage on the sidebar.
Example #1
Source File: service-generator.ts    From erda-ui with GNU Affero General Public License v3.0 6 votes vote down vote up
getSwaggerData = (url: string) => {
  return http
    .get(url)
    .set('content-type', 'application-json')
    .set('User-Agent', '')
    .then((response) => {
      logInfo('get swagger data successfully!');
      const content = decode(response?.body?.content);
      return content ? JSON.parse(content) : '';
    })
    .catch((err) => {
      logError('fail to get swagger data: ', err);
      return false;
    });
}
Example #2
Source File: xterm-binary.tsx    From erda-ui with GNU Affero General Public License v3.0 6 votes vote down vote up
function proxyOutput(term: ITerminal, socket: WebSocket) {
  const { __getMessage } = term;
  socket.removeEventListener('message', __getMessage);

  const timeZoneReg = /^\d[\d-]+T[\d:.]+Z/;

  term.__getMessage = (ev) => {
    let { data } = ev;
    data = data && decode(data);
    const timeRegResult = timeZoneReg.exec(data);
    if (timeRegResult) {
      data = `${moment(timeRegResult[0]).format('YYYY-MM-DD HH:mm:ss')} ${data.split(timeRegResult[0])?.[1]}`;
    }
    __getMessage({ data: `\r${data}\n` });
  };
  socket.addEventListener('message', term.__getMessage);
}
Example #3
Source File: xterm-channel.tsx    From erda-ui with GNU Affero General Public License v3.0 6 votes vote down vote up
function proxyOutput(term: ITerminal, socket: WebSocket) {
  const { __getMessage } = term;
  socket.removeEventListener('message', __getMessage);
  term.__getMessage = (ev) => {
    let { data } = ev;

    const type = data.substr(0, 1);
    data = data.substr(1);
    data && (data = decode(data));
    switch (type) {
      case Ping:
        sendData(term, Pong);
        break;
      case Pong:
        break;
      case Output:
      case Error:
      case ServiceError:
        __getMessage({ data });
        break;
      default:
        break;
    }
  };
  socket.addEventListener('message', term.__getMessage);
}
Example #4
Source File: list.tsx    From erda-ui with GNU Affero General Public License v3.0 6 votes vote down vote up
parseDetailSearch = (v: string) => {
  if (v) {
    try {
      const res = JSON.parse(decode(v));
      return res;
    } catch (error) {
      // eslint-disable-next-line no-console
      console.error(error);
      return null;
    }
  }
  return null;
}
Example #5
Source File: judge0.ts    From netless-app with MIT License 6 votes vote down vote up
public async runCode(source: string, lang: string): Promise<string> {
    if (!this.hasLanguage(lang)) {
      return "Language not supported!\n";
    }

    try {
      const response = await fetch(
        "https://judge0-ce.p.rapidapi.com/submissions?base64_encoded=true&wait=true&fields=*",
        {
          method: "POST",
          headers: {
            "content-type": "application/json",
            "x-rapidapi-host": "judge0-ce.p.rapidapi.com",
            "x-rapidapi-key": this.apiKey,
          },
          body: JSON.stringify({
            language_id: Judge0.lanMap[lang],
            source_code: encode(source),
          }),
        }
      );

      const data = await response.json();

      if (data.stderr) {
        return decode(data.stderr);
      } else if (data.stdout) {
        return decode(data.stdout);
      }
      return "Unknown error\n";
    } catch (err) {
      return `${err instanceof Error ? err.message : String(err)}\n`;
    }
  }
Example #6
Source File: register-command.tsx    From logseq-plugin-todo-master with MIT License 5 votes vote down vote up
export function registerCommand() {
  logseq.provideStyle(style);

  logseq.App.onMacroRendererSlotted(async ({ payload, slot }) => {
    const [type] = payload.arguments;
    if (!type?.startsWith(macroPrefix)) {
      return;
    }

    logseq.provideStyle({
      key: slot,
      style: `#${slot} {display: inline-flex;}`,
    });

    let maybeUUID = null;
    // Implicitly use the current block
    if (type === macroPrefix) {
      maybeUUID = payload.uuid;
    } else {
      maybeUUID = decode(type.substring(macroPrefix.length + 1));
    }
    if (maybeUUID) {
      startRendering(maybeUUID, slot);
    }
  });

  async function insertMacro(mode: "page" | "block" = "block") {
    const block = await logseq.Editor.getCurrentBlock();
    if (block && block.uuid) {
      let content = "";
      let maybeUUID = "";
      if (mode === "block") {
        // We will from now on always use implicit block IDs to get rid of "Tracking target not found" issue
        // maybeUUID = block.uuid;
      } else {
        const page = await logseq.Editor.getPage(block.page.id);
        if (page?.originalName) {
          maybeUUID = page.originalName;
        }
      }
      if (maybeUUID) {
        // Use base64 to avoid incorrectly rendering in properties
        content = `{{renderer ${macroPrefix}-${encode(maybeUUID)}}}`;
      } else {
        content = `{{renderer ${macroPrefix}}}`;
      }
      await logseq.Editor.insertAtEditingCursor(content);
    }
  }

  logseq.Editor.registerSlashCommand(
    "[TODO Master] Add Progress Bar",
    async () => {
      return insertMacro();
    }
  );
}
Example #7
Source File: export-factory.ts    From vscode-code-review with MIT License 4 votes vote down vote up
private exportHandlerMap = new Map<ExportFormat, ExportMap>([
    [
      'html',
      {
        fileExtension: 'html',
        storeOutside: true,
        writeFileHeader: (_outputFile: string) => {
          return;
        },
        handleData: (_outputFile: string, row: CsvEntry): CsvEntry => {
          row.code = this.includeCodeSelection ? this.getCodeForFile(row.filename, row.lines) : '';
          return row;
        },
        handleEnd: (outputFile: string, rows: CsvEntry[], template: Uri) => {
          // check template
          let templateData;
          try {
            templateData = fs.readFileSync(template.fsPath, 'utf8');
          } catch (error: any) {
            window.showErrorMessage(`Error when reading the template file: '${template.fsPath}'`);
            throw error;
          }
          // check if grouping should be applied
          let reviewExportData: ReviewFileExportSection[] = [];
          reviewExportData = this.groupResults(rows, this.groupBy);
          if (this.groupBy === Group.filename) {
            reviewExportData.forEach((group) => {
              group.lines.sort(sortCsvEntryForLines);
            });
          }

          // Helper that decodes the Base64 content to be displayed in the handlebar
          handlebars.registerHelper('codeBlock', (code: string) => decode(code));
          // compile template after helper is registered
          const templateCompiled = handlebars.compile(templateData);
          // inject date into the template
          const htmlOut = templateCompiled(reviewExportData);
          fs.writeFileSync(outputFile, htmlOut);
          window.showInformationMessage(`Code review file: '${outputFile}' successfully created.`);
          this.showPreview(outputFile);
        },
      },
    ],
    [
      'markdown',
      {
        fileExtension: 'md',
        storeOutside: true,
        writeFileHeader: (_outputFile: string) => {
          return;
        },
        handleData: (_outputFile: string, row: CsvEntry): CsvEntry => {
          row.code = this.includeCodeSelection ? this.getCodeForFile(row.filename, row.lines) : '';
          return row;
        },
        handleEnd: (outputFile: string, rows: CsvEntry[], template: Uri) => {
          // check template
          let templateData;
          try {
            templateData = fs.readFileSync(template.fsPath, 'utf8');
          } catch (error: any) {
            window.showErrorMessage(`Error when reading the template file: '${template.fsPath}'`);
            throw error;
          }

          // check if grouping should be applied
          let reviewExportData: ReviewFileExportSection[] = [];
          reviewExportData = this.groupResults(rows, this.groupBy);
          if (this.groupBy === Group.filename) {
            reviewExportData.forEach((group) => {
              group.lines.sort(sortCsvEntryForLines);
            });
          }

          // Helper that decodes the Base64 content to be displayed in the handlebar
          handlebars.registerHelper('codeBlock', (code: string) => decode(code));
          // compile template after helper is registered
          const templateCompiled = handlebars.compile(templateData);
          // inject data into the template
          const markdownOut = templateCompiled(reviewExportData);
          fs.writeFileSync(outputFile, markdownOut);
          window.showInformationMessage(`Code review file: '${outputFile}' successfully created.`);
          this.openFile(outputFile);
        },
      },
    ],
    [
      'gitlab',
      {
        fileExtension: 'gitlab.csv',
        storeOutside: false,
        writeFileHeader: (outputFile: string) => {
          fs.writeFileSync(outputFile, `title,description${EOL}`);
        },
        handleData: (outputFile: string, row: CsvEntry): CsvEntry => {
          row.comment = escapeEndOfLineForCsv(row.comment);

          this.includeCodeSelection ? (row.code = this.getCodeForFile(row.filename, row.lines)) : delete row.code;
          // cut the description (100 chars max) along with '...' at the end
          const descShort = row.comment.length > 100 ? `${row.comment.substring(0, 100)}...` : row.comment;
          // use the title when provided but max 255 characters (as GitLab supports this length for titles), otherwise use the shortened description
          const title = row.title ? row.title.substring(0, 255) : descShort;
          const fileRow = row.url ? `- file: [${row.filename}](${row.url})${EOL}` : `${row.filename}${EOL}`;
          const linesRow = `- lines: ${row.lines}${EOL}`;
          const shaRow = row.sha ? `- SHA: ${row.sha}${EOL}${EOL}` : '';
          const commentSection = `## Comment${EOL}${row.comment}${EOL}`;
          const additional = row.additional ? `## Additional information${EOL}${row.additional}${EOL}` : '';
          const priority = row.priority ? `## Priority${EOL}${this.priorityName(row.priority)}${EOL}${EOL}` : '';
          const category = row.category ? `## Category${EOL}${row.category}${EOL}${EOL}` : '';
          const code = row.code ? `${EOL}## Source Code${EOL}${EOL}\`\`\`${EOL}${row.code}\`\`\`${EOL}` : '';
          const description = `${priority}${category}## Affected${EOL}${fileRow}${linesRow}${shaRow}${commentSection}${EOL}${additional}${code}`;
          fs.appendFileSync(outputFile, `"[code review] ${title}","${description}"${EOL}`);
          return row;
        },
        handleEnd: (outputFile: string, _rows: CsvEntry[]) => {
          window.showInformationMessage(`GitLab importable CSV file: '${outputFile}' successfully created.`);
        },
      },
    ],
    [
      'github',
      {
        fileExtension: 'github.csv',
        storeOutside: false,
        writeFileHeader: (outputFile: string) => {
          fs.writeFileSync(outputFile, `title,description,labels,state,assignee${EOL}`);
        },
        handleData: (outputFile: string, row: CsvEntry): CsvEntry => {
          row.comment = escapeEndOfLineForCsv(row.comment);

          this.includeCodeSelection ? (row.code = this.getCodeForFile(row.filename, row.lines)) : delete row.code;
          // cut the description (100 chars max) along with '...' at the end
          const descShort = row.comment.length > 100 ? `${row.comment.substring(0, 100)}...` : row.comment;
          // use the title when provided but max 255 characters (as GitLab supports this length for titles), otherwise use the shortened description
          const title = row.title ? row.title.substring(0, 255) : descShort;

          const fileRow = row.url ? `- file: [${row.filename}](${row.url})${EOL}` : `${row.filename}${EOL}`;
          const linesRow = `- lines: ${row.lines}${EOL}`;
          const shaRow = row.sha ? `- SHA: ${row.sha}${EOL}${EOL}` : '';
          const commentSection = `## Comment${EOL}${row.comment}${EOL}`;
          const additional = row.additional ? `## Additional information${EOL}${row.additional}${EOL}` : '';
          const priority = row.priority ? `## Priority${EOL}${this.priorityName(row.priority)}${EOL}${EOL}` : '';
          const category = row.category ? `## Category${EOL}${row.category}${EOL}${EOL}` : '';
          const code = row.code ? `${EOL}## Source Code${EOL}${EOL}\`\`\`${EOL}${row.code}\`\`\`${EOL}` : '';

          const description = `${priority}${category}## Affected${EOL}${fileRow}${linesRow}${shaRow}${commentSection}${EOL}${additional}${code}`;

          fs.appendFileSync(outputFile, `"[code review] ${title}","${description}","code-review","open",""${EOL}`);
          return row;
        },
        handleEnd: (outputFile: string, _rows: CsvEntry[]) => {
          window.showInformationMessage(`GitHub importable CSV file: '${outputFile}' successfully created.`);
        },
      },
    ],
    [
      'jira',
      {
        fileExtension: 'jira.csv',
        storeOutside: false,
        writeFileHeader: (outputFile: string) => {
          fs.writeFileSync(
            outputFile,
            `Summary,Description,Priority,sha,filename,url,lines,title,category,comment,additional${EOL}`,
          );
        },
        handleData: (outputFile: string, row: CsvEntry): CsvEntry => {
          row.comment = escapeEndOfLineForCsv(row.comment);

          this.includeCodeSelection ? (row.code = this.getCodeForFile(row.filename, row.lines)) : delete row.code;
          // cut the description (100 chars max) along with '...' at the end
          const descShort = row.comment?.length > 100 ? `${row.comment.substring(0, 100)}...` : row.comment;
          // use the title when provided but max 255 characters (as GitLab supports this length for titles), otherwise use the shortened description
          const title = row.title ? row.title.substring(0, 255) : descShort;

          const fileRow = row.url ? `* file: [${row.filename}|${row.url}]${EOL}` : `${row.filename}${EOL}`;
          const linesRow = `* lines: ${row.lines}${EOL}`;
          const shaRow = row.sha ? `* SHA: ${row.sha}${EOL}${EOL}` : '';
          const categorySection = `h2. Category${EOL}${row.category}${EOL}${EOL}`;
          const commentSection = `h2. Comment${EOL}${row.comment}${EOL}`;
          const additional = row.additional ? `h2. Additional information${EOL}${row.additional}${EOL}` : '';
          const code = row.code ? `${EOL}h2. Source Code${EOL}${EOL}{code}${EOL}${row.code}{code}${EOL}` : '';

          const description = `h2. Affected${EOL}${fileRow}${linesRow}${shaRow}${categorySection}${commentSection}${EOL}${additional}${code}`;

          fs.appendFileSync(
            outputFile,
            `"[code review] ${title}","${description}","${this.priorityName(row.priority)}","${row.sha}","${
              row.filename
            }","${row.url}","${row.lines}","${row.title}","${row.category}","${row.comment}","${row.additional}"${EOL}`,
          );
          return row;
        },
        handleEnd: (outputFile: string, _rows: CsvEntry[]) => {
          window.showInformationMessage(`JIRA importable file: '${outputFile}' successfully created.`);
        },
      },
    ],
    [
      'json',
      {
        fileExtension: 'json',
        storeOutside: true,
        writeFileHeader: (_outputFile: string) => {
          return;
        },
        handleData: (_outputFile: string, row: CsvEntry): CsvEntry => {
          this.includeCodeSelection ? (row.code = this.getCodeForFile(row.filename, row.lines)) : delete row.code;
          return row;
        },
        handleEnd: (outputFile: string, rows: CsvEntry[]) => {
          fs.writeFileSync(outputFile, JSON.stringify(rows, null, 2));
          window.showInformationMessage(`GitHub importable CSV file: '${outputFile}' successfully created.`);
        },
      },
    ],
  ]);
Example #8
Source File: form.tsx    From erda-ui with GNU Affero General Public License v3.0 4 votes vote down vote up
PipelineForm = ({ onCancel, pipelineCategory, onOk, data: editData, fixedApp }: IProps) => {
  const { key: pipelineCategoryKey, rules: pipelineCategoryRules } = pipelineCategory || {};
  const [{ projectId }] = routeInfoStore.useStore((s) => [s.params]);
  const [form] = Form.useForm();
  const [appList, setAppList] = React.useState<App[]>([]);
  const [app, setApp] = React.useState<App>({} as App);
  const [tree, setTree] = React.useState<TreeNode[]>([]);
  const [treeVisible, setTreeVisible] = React.useState(false);
  const [treeValue, setTreeValue] = React.useState('');
  const [treeExpandedKeys, setTreeExpandedKeys] = React.useState<Array<string | number>>([]);
  const canTreeSelectClose = React.useRef(true);
  const [sourceErrorMessage, setSourceErrorMessage] = React.useState('');
  const appDetail = appStore.useStore((s) => s.detail);

  const type = editData ? 'edit' : 'add';

  const convertTreeData = (data: Node[]) => {
    return data.map((item) => ({
      ...item,
      key: item.inode,
      id: item.inode,
      pId: item.pinode,
      title: item.name,
      isLeaf: item.type === 'f',
      value: item.inode,
    }));
  };

  const getTree = React.useCallback(
    async (pinode: string) => {
      const res = await getFileTree.fetch({
        scopeID: projectId,
        scope: 'project-app',
        pinode,
        pipelineCategoryKey: !pipelineCategoryKey || pipelineCategoryKey === 'all' ? '' : pipelineCategoryKey,
      });

      if (res.success) {
        return convertTreeData(res.data || []);
      } else {
        return [];
      }
    },
    [projectId, pipelineCategoryKey],
  );

  const loadTree = async (node: TreeNode) => {
    const data = await getTree(node.id);
    setTree((prev) => [...prev, ...data]);
    return Promise.resolve();
  };

  const getApps = React.useCallback(async () => {
    if (!fixedApp) {
      const res = await getAppList.fetch({ projectID: projectId });
      if (res.success) {
        setAppList(
          res.data?.map((item) => ({ value: item.ID, label: item.displayName, projectName: item.projectName })) || [],
        );
      }
    }
  }, [projectId, fixedApp]);

  React.useEffect(() => {
    getApps();
  }, [getApps]);

  React.useEffect(() => {
    const initialTree = async () => {
      const data = await getTree(btoa(encodeURI(`${projectId}/${app.value || fixedApp}`)));
      setTree(data);
    };
    if (app.value || fixedApp) {
      initialTree();
      setSourceErrorMessage('');

      if (tree.length !== 0) {
        setTreeValue('');
        form.resetFields(['tree']);
      }
    }
  }, [app.value, projectId, getTree, form, fixedApp]);

  React.useEffect(() => {
    if (fixedApp) {
      form.setFieldsValue?.({ app: fixedApp });
      setApp({ value: fixedApp });
    }
  }, [form, fixedApp]);

  useEffectOnce(() => {
    if (editData) {
      const { name, app, fileName, inode } = editData;
      form.setFieldsValue({ name, app, tree: inode });
      setApp({ value: app });
      setTreeValue(fileName);
    }
  });

  const submit = () => {
    form.validateFields().then(async (value) => {
      const path = decode(value.tree).split('/');
      const fileName = path[path.length - 1];
      path.length--;
      const appId = path[1];
      const branch = path.join('/').split('tree/')[1].split('/.dice')[0].split('/.erda')[0];
      const ymlPath = (path.join('/').split(branch)[1] || '').substr(1);

      const params = {
        edit: {
          projectID: +projectId,
          name: value.name,
          id: editData?.id,
          projectPipelineSource: {
            sourceType: 'erda',
            appID: appId,
            ref: branch,
            path: ymlPath,
            fileName,
          },
        },
        add: {
          projectID: +projectId,
          name: value.name,
          sourceType: 'erda',
          appID: appId,
          ref: branch,
          path: ymlPath,
          fileName,
        },
      };

      const res = await interfaceMap[type].fetch({ ...params[type], $options: { successMsg: successMsgMap[type] } });
      if (res.success) {
        onOk();
      }
    });
  };

  const sourceCheck = async (value: string) => {
    if (value === editData?.inode) {
      return Promise.resolve();
    }
    const node = tree.find((item) => item.id === value);
    if (node?.isLeaf) {
      const path = decode(node.pId);
      const _appID = path.split('/')[1];
      const ref = path.split('tree/')[1].split('/.dice')[0].split('/.erda')[0];
      const payload = {
        appID: _appID,
        ref,
        fileName: node.name,
        sourceType: 'erda',
      };

      const res = await checkSource.fetch(payload);
      const { data } = res;
      if (data?.pass) {
        setSourceErrorMessage('');
      } else {
        data?.message && setSourceErrorMessage(data.message);
      }
    }

    return Promise.resolve();
  };

  return (
    <div className="project-pipeline-form flex flex-col h-full">
      <div className="header py-2.5 pl-4 bg-default-02 flex-h-center">
        <span className="text-base text-default">{titleMap[type]}</span>
        <ErdaIcon type="zhedie" className="ml-1" />

        <div className="flex-h-center cursor-pointer mx-2 px-2 py-1 flex-1 justify-end">
          <ErdaIcon type="guanbi" size="20" onClick={() => onCancel()} />
        </div>
      </div>

      <div className="flex-1 min-h-0 pl-4 pt-4 w-1/2">
        <Form form={form}>
          <RenderFormItem
            name={'name'}
            type={'input'}
            rules={[
              {
                required: true,
                message: i18n.t('Please enter the {name}', { name: i18n.t('Pipeline').toLowerCase() }),
              },
              { max: 30, message: i18n.t('dop:no more than 30 characters') },
              {
                pattern: /^[\u4e00-\u9fa5A-Za-z0-9._-]+$/,
                message: i18n.t('dop:Must be composed of Chinese, letters, numbers, underscores, hyphens and dots.'),
              },
            ]}
            itemProps={{
              className: 'border-transparent shadow-none pl-0 text-xl bg-transparent',
              placeholder: i18n.t('Please enter the {name}', { name: i18n.t('Pipeline').toLowerCase() }),
            }}
          />
          <div>
            <div className="text-default">{i18n.t('dop:Code source')}</div>
            <CodeResource />
          </div>
          <div>
            <div className="text-default mb-3">{i18n.t('Configuration')}</div>
            <div className="flex-h-center">
              <div className="mb-3 w-32 text-default-6 flex-h-center">
                <ErdaIcon type="yingyongmingcheng" size={20} className="text-default-4 mr-1" />
                {i18n.t('App')}
              </div>
              <div className="flex-1 pr-6 mb-3">
                {fixedApp ? (
                  appDetail?.displayName || appDetail?.name
                ) : (
                  <RenderFormItem
                    name="app"
                    type="select"
                    options={appList}
                    rules={[{ required: true, message: i18n.t('please choose the {name}', { name: i18n.t('App') }) }]}
                    itemProps={{
                      disabled: type === 'edit',
                      className: 'project-release-select',
                      onChange: (_: string, _app: App) => setApp(_app),
                    }}
                  />
                )}
              </div>
            </div>
            <div className="flex">
              <div className="w-32 text-default-6">
                <div className="flex-h-center mt-1.5">
                  <ErdaIcon type="pipeline" size={20} className="text-default-4 mr-1" />
                  {i18n.t('dop:Pipeline file')}
                </div>
              </div>
              <div className="flex-1">
                <RenderFormItem
                  name="tree"
                  type="custom"
                  rules={[
                    {
                      validator: (_: string, value: string) => {
                        if (!value) {
                          return Promise.reject(
                            new Error(i18n.t('please choose the {name}', { name: i18n.t('Pipelines').toLowerCase() })),
                          );
                        }

                        return sourceCheck(value);
                      },
                    },
                  ]}
                  getComp={() => (
                    <div className="flex">
                      <TreeSelect
                        className="project-release-select"
                        treeDataSimpleMode
                        treeData={tree}
                        open={treeVisible}
                        onDropdownVisibleChange={(_visible) => {
                          if (canTreeSelectClose.current) {
                            setTreeVisible(_visible);
                          } else {
                            canTreeSelectClose.current = true;
                          }
                        }}
                        value={treeValue}
                        onSelect={(value, node) => {
                          if (node.isLeaf === false) {
                            canTreeSelectClose.current = false;
                            if (treeExpandedKeys.includes(value)) {
                              setTreeExpandedKeys((pre) => pre.filter((item) => item !== value));
                            } else {
                              setTreeExpandedKeys((pre) => [...pre, value]);
                            }
                          } else {
                            setTreeValue(value);
                            form.setFieldsValue({ tree: value });
                          }
                        }}
                        treeExpandedKeys={treeExpandedKeys}
                        onTreeExpand={(expandedKeys: Array<string | number>) => {
                          setTreeExpandedKeys(expandedKeys);
                        }}
                        loadData={loadTree}
                      />
                      {pipelineCategoryRules ? (
                        <Tooltip title={pipelineCategoryRules?.join(', ')}>
                          <ErdaIcon type="help" className="text-default-6 ml-2" size="16" />
                        </Tooltip>
                      ) : (
                        <div className="w-6" />
                      )}
                    </div>
                  )}
                />
              </div>
            </div>
            {sourceErrorMessage ? (
              <ErdaAlert message={sourceErrorMessage} type="error" closeable={false} className="py-1.5" />
            ) : null}
          </div>
        </Form>
      </div>

      <div className="py-3 px-4">
        <Button type="primary" className="mr-2" onClick={submit}>
          {btnMap[type]}
        </Button>
        <Button className="bg-default-06 border-default-06 text-default-8" onClick={() => onCancel()}>
          {i18n.t('Cancel')}
        </Button>
      </div>
    </div>
  );
}
Example #9
Source File: list.tsx    From erda-ui with GNU Affero General Public License v3.0 4 votes vote down vote up
PipelineProtocol = React.forwardRef(
  (
    { pipelineCategory, updateCategory, onAddPipeline, projectId, appId }: IProps,
    ref: React.Ref<{ reload: () => void }>,
  ) => {
    const { name: projectName } = projectStore.useStore((s) => s.info);
    const inParams = {
      projectId,
      appId,
      pipelineCategoryKey: pipelineCategory === 'all' ? undefined : pipelineCategory,
    };

    const detailId = routeInfoStore.useStore((s) => s.query.detailId);
    const initDetail = parseDetailSearch(detailId);

    const [detailVisible, setDetailVisible] = React.useState(!!initDetail);
    const [newPipelineUsed, setNewPipelineUsed] = React.useState(false);
    const [detail, setDetail] = React.useState<Detail | null>(initDetail);
    const [executeRecordId, setExecuteRecordId] = React.useState('');

    const reloadRef = React.useRef<{ reload: () => void }>(null);

    const executeRef = React.useRef<{
      execute: (_ymlStr: string, extra: { pipelineID?: string; pipelineDetail?: BUILD.IPipelineDetail }) => void;
    }>(null);

    React.useEffect(() => {
      reloadRef.current?.reload();
    }, [pipelineCategory]);

    React.useImperativeHandle(ref, () => ({
      reload: () => {
        reloadRef.current?.reload();
      },
    }));

    const runBuild = (_v?: { runParams: Obj<string | number> }) => {
      runPipeline({ pipelineDefinitionID: executeRecordId, projectID: +projectId, ..._v }).then(() => {
        reloadRef.current?.reload();
      });
    };

    const onDetailClose = React.useCallback(() => {
      updateSearch({
        detailId: undefined,
      });
      setDetailVisible(false);
      setDetail(null);
      if (newPipelineUsed) {
        reloadRef.current?.reload();
        setNewPipelineUsed(false);
      }
    }, [newPipelineUsed]);

    const shareLink = `${location.href.split('?')[0]}?${mergeSearch({ detailId: getDetailId(detail) }, true)}`;

    return (
      <>
        <DiceConfigPage
          scenarioKey="project-pipeline"
          scenarioType="project-pipeline"
          showLoading
          inParams={inParams}
          ref={reloadRef}
          operationCallBack={(reqConfig) => {
            const { event } = reqConfig;
            const { component, operationData } = event || {};
            if (component === 'pipelineTable') {
              const id = get(operationData, 'clientData.dataRef.id');
              if (['run', 'cancelRun', 'batchRun'].includes(id)) {
                updateCategory?.();
              }
            }
          }}
          customProps={{
            myPage: {
              props: {
                fullHeight: true,
              },
            },
            pageHeader: {
              props: {
                className: 'mx-2',
                isTopHead: true,
              },
            },
            pipelineTable: {
              op: {
                clickRow: async (record: {
                  id: string;
                  operations: { click: { serverData: { pipelineID: string; inode: string; appName: string } } };
                }) => {
                  setDetailVisible(true);
                  const { operations, id } = record;
                  const serverData = get(operations, 'click.serverData');
                  const { pipelineID: pipelineId, inode, appName, pipelineName } = serverData;
                  if (inode) {
                    const path = decode(inode).split('/');
                    path.pop();
                    const _appId = path[1];
                    const branchName = path.join('/').split('tree/')[1].split('/.dice')[0].split('/.erda')[0]; // such as '1/12/tree/feature/0.17.x-treeOrder/.dice', take the 'feature/0.17.x-treeOrder' of it
                    const res = await getAllBranch.fetch({ appID: +_appId });
                    let branchExist = false;
                    if (res.data) {
                      const branch = res.data.find((item: { name: string }) => item.name === branchName);
                      branch && (branchExist = true);
                    }
                    // url search 'applicationId' use for action-config-form some action with member-selector
                    updateSearch({ applicationId: appId });
                    setDetail({
                      nodeId: inode,
                      appId: _appId,
                      pipelineId,
                      pipelineDefinitionID: id,
                      branchExist,
                      pipelineName,
                      projectId,
                      projectName,
                      appName,
                    });
                  }
                },
                operations: {
                  run: async (
                    op: {
                      operations: { click: { serverData: { inode: string; pipelineID: string } } };
                    },
                    record: { id: string },
                  ) => {
                    setExecuteRecordId(record.id);
                    const { inode, pipelineID } = op.operations?.click?.serverData || {};
                    if (inode) {
                      const path = decode(inode).split('/');
                      path.pop();
                      const _appId = path[1];
                      const res = await getTreeNodeDetailNew({ id: inode, scopeID: _appId, scope: 'project-app' });
                      const ymlStr = res?.data?.meta?.pipelineYml;
                      executeRef?.current?.execute(ymlStr, { pipelineID });
                    }
                  },
                  update: (
                    op: Obj,
                    record: {
                      id: string;
                      pipeline: {
                        data: { pipelineName: { data: { text: string } }; sourceFile: { data: { text: string } } };
                      };
                    },
                  ) => {
                    const { appID, inode } = op.operations.click.serverData;
                    const { id, pipeline } = record;
                    const { data } = pipeline;
                    const { pipelineName, sourceFile } = data;
                    onAddPipeline({
                      id,
                      name: pipelineName.data.text,
                      fileName: sourceFile.data.text,
                      app: appID,
                      inode,
                    });
                  },
                },
              },
              props: {
                tableProps: {
                  whiteHead: true,
                  whiteFooter: true,
                  styleNames: 'h-full',
                  wrapperClassName: 'flex-1',
                  tableKey: 'project-pipeline',
                },
                columnsRender: {
                  source: (_val: string, _record: string, map: { [key: string]: React.ReactNode }) => {
                    return (
                      <div>
                        <div className="leading-5 text-default-9">{map.applicationName}</div>
                        <div className="flex-h-center">
                          <div className="mr-1 flex-h-center text-default-4">{map.icon}</div>
                          <div className="text-default-6">{map.branch}</div>
                        </div>
                      </div>
                    );
                  },
                  pipeline: (_val: string, _record: string, map: { [key: string]: React.ReactNode }) => {
                    return (
                      <div>
                        <div className="leading-5 text-default-9">{map.pipelineName}</div>
                        <div className="text-default-6">{map.sourceFile}</div>
                      </div>
                    );
                  },
                },
              },
            },
            addPipelineBtn: {
              op: {
                click: () => {
                  onAddPipeline();
                },
              },
            },
          }}
        />

        <Drawer
          title={
            <div className="flex justify-between items-center">
              <span>
                {i18n.t('Pipeline')} {detail?.pipelineName || ''}
              </span>
              <div>
                <Copy selector=".copy-share-link" tipName={i18n.t('dop:link-share')} />
                <ErdaIcon
                  type="lianjie"
                  className="cursor-copy hover-active copy-share-link ml-4 text-default-6"
                  size="20"
                  data-clipboard-text={shareLink}
                />
                <ErdaIcon
                  type="guanbi"
                  className="ml-4 hover-active text-default-6"
                  size="20"
                  onClick={onDetailClose}
                />
              </div>
            </div>
          }
          onClose={onDetailClose}
          visible={detailVisible}
          closable={false}
          width="80%"
          destroyOnClose
        >
          {detail ? <PipelineDetail {...detail} setNewPipelineUsed={setNewPipelineUsed} /> : null}
        </Drawer>
        <InParamsForm ref={executeRef} onExecute={runBuild} />
      </>
    );
  },
)