summary history files

frontend/src/components/SecretsCreateGuided.vue
<!-- SecretsCreateGuided.vue -->
<script lang="ts">
import { defineComponent, ref, computed } from 'vue';
import { SecretCreateOptions } from '../types/custom'

export default defineComponent({
  name: 'SecretsCreateGuided',

  props: {
    show: {
      type: Boolean,
      required: true
    },
    cluster: {
      type: Object as PropType<KubernetesCluster | null>,
      required: false,
      default: null
    }
  },

  emits: ['close', 'create-secret'],

  setup(props, { emit }) {
    const name = ref('');
    const namespace = ref('default');
    const isSubmitting = ref(false);
    const error = ref('');
    const secretData = ref([{ key: '', value: '', showValue: false }]);

    const isFormValid = computed(() => {
      if (!name.value.trim()) return false;
      if (!namespace.value.trim()) return false;

      // Check if at least one key-value pair is valid
      return secretData.value.some(item => 
        item.key.trim() !== '' && item.value.trim() !== ''
      );
    });

    const addSecretData = () => {
      secretData.value.push({ key: '', value: '', showValue: false });
    };

    const removeSecretData = (index: number) => {
      if (secretData.value.length > 1) {
        secretData.value.splice(index, 1);
      }
    };

    const resetForm = () => {
      name.value = '';
      namespace.value = 'default';
      secretData.value = [{ key: '', value: '' }];
      error.value = '';
      isSubmitting.value = false;
    };

    const closeModal = () => {
      resetForm();
      emit('close');
    };

    const toggleValueVisibility = (index: number) => {
      secretData.value[index].showValue = !secretData.value[index].showValue;
    };


    const createSecret = () => {
      if (!props.cluster) {
        error.value = 'No cluster selected';
        return;
      }

      if (!name.value.trim()) {
        error.value = 'Name is required';
        return;
      }

      if (!namespace.value.trim()) {
        error.value = 'Namespace is required';
        return;
      }

      // Check if at least one key-value pair is valid
      const validData = secretData.value.filter(
        item => item.key.trim() !== '' && item.value.trim() !== ''
      );

      if (validData.length === 0) {
        error.value = 'At least one key-value pair is required';
        return;
      }

      isSubmitting.value = true;

      const stringData = {};
      validData.forEach(item => {
        stringData[item.key.trim()] = item.value;
      });

      const opts: SecretCreateOptions = {
        context: props.cluster.contextName,
        opts: {
          apiVersion: 'v1',
          kind: 'Secret',
          metadata: {
            name: name.value.trim(),
            namespace: namespace.value.trim()
          },
          type: 'Opaque',
          stringData: stringData
        }
      }
      emit('create-secret', opts);
      resetForm();
      closeModal();
    };

    return {
      name,
      namespace,
      secretData,
      isSubmitting,
      error,
      isFormValid,
      addSecretData,
      removeSecretData,
      closeModal,
      createSecret,
      toggleValueVisibility
    };
  }
});
</script>

<template>
  <div v-if="show" class="modal-overlay" @click="closeModal">
    <div class="modal-content" @click.stop>
      <div class="modal-header">
        <h3>Create Secret</h3>
        <button class="close-button" @click="closeModal">&times;</button>
      </div>

      <div class="modal-body">
        <div v-if="error" class="error-message">{{ error }}</div>

        <div class="form-group">
          <label for="name">Name:</label>
          <input 
            id="name" 
            v-model="name" 
            type="text" 
            placeholder="test-secret-1"
            :disabled="isSubmitting"
          />
        </div>

        <div class="form-group">
          <label for="namespace">Namespace:</label>
          <input 
            id="namespace" 
            v-model="namespace" 
            type="text" 
            placeholder="default"
            :disabled="isSubmitting"
          />
        </div>

        <div class="form-section">
          <h4>Secret Data</h4>
          <div 
            v-for="(item, index) in secretData" 
            :key="index" 
            class="secret-data-row"
          >
            <div class="form-group key-field">
              <label :for="`key-${index}`">Key:</label>
              <input 
                :id="`key-${index}`" 
                v-model="item.key" 
                type="text" 
                placeholder="username"
                :disabled="isSubmitting"
              />
            </div>
            <div class="form-group value-field">
              <label :for="`value-${index}`">Value:</label>
              <input 
                :id="`value-${index}`" 
                v-model="item.value" 
                type="password" 
                placeholder="••••••••"
                :disabled="isSubmitting"
              />
            </div>
            <button 
              class="remove-button" 
              @click="removeSecretData(index)"
              :disabled="isSubmitting || secretData.length <= 1"
            >
              &times;
            </button>
          </div>

          <!-- Single add button outside the v-for loop -->
          <button 
            class="add-button" 
            @click="addSecretData"
            :disabled="isSubmitting"
          >
            + Add Another Key-Value Pair
          </button>
        </div>
      </div>

      <div class="modal-footer">
        <button 
          class="cancel-button" 
          @click="closeModal"
          :disabled="isSubmitting"
        >
          Cancel
        </button>
        <button 
          class="create-button" 
          @click="createSecret"
          :disabled="isSubmitting"
        >
          {{ isSubmitting ? 'Creating...' : 'Create' }}
        </button>
      </div>
    </div>
  </div>
</template>

<style src="@/assets/css/CreateResource.css" scoped></style>