kirin-ri / memo

0 stars 0 forks source link

sss #22

Open kirin-ri opened 3 months ago

kirin-ri commented 3 months ago
xhr.js:258 
 POST https://li-catalog.mock.i-dna.i4square.net/api/sampleData 413
newSampleDataModal.tsx:147 Uncaught (in promise) 
Qe {message: 'Request failed with status code 413', name: 'AxiosError', code: 'ERR_BAD_REQUEST', config: {…}, request: XMLHttpRequest, …}
code
: 
"ERR_BAD_REQUEST"
config
: 
{transitional: {…}, adapter: Array(2), transformRequest: Array(1), transformResponse: Array(1), timeout: 0, …}
message
: 
"Request failed with status code 413"
name
: 
"AxiosError"
request
: 
XMLHttpRequest {onreadystatechange: null, readyState: 4, timeout: 0, withCredentials: false, upload: XMLHttpRequestUpload, …}
response
: 
{data: '<html>\r\n<head><title>413 Request Entity Too Large<…disable MSIE and Chrome friendly error page -->\r\n', status: 413, statusText: '', headers: Nt, config: {…}, …}
stack
: 
"AxiosError: Request failed with status code 413\n    at https://li-catalog.mock.i-dna.i4square.net/js/main.153daade.js:2:570327\n    at XMLHttpRequest.h (https://li-catalog.mock.i-dna.i4square.net/js/main.153daade.js:2:570475)\n    at Xt.request (https://li-catalog.mock.i-dna.i4square.net/js/main.153daade.js:2:576100)\n    at async https://li-catalog.mock.i-dna.i4square.net/js/main.153daade.js:2:999346"
[[Prototype]]
: 
Error
kirin-ri commented 3 months ago
// CodeMirror, copyright (c) by Marijn Haverbeke and others
// Distributed under an MIT license: https://codemirror.net/LICENSE

