kirin-ri / memo

0 stars 0 forks source link

718 #7

Open kirin-ri opened 1 year ago

kirin-ri commented 1 year ago
              <button className="btn btn-primary" data-target='#MessageModal'
                      onClick={()=>{
                        let flg = true
                        editAPI.outinfo[0].column.map((item:Defs.EditColumn)=>{
                          if(!item.delete){
                            flg = false
                            setReflectLock(false)
                          }
                        })
                        if(!flg){
                          putChangeAPI()
                          //メッセージモーダル
                          {
                            $("#"+editAPI.physical_name+"-dtl-modal").modal("hide").on("hidden.bs.modal",()=>{
                              setTimeout(()=>$("#MessageModal").modal("show"))
                              $("#"+editAPI.physical_name+"-dtl-modal").off("hidden.bs.modal")
                            })
                          }
                        }else{
                          $('#'+editAPI.physical_name+'-error').text("連携項目は1つ以上必要です")
                        }
                      }}>
                反映する
              </button>
kirin-ri commented 1 year ago

メッセージモーダル部分が動かないため、修正してください。

kirin-ri commented 1 year ago
          <div>
          販売計画誤差率:年次
          </div>
kirin-ri commented 1 year ago

販売計画誤差率:年次を押して、別ページでリンク先が開くように修正してください。

kirin-ri commented 1 year ago

開いたモーダルがモーダル以外の部分をクリックしたら、モーダルが閉じれます。 閉じれないように修正してください。

                            {
                              $("#"+editAPI.physical_name+"-dtl-modal").modal("hide").on("hidden.bs.modal",()=>{
                                setTimeout(()=>$("#MessageModal").modal("show"))
                                $("#"+editAPI.physical_name+"-dtl-modal").off("hidden.bs.modal")
                              })
                            }
kirin-ri commented 1 year ago
             <button className="btn btn-primary" data-backdrop="false" data-target='#MessageModal'
                      onClick={()=>{
                        let flg = true
                        editAPI.outinfo[0].column.map((item:Defs.EditColumn)=>{
                          if(!item.delete){
                            flg = false
                            setReflectLock(false)
                          }
                        })
                        if(!flg){
                          putChangeAPI()
                          //メッセージモーダル
                          // if (updated){
                            {
                              $("#"+editAPI.physical_name+"-dtl-modal").modal("hide").on("hidden.bs.modal",()=>{
                                setTimeout(()=>$("#MessageModal").modal({backdrop:"static"}).modal("show"))
                                $("#"+editAPI.physical_name+"-dtl-modal").off("hidden.bs.modal")
                              })
                            }
                          }else{
                            $('#'+editAPI.physical_name+'-error').text("連携項目は1つ以上必要です")
                          }
                        }
                      }>
                反映する
              </button>
kirin-ri commented 1 year ago

モーダル"#MessageModalがまだ閉じられます。

kirin-ri commented 1 year ago
              <button className="btn btn-primary"
                      data-toggle="modal" 
                      data-target="#MessageModal" 
                      data-backdrop="static"
                      onClick={()=>{
                        let flg = true
                        editAPI.outinfo[0].column.map((item:Defs.EditColumn)=>{
                          if(!item.delete){
                            flg = false
                            setReflectLock(false)
                          }
                        })
                        if(!flg){
                          putChangeAPI()
                          //メッセージモーダル
                          if (updated) {
                            {
                              $("#"+editAPI.physical_name+"-dtl-modal").modal("hide").on("hidden.bs.modal",()=>{
                                setTimeout(()=>$("#MessageModal").modal("show"))
                                $("#"+editAPI.physical_name+"-dtl-modal").off("hidden.bs.modal")
                              })
                            }
                          }else{
                            $('#'+editAPI.physical_name+'-error').text("連携項目は1つ以上必要です")
                          }
                        }
                      }}>
                反映する
              </button>
kirin-ri commented 1 year ago

updatedがfalseの場合でも#MessageModalモーダルが出ました。なぜ?

kirin-ri commented 1 year ago
          commonAjax
            .axios({swalFire: true, loading: true})
            .put(`/api/api/${editAPI.physical_name}`, apiList.outinfo[0].column)
            .then((res) => {
              apiList.outinfo[0].column.map((col:Defs.EditColumn)=>{
                col["delete"] = false;
                col["editing"] = false;
                col["edited"] = false;
              }
              )
              setEditAPI(apiList)
              setUpdated(true)
            });
        })();
kirin-ri commented 1 year ago

ここに通信してきた戻り値を取得したい

kirin-ri commented 1 year ago
バックエンドから以下を戻り値にしています。
res = {"meta": ["販売計画誤差率:年次","基準在庫(在庫数・金額):年次"]}
return res

res.data.metaがある度、listに挿入するコードは以下ですが、うまくいかないため、修正をお願い致します。
          commonAjax
            .axios({swalFire: true, loading: true})
            .put(`/api/api/${editAPI.physical_name}`, apiList.outinfo[0].column)
            .then((res) => {
    const list = [];
               list.add(res.data.meta)
              apiList.outinfo[0].column.map((col:Defs.EditColumn)=>{
                col["delete"] = false;
                col["editing"] = false;
                col["edited"] = false;
              }
              )
              setEditAPI(apiList)
              setUpdated(true)
            });
        })();
kirin-ri commented 1 year ago
list.push(res.data.meta);
setList(list);

listを格納できるuseStateを定義してください。
const [List, setList] = useState<>();
kirin-ri commented 1 year ago
listは['販売計画誤差率:年次', '基準在庫(在庫数・金額):年次']です。

const [List, setList] = useState([]);だとlistが入れない
kirin-ri commented 1 year ago
              <button className="btn btn-primary"
                      data-toggle="modal"
                      data-backdrop="static" 
                      onClick={()=>{
                        let flg = true
                        editAPI.outinfo[0].column.map((item:Defs.EditColumn)=>{
                          if(!item.delete){
                            flg = false
                            setReflectLock(false)
                          }
                        })
                        if(!flg){
                          putChangeAPI()
                          if (updated) {
                            $("#"+editAPI.physical_name+"-dtl-modal").modal("hide").on("hidden.bs.modal",()=>{
                              setTimeout(()=>$("#"+editAPI.physical_name+"MessageModal").modal({backdrop: "static"}).modal("show"))
                              $("#"+editAPI.physical_name+"-dtl-modal").off("hidden.bs.modal")
                            })
                          }
                        }else{
                          $('#'+editAPI.physical_name+'-error').text("連携項目は1つ以上必要です")
                        }
                      }}>
                反映する
              </button>