(function(mod) {
  if (typeof exports == "object" && typeof module == "object") // CommonJS
    mod(require("../../lib/codemirror"));
  else if (typeof define == "function" && define.amd) // AMD
    define(["../../lib/codemirror"], mod);
  else // Plain browser env
    mod(CodeMirror);
})(function(CodeMirror) {
"use strict";

CodeMirror.defineMode("nginx", function(config) {

  function words(str) {
    var obj = {}, words = str.split(" ");
    for (var i = 0; i < words.length; ++i) obj[words[i]] = true;
    return obj;
  }

  var keywords = words(
    /* ngxDirectiveControl */ "break return rewrite set" +
    /* ngxDirective */ " accept_mutex accept_mutex_delay access_log add_after_body add_before_body add_header addition_types aio alias allow ancient_browser ancient_browser_value auth_basic auth_basic_user_file auth_http auth_http_header auth_http_timeout autoindex autoindex_exact_size autoindex_localtime charset charset_types client_body_buffer_size client_body_in_file_only client_body_in_single_buffer client_body_temp_path client_body_timeout client_header_buffer_size client_header_timeout client_max_body_size connection_pool_size create_full_put_path daemon dav_access dav_methods debug_connection debug_points default_type degradation degrade deny devpoll_changes devpoll_events directio directio_alignment empty_gif env epoll_events error_log eventport_events expires fastcgi_bind fastcgi_buffer_size fastcgi_buffers fastcgi_busy_buffers_size fastcgi_cache fastcgi_cache_key fastcgi_cache_methods fastcgi_cache_min_uses fastcgi_cache_path fastcgi_cache_use_stale fastcgi_cache_valid fastcgi_catch_stderr fastcgi_connect_timeout fastcgi_hide_header fastcgi_ignore_client_abort fastcgi_ignore_headers fastcgi_index fastcgi_intercept_errors fastcgi_max_temp_file_size fastcgi_next_upstream fastcgi_param fastcgi_pass_header fastcgi_pass_request_body fastcgi_pass_request_headers fastcgi_read_timeout fastcgi_send_lowat fastcgi_send_timeout fastcgi_split_path_info fastcgi_store fastcgi_store_access fastcgi_temp_file_write_size fastcgi_temp_path fastcgi_upstream_fail_timeout fastcgi_upstream_max_fails flv geoip_city geoip_country google_perftools_profiles gzip gzip_buffers gzip_comp_level gzip_disable gzip_hash gzip_http_version gzip_min_length gzip_no_buffer gzip_proxied gzip_static gzip_types gzip_vary gzip_window if_modified_since ignore_invalid_headers image_filter image_filter_buffer image_filter_jpeg_quality image_filter_transparency imap_auth imap_capabilities imap_client_buffer index ip_hash keepalive_requests keepalive_timeout kqueue_changes kqueue_events large_client_header_buffers limit_conn limit_conn_log_level limit_rate limit_rate_after limit_req limit_req_log_level limit_req_zone limit_zone lingering_time lingering_timeout lock_file log_format log_not_found log_subrequest map_hash_bucket_size map_hash_max_size master_process memcached_bind memcached_buffer_size memcached_connect_timeout memcached_next_upstream memcached_read_timeout memcached_send_timeout memcached_upstream_fail_timeout memcached_upstream_max_fails merge_slashes min_delete_depth modern_browser modern_browser_value msie_padding msie_refresh multi_accept open_file_cache open_file_cache_errors open_file_cache_events open_file_cache_min_uses open_file_cache_valid open_log_file_cache output_buffers override_charset perl perl_modules perl_require perl_set pid pop3_auth pop3_capabilities port_in_redirect postpone_gzipping postpone_output protocol proxy proxy_bind proxy_buffer proxy_buffer_size proxy_buffering proxy_buffers proxy_busy_buffers_size proxy_cache proxy_cache_key proxy_cache_methods proxy_cache_min_uses proxy_cache_path proxy_cache_use_stale proxy_cache_valid proxy_connect_timeout proxy_headers_hash_bucket_size proxy_headers_hash_max_size proxy_hide_header proxy_ignore_client_abort proxy_ignore_headers proxy_intercept_errors proxy_max_temp_file_size proxy_method proxy_next_upstream proxy_pass_error_message proxy_pass_header proxy_pass_request_body proxy_pass_request_headers proxy_read_timeout proxy_redirect proxy_send_lowat proxy_send_timeout proxy_set_body proxy_set_header proxy_ssl_session_reuse proxy_store proxy_store_access proxy_temp_file_write_size proxy_temp_path proxy_timeout proxy_upstream_fail_timeout proxy_upstream_max_fails random_index read_ahead real_ip_header recursive_error_pages request_pool_size reset_timedout_connection resolver resolver_timeout rewrite_log rtsig_overflow_events rtsig_overflow_test rtsig_overflow_threshold rtsig_signo satisfy secure_link_secret send_lowat send_timeout sendfile sendfile_max_chunk server_name_in_redirect server_names_hash_bucket_size server_names_hash_max_size server_tokens set_real_ip_from smtp_auth smtp_capabilities smtp_client_buffer smtp_greeting_delay so_keepalive source_charset ssi ssi_ignore_recycled_buffers ssi_min_file_chunk ssi_silent_errors ssi_types ssi_value_length ssl ssl_certificate ssl_certificate_key ssl_ciphers ssl_client_certificate ssl_crl ssl_dhparam ssl_engine ssl_prefer_server_ciphers ssl_protocols ssl_session_cache ssl_session_timeout ssl_verify_client ssl_verify_depth starttls stub_status sub_filter sub_filter_once sub_filter_types tcp_nodelay tcp_nopush thread_stack_size timeout timer_resolution types_hash_bucket_size types_hash_max_size underscores_in_headers uninitialized_variable_warn use user userid userid_domain userid_expires userid_mark userid_name userid_p3p userid_path userid_service valid_referers variables_hash_bucket_size variables_hash_max_size worker_connections worker_cpu_affinity worker_priority worker_processes worker_rlimit_core worker_rlimit_nofile worker_rlimit_sigpending worker_threads working_directory xclient xml_entities xslt_stylesheet xslt_typesdrew@li229-23"
    );

  var keywords_block = words(
    /* ngxDirectiveBlock */ "http mail events server types location upstream charset_map limit_except if geo map"
    );

  var keywords_important = words(
    /* ngxDirectiveImportant */ "include root server server_name listen internal proxy_pass memcached_pass fastcgi_pass try_files"
    );

  var indentUnit = config.indentUnit, type;
  function ret(style, tp) {type = tp; return style;}

  function tokenBase(stream, state) {

    stream.eatWhile(/[\w\$_]/);

    var cur = stream.current();

    if (keywords.propertyIsEnumerable(cur)) {
      return "keyword";
    }
    else if (keywords_block.propertyIsEnumerable(cur)) {
      return "variable-2";
    }
    else if (keywords_important.propertyIsEnumerable(cur)) {
      return "string-2";
    }
    /**/

    var ch = stream.next();
    if (ch == "@") {stream.eatWhile(/[\w\\\-]/); return ret("meta", stream.current());}
    else if (ch == "/" && stream.eat("*")) {
      state.tokenize = tokenCComment;
      return tokenCComment(stream, state);
    }
    else if (ch == "<" && stream.eat("!")) {
      state.tokenize = tokenSGMLComment;
      return tokenSGMLComment(stream, state);
    }
    else if (ch == "=") ret(null, "compare");
    else if ((ch == "~" || ch == "|") && stream.eat("=")) return ret(null, "compare");
    else if (ch == "\"" || ch == "'") {
      state.tokenize = tokenString(ch);
      return state.tokenize(stream, state);
    }
    else if (ch == "#") {
      stream.skipToEnd();
      return ret("comment", "comment");
    }
    else if (ch == "!") {
      stream.match(/^\s*\w*/);
      return ret("keyword", "important");
    }
    else if (/\d/.test(ch)) {
      stream.eatWhile(/[\w.%]/);
      return ret("number", "unit");
    }
    else if (/[,.+>*\/]/.test(ch)) {
      return ret(null, "select-op");
    }
    else if (/[;{}:\[\]]/.test(ch)) {
      return ret(null, ch);
    }
    else {
      stream.eatWhile(/[\w\\\-]/);
      return ret("variable", "variable");
    }
  }

  function tokenCComment(stream, state) {
    var maybeEnd = false, ch;
    while ((ch = stream.next()) != null) {
      if (maybeEnd && ch == "/") {
        state.tokenize = tokenBase;
        break;
      }
      maybeEnd = (ch == "*");
    }
    return ret("comment", "comment");
  }

  function tokenSGMLComment(stream, state) {
    var dashes = 0, ch;
    while ((ch = stream.next()) != null) {
      if (dashes >= 2 && ch == ">") {
        state.tokenize = tokenBase;
        break;
      }
      dashes = (ch == "-") ? dashes + 1 : 0;
    }
    return ret("comment", "comment");
  }

  function tokenString(quote) {
    return function(stream, state) {
      var escaped = false, ch;
      while ((ch = stream.next()) != null) {
        if (ch == quote && !escaped)
          break;
        escaped = !escaped && ch == "\\";
      }
      if (!escaped) state.tokenize = tokenBase;
      return ret("string", "string");
    };
  }

  return {
    startState: function(base) {
      return {tokenize: tokenBase,
              baseIndent: base || 0,
              stack: []};
    },

    token: function(stream, state) {
      if (stream.eatSpace()) return null;
      type = null;
      var style = state.tokenize(stream, state);

      var context = state.stack[state.stack.length-1];
      if (type == "hash" && context == "rule") style = "atom";
      else if (style == "variable") {
        if (context == "rule") style = "number";
        else if (!context || context == "@media{") style = "tag";
      }

      if (context == "rule" && /^[\{\};]$/.test(type))
        state.stack.pop();
      if (type == "{") {
        if (context == "@media") state.stack[state.stack.length-1] = "@media{";
        else state.stack.push("{");
      }
      else if (type == "}") state.stack.pop();
      else if (type == "@media") state.stack.push("@media");
      else if (context == "{" && type != "comment") state.stack.push("rule");
      return style;
    },

    indent: function(state, textAfter) {
      var n = state.stack.length;
      if (/^\}/.test(textAfter))
        n -= state.stack[state.stack.length-1] == "rule" ? 2 : 1;
      return state.baseIndent + n * indentUnit;
    },

    electricChars: "}"
  };
});

CodeMirror.defineMIME("text/x-nginx-conf", "nginx");

});
kirin-ri commented 3 months ago
helm install nginx-ingress ingress-nginx/ingress-nginx \
    --namespace ingress-basic \
    --set controller.replicaCount=2 \
    --set controller.service.externalTrafficPolicy=Local \
    --set controller.service.loadBalancerSourceRanges="{[許可IP]}" \
    --version 4.8.0