kirin-ri commented 1 year ago
import React, { ChangeEvent, useState } from "react";
import { useForm } from 'react-hook-form';
import { Spacer } from "../spacer";
import { commonAjax } from '../../../components/commonAjax';
import * as Defs from './apiDefs';

const NewAPIDtlModal = (props: { val: Defs.Api }) => {
  // プルダウンの選択肢
  const gender = [
    { key: 'integer', label: 'integer' },
    { key: 'long', label: 'long' },
    { key: 'float', label: 'float' },
    { key: 'double', label: 'double' },
    { key: 'string', label: 'string' },
    { key: 'byte', label: 'byte' },
    { key: 'binary', label: 'binary' },
    { key: 'boolean', label: 'boolean(true,false)' },
    { key: 'date', label: 'date(yyyy-mm-dd)' },
    { key: 'dateTime', label: 'dateTime(yyyy-mm-ddTHH:MM:SSZ)' },
  ];

  // api情報をコピー
  const tmp = JSON.parse(JSON.stringify(props.val))
  // apiの各項目に削除、編集中、編集済のフラグを付与
  tmp.outinfo[0].column.map((col:Defs.EditColumn)=>{
    col["delete"] = false;
    col["editing"] = false;
    col["edited"] = false;
  })

  // useState
  const origin = JSON.parse(JSON.stringify(tmp))
  const [editAPI, setEditAPI] = useState<Defs.EditApi>(tmp);
  const [editIndex, setEditIndex] = useState<string>("")
  const [reflectLock, setReflectLock] = useState<boolean>(true)
  const [updated, setUpdated] = useState<boolean>(false)
  // input form
  const [colPhysicalName, setColPhysicalName] = useState<string>("")
  const [colLogicalName, setColLogicalName] = useState<string>("")
  const [colType, setColType] = useState<string>("")
  const [List, setList] = useState<any>();

  // react hook form
  const {
    register,
    resetField,
    formState: { isDirty, isValid, errors },
  } = useForm({
    defaultValues: { colLogicalName: '', colPhysicalName:'', colType:''},
    mode: 'onChange',
    criteriaMode: 'all',
  });
  const colLogicalNameField = register('colLogicalName', {
    required: {
      value: true,
      message: '論理名は入力が必須の項目です',
    },
  });
  const colPhysicalNameField = register('colPhysicalName', {
    required: {
      value: true,
      message: '物理名は入力が必須の項目です',
    },
    pattern: {
      value: /^[0-9a-zA-Z_]+$/,
      message: '物理名には英数字およびアンダースコアのみ使用可能です',
    }
  });
  const colTypeField = register('colType', {
    required: {
      value: true,
      message: 'データ型は入力が必須の項目です',
    },
  });

  // 物理名、論理名が入力された際に値を設定する
  const handleChange = (e: ChangeEvent<HTMLInputElement>) => {
    switch (e.target.name) {
      case 'colLogicalName':
        setColLogicalName(e.target.value);
        break;
      case 'colPhysicalName':
        setColPhysicalName(e.target.value);
        break;
    }
  };
  // データ型が入力された際に値を設定する
  const selectChange = (e: ChangeEvent<HTMLSelectElement>) => {
        setColType(e.target.value);
  };

  // 更新と追加のボタン切り替え
  const addOrUpd = ()=>{
    if(editIndex===""){
      return(
        <div className="btn-right">
          <button className="btn btn-secondary"
            disabled={!isDirty || !isValid}
            onClick={()=>{
              const addCol={
                "physicalName":colPhysicalName,
                "logicalName":colLogicalName,
                "type":colType,
                "required":$('#'+editAPI.physical_name+'-required').prop('checked'),
                "delete":false,
                "editing":false,
                "edited":true
              }
              editAPI.outinfo[0].column.push(addCol)
              setEditAPI({...editAPI})
              formReset()
              if(reflectLock){
                $('#'+editAPI.physical_name+'-error').text("")
              }
            }}
          >
            追加する
          </button>
        </div>
      )
    } else {
      return(
        <div className="btn-right">
          <button className="btn btn-secondary"
            disabled={
              Boolean(errors.colLogicalName)
              || Boolean(errors.colPhysicalName)
              || Boolean(errors.colType)
            }
            onClick={()=>{
              const addCol={
                "physicalName":colPhysicalName,
                "logicalName":colLogicalName,
                "type":colType,
                "required":$('#'+editAPI.physical_name+'-required').prop('checked'),
                "delete":false,
                "editing":false,
                "edited":true
              }
              editAPI.outinfo[0].column[Number(editIndex)] = addCol
              setEditAPI({...editAPI})
              setEditIndex("")
              formReset()
            }}
          >
            更新する
          </button>
        </div>
      )
    }
  }

  // 削除と復元のボタン切り替え
  const deleteOrUndo = (item:Defs.EditColumn) => {
    if(!item.delete) {
      return(
        <i className="fa fa-times-circle" aria-hidden="true"
           onClick={()=>{
            editCancel(item)
            item.delete=true
            setEditAPI({...editAPI})
           }}
        ></i>
      )
    } else {
      return(
        <i className="fa fa-reply" aria-hidden="true"
           onClick={()=>{
            item.delete=false
            formReset()
            if(reflectLock){
              $('#'+editAPI.physical_name+'-error').text("")
            }
            setEditAPI({...editAPI})
           }}
        ></i>
      )
    }
  }

  // 編集中断処理
  const editCancel = (item:Defs.EditColumn) => {
    formReset()
    setEditIndex("")
    item.editing=false
  }

  // フォームの初期化
  const formReset = () => {
    $('#'+editAPI.physical_name+'-required').prop('checked',false);
    setColLogicalName("")
    setColPhysicalName("")
    setColType("")
    resetField('colLogicalName')
    resetField('colPhysicalName')
    resetField('colType')
  }

  // put api(add col or delete col)
  function putChangeAPI(){
        (async () => {
          let apiList = JSON.parse(JSON.stringify(editAPI))
          apiList.outinfo[0].column.map((item:any, index:number)=>{
            if(item.delete){
              apiList.outinfo[0].column[index] = {}
            } else {
              delete item["delete"]
              delete item["editing"]
              delete item["edited"]
            }
          })
          apiList.outinfo[0].column = apiList.outinfo[0].column.filter((tmp:any) => Object.keys(tmp).length)
          commonAjax
            .axios({swalFire: false, loading: true})
            .put(`/api/api/${editAPI.physical_name}`, apiList.outinfo[0].column)
            .then((res) => {
              const list = [];
              list.push(res.data.meta);
              console.log(list)
              setList(list)
              console.log(List)
              apiList.outinfo[0].column.map((col:Defs.EditColumn)=>{
                col["delete"] = false;
                col["editing"] = false;
                col["edited"] = false;
              }
              )
              setEditAPI(apiList)
              setUpdated(true)
            });
        })();
  }

  // モーダルが閉じられた場合、表示するカラムをもとに戻す
  $("#"+props.val.physical_name+"-dtl-modal").on("hidden.bs.modal",()=>{
    if(!updated){
      setEditAPI(JSON.parse(JSON.stringify(origin)))
      setEditIndex("")
      setReflectLock(true)
      formReset()
      $('#'+editAPI.physical_name+'-error').text("")
      $("#"+props.val.physical_name+"-dtl-modal").off("hidden.bs.modal")
    }else{
      setUpdated(false)
      window.location.reload()
    }
  })

  return (
    <>
    {/* Add API col Modal */}
    {/* Content Header (Page header) */}
    <div className="modal fade" id={editAPI.physical_name+"-dtl-modal"}>
      <div className="modal-dialog api-dtl-modal-width">
        <div className="modal-content">
          <div className="modal-header">
            <h4 className="modal-title">サンプルデータ挿入 / API連携項目追加</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 */}
            <div className="name-disp-area">
              <div className="api-name">
                <div className="dtl-content-width">API 論理名</div>
                <div className="dtl-modal-font-color">{editAPI.logical_name}</div>
              </div>
              <div className="api-name">
                <div className="dtl-content-width">API 物理名</div>
                <div className="dtl-modal-font-color">{editAPI.physical_name}</div>
              </div>
              <div className="btn-right">
                <button className="btn btn-secondary"
                onClick={()=>{
                  $("#"+editAPI.physical_name+"-dtl-modal").modal("hide").on("hidden.bs.modal",()=>{
                    setTimeout(()=>$('#'+editAPI.physical_name.replaceAll('_', '')+"sample-data").modal("show"))
                    $("#"+editAPI.physical_name+"-dtl-modal").off("hidden.bs.modal")
                  })
                }}>
                  サンプルデータ挿入
                </button>
              </div>
            </div>
            {Spacer({"size":10})}
            <div className="dividing-line"/>
            {/* API col display area */}
            {Spacer({"size":10})}
            <div className="col-disp-title">すでに連携されている連携項目</div>
            {Spacer({"size":20})}
            {editAPI.outinfo.map((val: Defs.EditTableInfo) => {
              const res: any[] = []
              val.column.map((item: Defs.EditColumn, index:number) => {
                res.push(
                  <div className={`add-col-grid col-disp-grid ${item.delete?"delete-col":item.editing?"editing-col":item.edited&&"edited-col"}`}>
                    <div className="add-item">
                      <div className="add-input-form-title"/>
                      <p className="adjust-indent-base adjust-indent-check">{item.required&&"✔"}</p>
                    </div>
                    <div className="add-item">
                      <div className="add-input-form-title"/>
                      <p className="adjust-indent-base adjust-indent-form">{item.logicalName}</p>
                    </div>
                    <div className="add-item">
                      <div className="add-input-form-title"/>
                      <p className="adjust-indent-base adjust-indent-form">{item.physicalName}</p>
                    </div>
                    <div className="add-item">
                      <div className="add-input-form-title"/>
                      <p className="adjust-indent-base adjust-indent-type">{item.type}</p>
                    </div>
                    <div className="btn-left">
                      <i className={`fa fa-solid fa-pen ${item.delete&&"not-applicable"}`}
                         aria-hidden="true"
                         onClick={()=>{
                          if(item.editing){
                            editCancel(item)
                          }else{
                            if(editIndex!==""){
                              editAPI.outinfo[0].column[Number(editIndex)].editing=false
                            }
                            formReset()
                            setColLogicalName(item.logicalName)
                            setColPhysicalName(item.physicalName)
                            setColType(item.type)
                            $('#'+editAPI.physical_name+'-required').prop('checked',item.required);
                            item.editing=true
                            setEditIndex(String(index))
                          }
                         }}
                      ></i>
                      {Spacer({"size":50,horizontal:true})}
                      {deleteOrUndo(item)}
                    </div>
                  </div>
                )
              })
              return res
            })}
            {Spacer({"size":30})}
            <div className="dividing-line"/>
            {/* Add col input area */}
            {Spacer({"size":30})}
            <div className="add-col-grid">
              <div className="add-item">
                <div className="add-input-form-title">必須</div>
                <input type="checkbox" id={editAPI.physical_name+"-required"} className="form-check-input" name={editAPI.physical_name+"-required"} value="1"/>
                <label className="form-check-label check-only input-data-check" htmlFor={editAPI.physical_name+"-required"}></label>
              </div>
              <div className="add-item">
                <div className="add-input-form-title">論理名</div>
                <input
                  type="text"
                  id={editAPI.physical_name+"-add-col-l-name"}
                  className="form-control add-input-form"
                  value={colLogicalName}
                  {...colLogicalNameField}
                  onChange={(e) => {
                    colLogicalNameField.onChange(e);
                    handleChange(e);
                  }}
                />
              </div>
              <div className="add-item">
                <div className="add-input-form-title">物理名</div>
                <input
                  type="text"
                  id={editAPI.physical_name+"-add-col-p-name"}
                  className="form-control add-input-form"
                  value={colPhysicalName}
                  {...colPhysicalNameField}
                  onChange={(e) => {
                    colPhysicalNameField.onChange(e);
                    handleChange(e);
                  }}
                />
              </div>
              <div className="add-item">
                <div className="add-input-form-title">データ型</div>
                <select
                  id={editAPI.physical_name+"-category-sel"}
                  className="form-control input-data-type"
                  required
                  value={colType}
                  {...colTypeField}
                  onChange={(e) => {
                    colTypeField.onChange(e);
                    selectChange(e);
                  }}
                >
                  <option hidden value="">選択する</option>
                  {gender.map((item, i) => (
                    <option
                      value={item.key}
                      key={item.key}
                    >
                      {item.label}
                    </option>
                  ))}
                </select>
              </div>
              {addOrUpd()}
            </div>
            {Spacer({"size":25})}
            <div className="error-msg-area">
              {errors.colLogicalName?.message && (
                  <div className="text-danger">{errors.colLogicalName.message}</div>
              )}
              {errors.colPhysicalName?.message && (
                  <div className="text-danger">{errors.colPhysicalName.message}</div>
              )}
              {errors.colType?.message && (
                  <div className="text-danger">{errors.colType.message}</div>
              )}
              <div className="text-danger" id={editAPI.physical_name+'-error'}></div>
            </div>
            <div className="reflect-col-btn">
              <button className="btn btn-primary"
                      data-toggle="modal"
                      data-backdrop="static" 
                      onClick={()=>{
                        let flg = true
                        editAPI.outinfo[0].column.map((item:Defs.EditColumn)=>{
                          if(!item.delete){
                            flg = false
                            setReflectLock(false)
                          }
                        })
                        if(!flg){
                          putChangeAPI()
                          if (updated) {
                            $("#"+editAPI.physical_name+"-dtl-modal").modal("hide").on("hidden.bs.modal",()=>{
                              setTimeout(()=>$("#"+editAPI.physical_name+"MessageModal").modal({backdrop: "static"}).modal("show"))
                              $("#"+editAPI.physical_name+"-dtl-modal").off("hidden.bs.modal")
                            })
                          }
                        }else{
                          $('#'+editAPI.physical_name+'-error').text("連携項目は1つ以上必要です")
                        }
                      }}>
                反映する
              </button>
            </div>
            {Spacer({"size":30})}
          </div>
        </div>
        {/* <!-- /.modal-content --> */}
      </div>
      {/* <!-- /.modal-dialog --> */}
    </div>
    {/* <!-- /.modal --> */}
  </>
  )
}

export default NewAPIDtlModal;
kirin-ri commented 1 year ago
import React, { ChangeEvent, useState } from "react";
import { useForm } from 'react-hook-form';
import { Spacer } from "../spacer";
import { commonAjax } from '../../../components/commonAjax';
import * as Defs from './apiDefs';

const NewAPIDtlModal = (props: { val: Defs.Api }) => {
  // プルダウンの選択肢
  const gender = [
    { key: 'integer', label: 'integer' },
    { key: 'long', label: 'long' },
    { key: 'float', label: 'float' },
    { key: 'double', label: 'double' },
    { key: 'string', label: 'string' },
    { key: 'byte', label: 'byte' },
    { key: 'binary', label: 'binary' },
    { key: 'boolean', label: 'boolean(true,false)' },
    { key: 'date', label: 'date(yyyy-mm-dd)' },
    { key: 'dateTime', label: 'dateTime(yyyy-mm-ddTHH:MM:SSZ)' },
  ];

  // api情報をコピー
  const tmp = JSON.parse(JSON.stringify(props.val))
  // apiの各項目に削除、編集中、編集済のフラグを付与
  tmp.outinfo[0].column.map((col:Defs.EditColumn)=>{
    col["delete"] = false;
    col["editing"] = false;
    col["edited"] = false;
  })

  // useState
  const origin = JSON.parse(JSON.stringify(tmp))
  const [editAPI, setEditAPI] = useState<Defs.EditApi>(tmp);
  const [editIndex, setEditIndex] = useState<string>("")
  const [reflectLock, setReflectLock] = useState<boolean>(true)
  const [updated, setUpdated] = useState<boolean>(false)
  // input form
  const [colPhysicalName, setColPhysicalName] = useState<string>("")
  const [colLogicalName, setColLogicalName] = useState<string>("")
  const [colType, setColType] = useState<string>("")
  //const [List, setList] = useState<any>();

  // react hook form
  const {
    register,
    resetField,
    formState: { isDirty, isValid, errors },
  } = useForm({
    defaultValues: { colLogicalName: '', colPhysicalName:'', colType:''},
    mode: 'onChange',
    criteriaMode: 'all',
  });
  const colLogicalNameField = register('colLogicalName', {
    required: {
      value: true,
      message: '論理名は入力が必須の項目です',
    },
  });
  const colPhysicalNameField = register('colPhysicalName', {
    required: {
      value: true,
      message: '物理名は入力が必須の項目です',
    },
    pattern: {
      value: /^[0-9a-zA-Z_]+$/,
      message: '物理名には英数字およびアンダースコアのみ使用可能です',
    }
  });
  const colTypeField = register('colType', {
    required: {
      value: true,
      message: 'データ型は入力が必須の項目です',
    },
  });

  // 物理名、論理名が入力された際に値を設定する
  const handleChange = (e: ChangeEvent<HTMLInputElement>) => {
    switch (e.target.name) {
      case 'colLogicalName':
        setColLogicalName(e.target.value);
        break;
      case 'colPhysicalName':
        setColPhysicalName(e.target.value);
        break;
    }
  };
  // データ型が入力された際に値を設定する
  const selectChange = (e: ChangeEvent<HTMLSelectElement>) => {
        setColType(e.target.value);
  };

  // 更新と追加のボタン切り替え
  const addOrUpd = ()=>{
    if(editIndex===""){
      return(
        <div className="btn-right">
          <button className="btn btn-secondary"
            disabled={!isDirty || !isValid}
            onClick={()=>{
              const addCol={
                "physicalName":colPhysicalName,
                "logicalName":colLogicalName,
                "type":colType,
                "required":$('#'+editAPI.physical_name+'-required').prop('checked'),
                "delete":false,
                "editing":false,
                "edited":true
              }
              editAPI.outinfo[0].column.push(addCol)
              setEditAPI({...editAPI})
              formReset()
              if(reflectLock){
                $('#'+editAPI.physical_name+'-error').text("")
              }
            }}
          >
            追加する
          </button>
        </div>
      )
    } else {
      return(
        <div className="btn-right">
          <button className="btn btn-secondary"
            disabled={
              Boolean(errors.colLogicalName)
              || Boolean(errors.colPhysicalName)
              || Boolean(errors.colType)
            }
            onClick={()=>{
              const addCol={
                "physicalName":colPhysicalName,
                "logicalName":colLogicalName,
                "type":colType,
                "required":$('#'+editAPI.physical_name+'-required').prop('checked'),
                "delete":false,
                "editing":false,
                "edited":true
              }
              editAPI.outinfo[0].column[Number(editIndex)] = addCol
              setEditAPI({...editAPI})
              setEditIndex("")
              formReset()
            }}
          >
            更新する
          </button>
        </div>
      )
    }
  }

  // 削除と復元のボタン切り替え
  const deleteOrUndo = (item:Defs.EditColumn) => {
    if(!item.delete) {
      return(
        <i className="fa fa-times-circle" aria-hidden="true"
           onClick={()=>{
            editCancel(item)
            item.delete=true
            setEditAPI({...editAPI})
           }}
        ></i>
      )
    } else {
      return(
        <i className="fa fa-reply" aria-hidden="true"
           onClick={()=>{
            item.delete=false
            formReset()
            if(reflectLock){
              $('#'+editAPI.physical_name+'-error').text("")
            }
            setEditAPI({...editAPI})
           }}
        ></i>
      )
    }
  }

  // 編集中断処理
  const editCancel = (item:Defs.EditColumn) => {
    formReset()
    setEditIndex("")
    item.editing=false
  }

  // フォームの初期化
  const formReset = () => {
    $('#'+editAPI.physical_name+'-required').prop('checked',false);
    setColLogicalName("")
    setColPhysicalName("")
    setColType("")
    resetField('colLogicalName')
    resetField('colPhysicalName')
    resetField('colType')
  }

  // put api(add col or delete col)
  function putChangeAPI(){
        (async () => {
          let apiList = JSON.parse(JSON.stringify(editAPI))
          apiList.outinfo[0].column.map((item:any, index:number)=>{
            if(item.delete){
              apiList.outinfo[0].column[index] = {}
            } else {
              delete item["delete"]
              delete item["editing"]
              delete item["edited"]
            }
          })
          apiList.outinfo[0].column = apiList.outinfo[0].column.filter((tmp:any) => Object.keys(tmp).length)
          commonAjax
            .axios({swalFire: false, loading: true})
            .put(`/api/api/${editAPI.physical_name}`, apiList.outinfo[0].column)
            .then((res) => {
              // const list = [];
              // list.push(...res.data.meta);
              // setList(list)
              apiList.outinfo[0].column.map((col:Defs.EditColumn)=>{
                col["delete"] = false;
                col["editing"] = false;
                col["edited"] = false;
              })
              setEditAPI(apiList)
              setUpdated(true)
            });
        })();
  }

  // モーダルが閉じられた場合、表示するカラムをもとに戻す
  $("#"+props.val.physical_name+"-dtl-modal").on("hidden.bs.modal",()=>{
    if(!updated){
      setEditAPI(JSON.parse(JSON.stringify(origin)))
      setEditIndex("")
      setReflectLock(true)
      formReset()
      $('#'+editAPI.physical_name+'-error').text("")
      $("#"+props.val.physical_name+"-dtl-modal").off("hidden.bs.modal")
    }else{
      setUpdated(false)
      window.location.reload()
    }
  })

  return (
    <>
    {/* Add API col Modal */}
    {/* Content Header (Page header) */}
    <div className="modal fade" id={editAPI.physical_name+"-dtl-modal"}>
      <div className="modal-dialog api-dtl-modal-width">
        <div className="modal-content">
          <div className="modal-header">
            <h4 className="modal-title">サンプルデータ挿入 / API連携項目追加</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 */}
            <div className="name-disp-area">
              <div className="api-name">
                <div className="dtl-content-width">API 論理名</div>
                <div className="dtl-modal-font-color">{editAPI.logical_name}</div>
              </div>
              <div className="api-name">
                <div className="dtl-content-width">API 物理名</div>
                <div className="dtl-modal-font-color">{editAPI.physical_name}</div>
              </div>
              <div className="btn-right">
                <button className="btn btn-secondary"
                onClick={()=>{
                  $("#"+editAPI.physical_name+"-dtl-modal").modal("hide").on("hidden.bs.modal",()=>{
                    setTimeout(()=>$('#'+editAPI.physical_name.replaceAll('_', '')+"sample-data").modal("show"))
                    $("#"+editAPI.physical_name+"-dtl-modal").off("hidden.bs.modal")
                  })
                }}>
                  サンプルデータ挿入
                </button>
              </div>
            </div>
            {Spacer({"size":10})}
            <div className="dividing-line"/>
            {/* API col display area */}
            {Spacer({"size":10})}
            <div className="col-disp-title">すでに連携されている連携項目</div>
            {Spacer({"size":20})}
            {editAPI.outinfo.map((val: Defs.EditTableInfo) => {
              const res: any[] = []
              val.column.map((item: Defs.EditColumn, index:number) => {
                res.push(
                  <div className={`add-col-grid col-disp-grid ${item.delete?"delete-col":item.editing?"editing-col":item.edited&&"edited-col"}`}>
                    <div className="add-item">
                      <div className="add-input-form-title"/>
                      <p className="adjust-indent-base adjust-indent-check">{item.required&&"✔"}</p>
                    </div>
                    <div className="add-item">
                      <div className="add-input-form-title"/>
                      <p className="adjust-indent-base adjust-indent-form">{item.logicalName}</p>
                    </div>
                    <div className="add-item">
                      <div className="add-input-form-title"/>
                      <p className="adjust-indent-base adjust-indent-form">{item.physicalName}</p>
                    </div>
                    <div className="add-item">
                      <div className="add-input-form-title"/>
                      <p className="adjust-indent-base adjust-indent-type">{item.type}</p>
                    </div>
                    <div className="btn-left">
                      <i className={`fa fa-solid fa-pen ${item.delete&&"not-applicable"}`}
                         aria-hidden="true"
                         onClick={()=>{
                          if(item.editing){
                            editCancel(item)
                          }else{
                            if(editIndex!==""){
                              editAPI.outinfo[0].column[Number(editIndex)].editing=false
                            }
                            formReset()
                            setColLogicalName(item.logicalName)
                            setColPhysicalName(item.physicalName)
                            setColType(item.type)
                            $('#'+editAPI.physical_name+'-required').prop('checked',item.required);
                            item.editing=true
                            setEditIndex(String(index))
                          }
                         }}
                      ></i>
                      {Spacer({"size":50,horizontal:true})}
                      {deleteOrUndo(item)}
                    </div>
                  </div>
                )
              })
              return res
            })}
            {Spacer({"size":30})}
            <div className="dividing-line"/>
            {/* Add col input area */}
            {Spacer({"size":30})}
            <div className="add-col-grid">
              <div className="add-item">
                <div className="add-input-form-title">必須</div>
                <input type="checkbox" id={editAPI.physical_name+"-required"} className="form-check-input" name={editAPI.physical_name+"-required"} value="1"/>
                <label className="form-check-label check-only input-data-check" htmlFor={editAPI.physical_name+"-required"}></label>
              </div>
              <div className="add-item">
                <div className="add-input-form-title">論理名</div>
                <input
                  type="text"
                  id={editAPI.physical_name+"-add-col-l-name"}
                  className="form-control add-input-form"
                  value={colLogicalName}
                  {...colLogicalNameField}
                  onChange={(e) => {
                    colLogicalNameField.onChange(e);
                    handleChange(e);
                  }}
                />
              </div>
              <div className="add-item">
                <div className="add-input-form-title">物理名</div>
                <input
                  type="text"
                  id={editAPI.physical_name+"-add-col-p-name"}
                  className="form-control add-input-form"
                  value={colPhysicalName}
                  {...colPhysicalNameField}
                  onChange={(e) => {
                    colPhysicalNameField.onChange(e);
                    handleChange(e);
                  }}
                />
              </div>
              <div className="add-item">
                <div className="add-input-form-title">データ型</div>
                <select
                  id={editAPI.physical_name+"-category-sel"}
                  className="form-control input-data-type"
                  required
                  value={colType}
                  {...colTypeField}
                  onChange={(e) => {
                    colTypeField.onChange(e);
                    selectChange(e);
                  }}
                >
                  <option hidden value="">選択する</option>
                  {gender.map((item, i) => (
                    <option
                      value={item.key}
                      key={item.key}
                    >
                      {item.label}
                    </option>
                  ))}
                </select>
              </div>
              {addOrUpd()}
            </div>
            {Spacer({"size":25})}
            <div className="error-msg-area">
              {errors.colLogicalName?.message && (
                  <div className="text-danger">{errors.colLogicalName.message}</div>
              )}
              {errors.colPhysicalName?.message && (
                  <div className="text-danger">{errors.colPhysicalName.message}</div>
              )}
              {errors.colType?.message && (
                  <div className="text-danger">{errors.colType.message}</div>
              )}
              <div className="text-danger" id={editAPI.physical_name+'-error'}></div>
            </div>
            <div className="reflect-col-btn">
              <button className="btn btn-primary"
                      onClick={()=>{
                        let flg = true
                        editAPI.outinfo[0].column.map((item:Defs.EditColumn)=>{
                          if(!item.delete){
                            flg = false
                            setReflectLock(false)
                          }
                        })
                        if(!flg){
                          putChangeAPI()
                          $("#"+editAPI.physical_name+"-dtl-modal").modal("hide").on("hidden.bs.modal",()=>{
                            setTimeout(()=>$("#"+editAPI.physical_name+"MessageModal").modal({backdrop: "static"}).modal("show"))
                            $("#"+editAPI.physical_name+"-dtl-modal").off("hidden.bs.modal")
                          })
                        }else{
                          $('#'+editAPI.physical_name+'-error').text("連携項目は1つ以上必要です")
                        }
                      }}>
                反映する
              </button>
            </div>
            {Spacer({"size":30})}
          </div>
        </div>
        {/* <!-- /.modal-content --> */}
      </div>
      {/* <!-- /.modal-dialog --> */}
    </div>
    {/* <!-- /.modal --> */}
  </>
  )
}