# インストール確認
kubectl config set-context --current --namespace=ingress-basic
helm list -n ingress-basic
kirin-ri commented 3 months ago
import {
  useCallback,
  useEffect,
  useLayoutEffect,
  useMemo,
  useState,
} from 'react';
import { useDropzone } from 'react-dropzone';
import Swal from 'sweetalert2';
import withReactContent from 'sweetalert2-react-content';
import { Spacer } from '../spacer';
import { DialogModalOK, hideDialog, showDialog } from './dialogModal';
import { Link } from 'react-router-dom';
import axios from 'axios';
import React from 'react';

const MySwal = withReactContent(Swal);

type UploadedFile = {
  filename: string;
  jobId: string;
};

const NewSampleDataModal = (props: { id: string; logicalName: string }) => {
  const id = props.id;
  const [uploadedFileInfo, setUploadedFileInfo] = useState<UploadedFile[]>();
  const [errorMsg, setErrorMsg] = useState<string>('');

  const onDrop = useCallback((acceptedFiles: any) => {
    const type = acceptedFiles[0].type;
    if (type === 'text/csv' || type === 'application/json') {
      return;
    }
    MySwal.fire({
      icon: 'error',
      title: 'アップロードできるのはCSVかJSONのみです',
      toast: true,
      position: 'top-end',
      showConfirmButton: false,
      timer: 3000,
    });
    acceptedFiles.length = 0;
  }, []); // 空配列を指定したのでonDropのインスタンスはコンポーネントの破棄まで更新されない

  const { getRootProps, getInputProps, open, isDragActive, acceptedFiles } =
    useDropzone({
      onDrop,
      noClick: true,
    }); // (1)

  useLayoutEffect(() => {
    // モーダルが閉じられた場合、API連携項目追加モーダルに返す
    $('#' + id.replaceAll('_', '') + 'sample-data').on(
      'hidden.bs.modal',
      () => {
        setErrorMsg('');
        $('#' + id + '-dtl-modal').modal('show');
      }
    );
    $('#' + id.replaceAll('_', '') + '-job-start-notification').on(
      'hidden.bs.modal',
      () => {
        // ジョブ開始ダイアログが閉じられた場合、上のイベントを復活させる
        $('#' + id.replaceAll('_', '') + 'sample-data').on(
          'hidden.bs.modal',
          () => {
            setErrorMsg('');
            $('#' + id + '-dtl-modal').modal('show');
          }
        );
      }
    );
  }, []);

  useLayoutEffect(() => {
    if (uploadedFileInfo && uploadedFileInfo.length > 0) {
      // ジョブ開始ダイアログ表示
      const $sampleDataModal = $('#' + id.replaceAll('_', '') + 'sample-data');
      $sampleDataModal.off('hidden.bs.modal');
      showDialog(
        `${id.replaceAll('_', '')}-job-start-notification`,
        $sampleDataModal
      );
    }
  }, [uploadedFileInfo]);

  function sleep(ms: number | undefined) {
    return new Promise((resolve) => setTimeout(resolve, ms));
  }

  async function fileUpload(method: string) {
    let i = 1;
    let uploadedFiles: UploadedFile[] = [];
    let errorMsg = '';
    for (let el of acceptedFiles) {
      var reader = new FileReader();
      reader.onload = async function (e: any) {
        let filename = el.name;
        if (method === 'update' && i == 2) {
          method = 'insert';
        }
        if (uploadedFiles.length == 0) {
          document.getElementById('loading-spinner')!.style.display = 'grid';
        }
        // loading画面有効化・解除の都合でcommonAjaxを使用しない
        (async () => {
          const formData = new FormData();
          const rmp = {
            id,
            method,
            filename,
          };
          const jsonStr = JSON.stringify(rmp);
          formData.append('file', el);
          formData.append('data', jsonStr);

          await axios
            .post('/api/sampleData', formData, {
              headers: { 'Content-Type': 'multipart/form-data' },
            })
            .then((res: any) => {
              ++i;
              uploadedFiles.push({ filename: el.name, jobId: res.data.jobId });
              // すべてのファイルをアップロード後
              if (uploadedFiles.length === acceptedFiles.length) {
                if (res.data.errorMsg != null) {
                  const texts = res.data.errorMsg
                    .split(/(\n)/)
                    .map((item: any, index: any) => {
                      return (
                        <React.Fragment key={index}>
                          {item.match(/\n/) ? <br /> : item}
                        </React.Fragment>
                      );
                    });
                  setErrorMsg(texts);
                  document.getElementById('loading-spinner')!.style.display =
                    'none';
                } else {
                  setErrorMsg('');
                  setUploadedFileInfo(uploadedFiles);
                  document.getElementById('loading-spinner')!.style.display =
                    'none';
                }
              }
            });
        })();
      };
      reader.readAsText(el);
      // 複数ファイル挿入場合、連続したrequestでjobIDが同一になるのを防ぐためsleep
      //(前requestのジョブステータス登録を待つ)
      await sleep(3000);
    }
    if (errorMsg) {
      MySwal.fire({
        icon: 'error',
        title: 'ERROR: ' + errorMsg,
        toast: true,
        position: 'top-end',
        showConfirmButton: false,
        timer: 3000,
      });
      document.getElementById('loading-spinner')!.style.display = 'none';
    }
  }

  function fileUpdate() {
    fileUpload('update');
  }

  function fileInsert() {
    fileUpload('insert');
  }

  function csv2json(csv: string) {
    const csvArray = csv.split('\n');
    var jsonArray = [];

    // 1行目から「項目名」の配列を生成する
    var items = csvArray[0].split(',');

    // CSVデータの配列の各行をループ処理する
    //// 配列の先頭要素(行)は項目名のため処理対象外
    //// 配列の最終要素(行)は空のため処理対象外
    for (let i = 1; i < csvArray.length - 1; i++) {
      const a_line: any = {};
      // カンマで区切られた各データに分割する
      const csvArrayD = csvArray[i].split(',');
      //// 各データをループ処理する
      for (let j = 0; j < items.length; j++) {
        // 要素名:items[j]
        // データ:csvArrayD[j]
        a_line[items[j]] = csvArrayD[j];
      }
      jsonArray.push(a_line);
    }
    //console.debug(jsonArray);
    return jsonArray;
  }

  const files = useMemo(
    () =>
      acceptedFiles.map((file) => [
        <div className="cell-boder" key={file.name + '-name'}>
          {file.name}
        </div>,
        <div className="cell-boder" key={file.name + '-type'}>
          {file.type === 'text/csv' ? 'CSVファイル' : 'JSONファイル'}
        </div>,
      ]),
    [acceptedFiles]
  );

  return (
    <div>
      {/* Content Header (Page header) */}
      <div className="modal fade" id={id.replaceAll('_', '') + 'sample-data'}>
        <div className="modal-dialog modal-xl">
          <div className="modal-content">
            <div className="modal-header">
              <h4 className="modal-title">サンプルデータ挿入</h4>
              <button
                type="button"
                className="close"
                data-dismiss="modal"
                aria-label="Close"
              >
                <span aria-hidden="true">&times;</span>
              </button>
            </div>
            <div className="modal-body">
              {/* API name display area */}
              {Spacer({ size: 20 })}
              <div className="drop-area">
                <div {...getRootProps()}>
                  <input {...getInputProps()} />
                  <div
                    className={`data-insert-box ${
                      acceptedFiles.length === 0 && 'drop-bg'
                    }`}
                  >
                    {Spacer({ size: 20 })}
                    <div
                      className={`${
                        acceptedFiles.length != 0 && 'file-name-wrapper'
                      }`}
                    >
                      <div className="file-name-area">{files}</div>
                    </div>
                    <div
                      className={`${
                        acceptedFiles.length === 0
                          ? 'input-file-area-empty'
                          : 'input-file-area'
                      }`}
                    >
                      {acceptedFiles.length === 0 && (
                        <>
                          {Spacer({ size: 80 })}
                          <i className="fa fa-upload upload-icon"></i>
                          {Spacer({ size: 20 })}
                        </>
                      )}
                      ここにファイルをドロップ
                      <br />
                      <p>
                        またはファイルを
                        <a className="file-a-btn" onClick={open}>
                          &nbsp;<u>参照</u>
                        </a>
                      </p>
                    </div>
                  </div>
                </div>
              </div>
              {Spacer({ size: 50 })}
              <div className="text-danger error-msg">{errorMsg}</div>
              <div className="dividing-line" />
              {Spacer({ size: 30 })}
              <div className="btn-center">
                <button
                  className={`btn btn-primary ${
                    acceptedFiles.length === 0 && 'disabled'
                  }`}
                  onClick={fileInsert}
                >
                  挿入
                </button>
                {Spacer({ size: 30, horizontal: true })}
                <button
                  className={`btn btn-primary ${
                    acceptedFiles.length === 0 && 'disabled'
                  }`}
                  onClick={fileUpdate}
                >
                  差替
                </button>
              </div>
              {Spacer({ size: 30 })}
            </div>
          </div>
          {/* <!-- /.modal-content --> */}
        </div>
      </div>
      <JobStartNotification
        id={id}
        name={props.logicalName}
        files={uploadedFileInfo}
      />
    </div>
  );
};