export default NewAPIDtlModal;
kirin-ri commented 1 year ago
{"values":[{"logicalName":"販売計画誤差率:年次","logicalName":"基準在庫(在庫数・金額):年次"}]}
kirin-ri commented 1 year ago
res = {"values":[{"logicalName":"販売計画誤差率:年次"},{"logicalName":"基準在庫(在庫数・金額):年次"}]}
kirin-ri commented 1 year ago
        let resData = res.data; // Assuming this is your response object
        resData.values.forEach((value: {logicalName: string}) => {
          apiList.outinfo[0].column.push({logicalName: value.logicalName, delete: false, editing: false, edited: false})
        })
kirin-ri commented 1 year ago

[{…}, {…}]

kirin-ri commented 1 year ago

プロダクトメトリクス 収益

プロダクトによって得られる収益

市場占有率

プロダクトが市場を占める相対的な割合

顧客満⾜度

プロダクトによって顧客の課題が解決された状態、もしくは、あるべき理想の状態、その満足度

顧客使⽤指標

プロダクトに対する、熱心さ・意欲・モチベーション・使い倒し度合い

利用/復帰顧客数

プロダクトの新規顧客や機能を新たに使い始めた、復帰した顧客数

タスク成功率

プロダクトの機能の達成度合いを示すもの。効率性、有効性、エラー率など

プロセスメトリクス デプロイの頻度

組織による正常な本番環境へのリリースの頻度

リードタイム

コミットから本番環境稼働までの所要時間

変更障害率

デプロイが原因で本番環境で障害が発生する割合

サービス復元時間

組織が本番環境での障害から回復するのにかかる時間

手戻り率

プロセスの前段階に戻ったタスクの割合

プルリク数

タスクのプルリクエスト数

従業員満足度

チームメンバーの仕事に対する満足度

kirin-ri commented 1 year ago
snowflakeのデータベースで、カラムrelated_metricsに以下のjsonが格納しています。

[
  {
    "column": [
      {
        "logicalName": "一次部品(部品番号)",
        "physicalName": "PARTS_NO",
        "type": "文字列"
      },
      {
        "logicalName": "基準日",
        "physicalName": "REF_DATE",
        "type": "日付"
      },
      {
        "logicalName": "部品在庫欠品:欠品数",
        "physicalName": "OUT_OF_STOCK_QTY",
        "type": "数値"
      },
      {
        "logicalName": "部品在庫欠品:欠品率",
        "physicalName": "OUT_OF_STOCK_RATE",
        "type": "数値"
      },
      {
        "logicalName": "実行日",
        "physicalName": "EXEC_DATE",
        "type": "日付"
      },
      {
        "logicalName": "ユニークキー",
        "physicalName": "UID",
        "type": "文字列"
      }
    ]
  }
]
kirin-ri commented 1 year ago
import json
from tools.snowflakeAccessor import SnowflakeAccessor