function JobStartNotification({
  id,
  name,
  files,
}: {
  id: string;
  name: string;
  files?: UploadedFile[];
}) {
  const modalId = `${id.replaceAll('_', '')}-job-start-notification`;
  return (
    <DialogModalOK id={modalId} title="処理を開始しました">
      <p>
        {name} サンプルデータ挿入処理を開始しました。
        <br />
        完了には時間がかかりますのでお待ちください。
        <br />
        処理の状況は下記画面で確認できます。
      </p>
      <p>アップロードされたファイル:</p>
      <ul>
        {files?.map((f) => (
          <li key={f.filename}>
            {f.filename}&nbsp;
            <Link
              to={`/jobs/${f.jobId}`}
              className="btn btn-secondary"
              target="_blank"
              onClick={() => hideDialog(modalId)}
            >
              ジョブステータス確認
            </Link>
          </li>
        ))}
      </ul>
    </DialogModalOK>
  );
}

export default NewSampleDataModal;
kirin-ri commented 3 months ago
import {
  useCallback,
  useEffect,
  useLayoutEffect,
  useMemo,
  useState,
} from 'react';
import { useDropzone } from 'react-dropzone';
import Swal from 'sweetalert2';
import withReactContent from 'sweetalert2-react-content';
import { Spacer } from '../spacer';
import { DialogModalOK, hideDialog, showDialog } from './dialogModal';
import { Link } from 'react-router-dom';
import axios from 'axios';
import React from 'react';