def getApiList(id: str):
    sf = SnowflakeAccessor()

    out = []

    # メタデータ取得クエリ
    query = """
        SELECT
            API_PHYSICAL_NAME,
            API_LOGICAL_NAME,
            PROVIDE,
            API_LINKAGE_ITEMS,
            TAGS
        FROM
            API_META_INFO
        ORDER BY
            API_PHYSICAL_NAME
        """
    try:
        result = sf.execute(query)
        for (physical_name, logical_name, provide, items, tags) in result:
            outinfo = []
            column = []
            related_metrics = []
            try:
                for item in json.loads(items):
                    outinfo.append(
                        {
                            "physicalName": item["PHYSICAL_NAME"],
                            "logicalName": item["LOGICAL_NAME"],
                            "type": item["TYPE"],
                            "required": item["REQUIRED"],
                        }
                    )
            except TypeError:
                outinfo.append(None)
            column.append({"column": outinfo})
            if tags == "[]" or not tags:
                tags = '["その他"]'
            #dami
            related_metrics.append()
            out.append(
                {
                    "related_metrics" : related_metrics,
                    "physical_name": physical_name,
                    "logical_name": logical_name,
                    "provide": provide,
                    "outinfo": column,
                    "tags": json.loads(tags)
                }
            )
        # print({"api": out})
    finally:
        sf.close()
    return {"api": out}