const MySwal = withReactContent(Swal);

type UploadedFile = {
  filename: string;
  jobId: string;
};

const NewSampleDataModal = (props: { id: string; logicalName: string }) => {
  const id = props.id;
  const [uploadedFileInfo, setUploadedFileInfo] = useState<UploadedFile[]>();
  const [errorMsg, setErrorMsg] = useState<string>('');

  const onDrop = useCallback((acceptedFiles: any) => {
    const type = acceptedFiles[0].type;
    if (type === 'text/csv' || type === 'application/json') {
      return;
    }
    MySwal.fire({
      icon: 'error',
      title: 'アップロードできるのはCSVかJSONのみです',
      toast: true,
      position: 'top-end',
      showConfirmButton: false,
      timer: 3000,
    });
    acceptedFiles.length = 0;
  }, []); // 空配列を指定したのでonDropのインスタンスはコンポーネントの破棄まで更新されない

  const { getRootProps, getInputProps, open, isDragActive, acceptedFiles } =
    useDropzone({
      onDrop,
      noClick: true,
    }); // (1)

  useLayoutEffect(() => {
    // モーダルが閉じられた場合、API連携項目追加モーダルに返す
    $('#' + id.replaceAll('_', '') + 'sample-data').on(
      'hidden.bs.modal',
      () => {
        setErrorMsg('');
        $('#' + id + '-dtl-modal').modal('show');
      }
    );
    $('#' + id.replaceAll('_', '') + '-job-start-notification').on(
      'hidden.bs.modal',
      () => {
        // ジョブ開始ダイアログが閉じられた場合、上のイベントを復活させる
        $('#' + id.replaceAll('_', '') + 'sample-data').on(
          'hidden.bs.modal',
          () => {
            setErrorMsg('');
            $('#' + id + '-dtl-modal').modal('show');
          }
        );
      }
    );
  }, []);

  useLayoutEffect(() => {
    if (uploadedFileInfo && uploadedFileInfo.length > 0) {
      // ジョブ開始ダイアログ表示
      const $sampleDataModal = $('#' + id.replaceAll('_', '') + 'sample-data');
      $sampleDataModal.off('hidden.bs.modal');
      showDialog(
        `${id.replaceAll('_', '')}-job-start-notification`,
        $sampleDataModal
      );
    }
  }, [uploadedFileInfo]);

  function sleep(ms: number | undefined) {
    return new Promise((resolve) => setTimeout(resolve, ms));
  }

  async function fileUpload(method: string) {
    let i = 1;
    let uploadedFiles: UploadedFile[] = [];
    let errorMsg = '';
    for (let el of acceptedFiles) {
      var reader = new FileReader();
      reader.onload = async function (e: any) {
        let filename = el.name;
        if (method === 'update' && i == 2) {
          method = 'insert';
        }
        if (uploadedFiles.length == 0) {
          document.getElementById('loading-spinner')!.style.display = 'grid';
        }
        // loading画面有効化・解除の都合でcommonAjaxを使用しない
        (async () => {
          const formData = new FormData();
          const rmp = {
            id,
            method,
            filename,
          };
          const jsonStr = JSON.stringify(rmp);
          formData.append('file', el);
          formData.append('data', jsonStr);

          await axios
            .post('/api/sampleData', formData, {
              headers: { 'Content-Type': 'multipart/form-data' },
            })
            .then((res: any) => {
              ++i;
              uploadedFiles.push({ filename: el.name, jobId: res.data.jobId });
              // すべてのファイルをアップロード後
              if (uploadedFiles.length === acceptedFiles.length) {
                if (res.data.errorMsg != null) {
                  const texts = res.data.errorMsg
                    .split(/(\n)/)
                    .map((item: any, index: any) => {
                      return (
                        <React.Fragment key={index}>
                          {item.match(/\n/) ? <br /> : item}
                        </React.Fragment>
                      );
                    });
                  setErrorMsg(texts);
                  document.getElementById('loading-spinner')!.style.display =
                    'none';
                } else {
                  setErrorMsg('');
                  setUploadedFileInfo(uploadedFiles);
                  document.getElementById('loading-spinner')!.style.display =
                    'none';
                }
              }
            }).catch((error) => {
              if (error.response && error.response.status === 413) {
                setErrorMsg('20MB以下のファイルをアップロードしてください。')
              }
            })
        })();
      };
      reader.readAsText(el);
      // 複数ファイル挿入場合、連続したrequestでjobIDが同一になるのを防ぐためsleep
      //(前requestのジョブステータス登録を待つ)
      await sleep(3000);
    }
    if (errorMsg) {
      MySwal.fire({
        icon: 'error',
        title: 'ERROR: ' + errorMsg,
        toast: true,
        position: 'top-end',
        showConfirmButton: false,
        timer: 3000,
      });
      document.getElementById('loading-spinner')!.style.display = 'none';
    }
  }

  function fileUpdate() {
    fileUpload('update');
  }

  function fileInsert() {
    fileUpload('insert');
  }

  function csv2json(csv: string) {
    const csvArray = csv.split('\n');
    var jsonArray = [];

    // 1行目から「項目名」の配列を生成する
    var items = csvArray[0].split(',');

    // CSVデータの配列の各行をループ処理する
    //// 配列の先頭要素(行)は項目名のため処理対象外
    //// 配列の最終要素(行)は空のため処理対象外
    for (let i = 1; i < csvArray.length - 1; i++) {
      const a_line: any = {};
      // カンマで区切られた各データに分割する
      const csvArrayD = csvArray[i].split(',');
      //// 各データをループ処理する
      for (let j = 0; j < items.length; j++) {
        // 要素名:items[j]
        // データ:csvArrayD[j]
        a_line[items[j]] = csvArrayD[j];
      }
      jsonArray.push(a_line);
    }
    //console.debug(jsonArray);
    return jsonArray;
  }

  const files = useMemo(
    () =>
      acceptedFiles.map((file) => [
        <div className="cell-boder" key={file.name + '-name'}>
          {file.name}
        </div>,
        <div className="cell-boder" key={file.name + '-type'}>
          {file.type === 'text/csv' ? 'CSVファイル' : 'JSONファイル'}
        </div>,
      ]),
    [acceptedFiles]
  );

  return (
    <div>
      {/* Content Header (Page header) */}
      <div className="modal fade" id={id.replaceAll('_', '') + 'sample-data'}>
        <div className="modal-dialog modal-xl">
          <div className="modal-content">
            <div className="modal-header">
              <h4 className="modal-title">サンプルデータ挿入</h4>
              <button
                type="button"
                className="close"
                data-dismiss="modal"
                aria-label="Close"
              >
                <span aria-hidden="true">&times;</span>
              </button>
            </div>
            <div className="modal-body">
              {/* API name display area */}
              {Spacer({ size: 20 })}
              <div className="drop-area">
                <div {...getRootProps()}>
                  <input {...getInputProps()} />
                  <div
                    className={`data-insert-box ${
                      acceptedFiles.length === 0 && 'drop-bg'
                    }`}
                  >
                    {Spacer({ size: 20 })}
                    <div
                      className={`${
                        acceptedFiles.length != 0 && 'file-name-wrapper'
                      }`}
                    >
                      <div className="file-name-area">{files}</div>
                    </div>
                    <div
                      className={`${
                        acceptedFiles.length === 0
                          ? 'input-file-area-empty'
                          : 'input-file-area'
                      }`}
                    >
                      {acceptedFiles.length === 0 && (
                        <>
                          {Spacer({ size: 80 })}
                          <i className="fa fa-upload upload-icon"></i>
                          {Spacer({ size: 20 })}
                        </>
                      )}
                      ここにファイルをドロップ
                      <br />
                      <p>
                        またはファイルを
                        <a className="file-a-btn" onClick={open}>
                          &nbsp;<u>参照</u>
                        </a>
                      </p>
                    </div>
                  </div>
                </div>
              </div>
              {Spacer({ size: 50 })}
              <div className="text-danger error-msg">{errorMsg}</div>
              <div className="dividing-line" />
              {Spacer({ size: 30 })}
              <div className="btn-center">
                <button
                  className={`btn btn-primary ${
                    acceptedFiles.length === 0 && 'disabled'
                  }`}
                  onClick={fileInsert}
                >
                  挿入
                </button>
                {Spacer({ size: 30, horizontal: true })}
                <button
                  className={`btn btn-primary ${
                    acceptedFiles.length === 0 && 'disabled'
                  }`}
                  onClick={fileUpdate}
                >
                  差替
                </button>
              </div>
              {Spacer({ size: 30 })}
            </div>
          </div>
          {/* <!-- /.modal-content --> */}
        </div>
      </div>
      <JobStartNotification
        id={id}
        name={props.logicalName}
        files={uploadedFileInfo}
      />
    </div>
  );
};

function JobStartNotification({
  id,
  name,
  files,
}: {
  id: string;
  name: string;
  files?: UploadedFile[];
}) {
  const modalId = `${id.replaceAll('_', '')}-job-start-notification`;
  return (
    <DialogModalOK id={modalId} title="処理を開始しました">
      <p>
        {name} サンプルデータ挿入処理を開始しました。
        <br />
        完了には時間がかかりますのでお待ちください。
        <br />
        処理の状況は下記画面で確認できます。
      </p>
      <p>アップロードされたファイル:</p>
      <ul>
        {files?.map((f) => (
          <li key={f.filename}>
            {f.filename}&nbsp;
            <Link
              to={`/jobs/${f.jobId}`}
              className="btn btn-secondary"
              target="_blank"
              onClick={() => hideDialog(modalId)}
            >
              ジョブステータス確認
            </Link>
          </li>
        ))}
      </ul>
    </DialogModalOK>
  );
}

export default NewSampleDataModal;
kirin-ri commented 3 months ago

az network nic list --resource-group <リソースグループ名> --query "[].{name:name, PrivateIP:ipConfigurations[0].privateIpAddress, PublicIP:ipConfigurations[0].publicIpAddress.id}" -o table