kirin-ri commented 1 year ago
現在の状況はベタ書きです
販売計画誤差率:年次と基準在庫(在庫数・金額):年次の文字列は、test=['販売計画誤差率:年次', 基準在庫(在庫数・金額):年次の文字列']になってます。

下の表示は配列数がある度<div></div>を生成するように修正してください。

            <div>
              <div className="text-center">
                <div>
                -<a href="/#/scm-metrics-edit/販売計画誤差率:年次" target="_blank">販売計画誤差率:年次</a>
                </div>
                <div>
                -<a href="/#/scm-metrics-edit/基準在庫(在庫数・金額):年次" target="_blank">基準在庫(在庫数・金額):年次 </a>
                </div>
              </div>
            </div>
kirin-ri commented 1 year ago
<div>
  <div className="text-center">
    {test.map((item, index) => (
      <div key={index}>
        -<a href={"/#/scm-metrics-edit/" + item} target="_blank">{item}</a>
      </div>
    ))}
  </div>
</div>
kirin-ri commented 1 year ago

キャプチャ

kirin-ri commented 1 year ago
import React, { ChangeEvent, useEffect, useState } from "react";
import { useForm } from 'react-hook-form';
import { Spacer } from "../spacer";
import { commonAjax } from '../../../components/commonAjax';
import * as Defs from './apiDefs';

// Message Modal
const ApiUpdateResultModal = (props: { val: Defs.Api}) => {
  const tmp = JSON.parse(JSON.stringify(props.val))
  const [editAPI, setEditAPI] = useState<Defs.Api>(tmp);

  return (
    <>
    {/* Content Header (Page header) */}
    {/* <div className="modal fade" id={"MessageModal"}> */}
    <div className="modal fade" data-backdrop="static" id={editAPI.physical_name+"MessageModal"}>
      <div className="modal-dialog modal-xl">
        <div className="modal-content">
          <div className="modal-header">
            <h4 className="modal-title">サンプルデータ挿入 / API連携項目追加</h4>
            <button type="button" className="close" data-dismiss="modal" aria-label="Close">
              <span aria-hidden="true">&times;</span>
            </button>
          </div>
          <div className="modal-body">
          <div className="name-disp-area">
              <div className="api-name">
                <div className="dtl-content-width">API 論理名</div>
                <div className="dtl-modal-font-color">{editAPI.logical_name}</div>
              </div>
              <div className="api-name">
                <div className="dtl-content-width">API 物理名</div>
                <div className="dtl-modal-font-color">{editAPI.physical_name}</div>
              </div>
          </div>
          </div>
          <div className="modal-body">
            <div className="dividing-line"/>
          </div>
          <div className="modal-body">
            <div className="text-center">
              <div className="text-center">
                <div className="text-center">
                  <div>API項目が更新されました。</div>
                  <div>再度マッピングを行う必要があります。</div>
                </div>
              </div>
            </div>
            {Spacer({"size":50})}
            <div>
              <div className="text-center">
              {editAPI.related_metrics.map((item, index) => (
                  <div key={index}>
                    <div style={{margin:"0 auto",textAlign:"left"}}>
                    -<a href={"/#/scm-metrics-edit/" + item} target="_blank">{item}</a>
                    </div>
                  </div>
                ))}
              </div>
            </div>
            {Spacer({"size":50})}
            <div className="text-center">
              <div className="centering-btn">
                <div style={{color : "red"}}>
                  ※マッピングが完了するまで、このページを閉じないでください。
                </div>
                {Spacer({"size":25})}
                <button className="btn btn-primary" data-dismiss="modal">
                  OK
                </button>
              </div>
            </div>
            {Spacer({"size":25})}
          </div>
        </div>
        {/* <!-- /.modal-content --> */}
      </div>
      {/* <!-- /.modal-dialog --> */}
    </div>
    {/* <!-- /.modal --> */}
    {/* /.content */}
  </>
  )
}

export default ApiUpdateResultModal;
kirin-ri commented 1 year ago

再度マッピングを行う必要があります。 -基準在庫(在庫数・金額):年次 -販売計画誤差率:年次

kirin-ri commented 1 year ago
                  <div key={index}>
                    <div style={{margin:"0 auto",textAlign:"left"}}>
                    -<a href={"/#/scm-metrics-edit/" + item} target="_blank">{item}</a>
                    </div>
                  </div>
kirin-ri commented 1 year ago
<span style={{ display: "inline-block" }}>
  <span style={{ whiteSpace: "nowrap" }}>-</span>
  <span style={{ visibility: "hidden" }}>&nbsp;</span>
</span>
kirin-ri commented 1 year ago

<div key={index} style={{ display: "flex", justifyContent: "center" }}> <div style={{ textAlign: "left" }}> <span style={{ marginRight: "5px" }}>- <a href={"/#/scm-metrics-edit/" + item} target="_blank">{item}

kirin-ri commented 1 year ago
<div key={index} style={{ display: "flex", justifyContent: "center" }}>
  <div style={{ textAlign: "left" }}>
    <span style={{ marginRight: "5px" }}>-</span>
    <a href={"/#/scm-metrics-edit/" + item} target="_blank">{item}</a>
  </div>
</div>
kirin-ri commented 1 year ago
            <div>
              <div className="text-center">
                {editAPI.related_metrics.map((item, index) => (
                  <div key={index} style={{ display: "flex", justifyContent: "center" }}>
                  <div style={{ textAlign: "left" }}>
                    <span style={{ marginRight: "5px" }}>-</span>
                    <a href={"/#/scm-metrics-edit/" + item} target="_blank">{item}</a>
                  </div>
                  </div>
                ))}
              </div>
            </div>
kirin-ri commented 1 year ago
<div>
  <div className="text-center">
    {editAPI.related_metrics.map((item, index) => (
      <div key={index} style={{ display: "flex", justifyContent: "center" }}>
        <div style={{ textAlign: "left", margin: "0 auto" }}>
          <span style={{ marginRight: "5px" }}>-</span>
          <a href={"/#/scm-metrics-edit/" + item} target="_blank">{item}</a>
        </div>
      </div>
    ))}
  </div>
</div>
kirin-ri commented 1 year ago
<div>
  <div className="text-center">
    {editAPI.related_metrics.map((item, index) => (
      <div key={index} style={{ display: "flex", justifyContent: "center" }}>
        <div style={{ textAlign: "left", margin: "0 auto", display: "flex", alignItems: "center" }}>
          <span style={{ marginRight: "5px", alignSelf: "flex-start" }}>-</span>
          <a href={"/#/scm-metrics-edit/" + item} target="_blank">{item}</a>
        </div>
      </div>
    ))}
  </div>
</div>
kirin-ri commented 1 year ago
            <div className="text-center">
              <div className="text-center">
                <div className="text-center">
                  <div>API項目が更新されました。</div>
                  <div>再度マッピングを行う必要があります。</div>
                </div>
              </div>
            </div>
kirin-ri commented 1 year ago
<div className="text-center">
  <div className="text-center">
    <div className="text-center">
      <div style={{ display: "flex", justifyContent: "center", flexDirection: "column" }}>
        <div style={{ textAlign: "center" }}>API項目が更新されました。</div>
        <div style={{ textAlign: "center" }}>再度マッピングを行う必要があります。</div>
      </div>
    </div>
  </div>
</div>
kirin-ri commented 1 year ago
            <div className="text-center">
              {editAPI.related_metrics.map((item, index) => (
                <div key={index}>
                  <div style={{ textAlign: "center", margin: "0 auto" }}>
                    -<a href={"/#/scm-metrics-edit/" + item} target="_blank">{item}</a>
                  </div>
                </div>
              ))}
            </div>
kirin-ri commented 1 year ago
{editAPI.related_metrics.map((item, index) => (
- {item}

))}

kirin-ri commented 1 year ago
<div className="text-center">
  {editAPI.related_metrics.map((item, index) => (
    <div key={index} style={{ textAlign: "center" }}>
      -<a
        href={"/#/scm-metrics-edit/" + item}
        target="_blank"
        style={{ display: "inline-block", textAlign: "left" }}
      >
        {item}
      </a>
    </div>
  ))}
</div>
kirin-ri commented 1 year ago
import React, { ChangeEvent, useEffect, useState } from "react";
import { useForm } from 'react-hook-form';
import { Spacer } from "../spacer";
import { commonAjax } from '../../../components/commonAjax';
import * as Defs from './apiDefs';

// Message Modal
const ApiUpdateResultModal = (props: { val: Defs.Api}) => {
  const tmp = JSON.parse(JSON.stringify(props.val))
  const [editAPI, setEditAPI] = useState<Defs.Api>(tmp);

  return (
    <>
    {/* Content Header (Page header) */}
    {/* <div className="modal fade" id={"MessageModal"}> */}
    <div className="modal fade" data-backdrop="static" id={editAPI.physical_name+"MessageModal"}>
      <div className="modal-dialog modal-xl">
        <div className="modal-content">
          <div className="modal-header">
            <h4 className="modal-title">サンプルデータ挿入 / API連携項目追加</h4>
            <button type="button" className="close" data-dismiss="modal" aria-label="Close">
              <span aria-hidden="true">&times;</span>
            </button>
          </div>
          <div className="modal-body">
          <div className="name-disp-area">
              <div className="api-name">
                <div className="dtl-content-width">API 論理名</div>
                <div className="dtl-modal-font-color">{editAPI.logical_name}</div>
              </div>
              <div className="api-name">
                <div className="dtl-content-width">API 物理名</div>
                <div className="dtl-modal-font-color">{editAPI.physical_name}</div>
              </div>
          </div>
          </div>
          <div className="modal-body">
            <div className="dividing-line"/>
          </div>
          <div className="modal-body">
            <div className="text-center">
              <div>API項目が更新されました。</div>
              <div>再度マッピングを行う必要があります。</div>
            </div>
          </div>
          <div className="modal-body">
            {Spacer({"size":50})}
            <div className="text-center">
              {editAPI.related_metrics.map((item, index) => (
                <div key={index} style={{textAlign:"center"}}>
                    -<a href={"/#/scm-metrics-edit/" + item} target="_blank" style={{display:"inline-block",textAlign:"left"}}>{item}</a>
                </div>
              ))}
            </div>
            {Spacer({"size":50})}
            <div className="text-center">
              <div className="centering-btn">
                <div style={{color : "red"}}>
                  ※マッピングが完了するまで、このページを閉じないでください。
                </div>
                {Spacer({"size":25})}
                <button className="btn btn-primary" data-dismiss="modal">
                  OK
                </button>
              </div>
            </div>
            {Spacer({"size":25})}
          </div>
        </div>
        {/* <!-- /.modal-content --> */}
      </div>
      {/* <!-- /.modal-dialog --> */}
    </div>
    {/* <!-- /.modal --> */}
    {/* /.content */}
  </>
  )
}

export default ApiUpdateResultModal;