Skip to content

Commit

Permalink
feat: modal component for saving any asset specified (#3484)
Browse files Browse the repository at this point in the history
  • Loading branch information
shawnyama authored May 8, 2024
1 parent ab2bef9 commit a1f46f3
Show file tree
Hide file tree
Showing 12 changed files with 346 additions and 302 deletions.
128 changes: 33 additions & 95 deletions packages/client/hmi-client/src/components/code/tera-code.vue
Original file line number Diff line number Diff line change
Expand Up @@ -34,8 +34,8 @@
class="toolbar-button white-space-nowrap"
severity="secondary"
outlined
label="Save as new"
@click="isCodeNamingModalVisible = true"
label="Save as"
@click="showSaveAssetModal = true"
/>
<Dropdown
class="toolbar-button"
Expand Down Expand Up @@ -141,43 +141,15 @@
/>
</template>
</tera-modal>
<tera-modal
v-if="isCodeNamingModalVisible"
@modal-mask-clicked="isCodeNamingModalVisible = false"
@modal-enter-press="isCodeNamingModalVisible = false"
>
<template #header>
<h4>Save code file</h4>
<p>Choose a descriptive and unique name for your code file.</p>
</template>
<template #default>
<form @submit.prevent>
<label class="text-sm" for="model-name">Name</label>
<InputText id="model-name" type="text" placeholder="Filename" v-model="newCodeName" />
</form>
</template>
<template #footer>
<Button
label="Save"
size="large"
@click="
() => {
isCodeNamingModalVisible = false;
saveNewCode();
}
"
/>
<Button
label="Cancel"
size="large"
outlined
severity="secondary"
class="p-button-secondary"
@click="isCodeNamingModalVisible = false"
/>
</template>
</tera-modal>
</Teleport>
<tera-save-asset-modal
v-if="codeText"
:is-visible="showSaveAssetModal"
:asset="codeText"
:assetType="AssetType.Code"
:initial-name="codeName"
@close-modal="showSaveAssetModal = false"
/>
</tera-asset>
</template>

Expand All @@ -192,16 +164,13 @@ import {
getCodeFileAsText,
getProgrammingLanguage,
setFileExtension,
updateCodeAsset,
uploadCodeToProject
updateCodeAsset
} from '@/services/code';
import { useToastService } from '@/services/toast';
import type { Code, CodeFile } from '@/types/Types';
import { AssetType, ProgrammingLanguage } from '@/types/Types';
import TeraModal from '@/components/widgets/tera-modal.vue';
import InputText from 'primevue/inputtext';
import router from '@/router';
import { RouteName } from '@/router/routes';
import Textarea from 'primevue/textarea';
import TeraAsset from '@/components/asset/tera-asset.vue';
import { useProjects } from '@/composables/project';
Expand All @@ -211,6 +180,8 @@ import { cloneDeep, isEmpty, isEqual } from 'lodash';
import { extractDynamicRows } from '@/utils/code-asset';
import ContextMenu from 'primevue/contextmenu';
import { logger } from '@/utils/logger';
import TeraSaveAssetModal from '@/page/project/components/tera-save-asset-modal.vue';
import * as saveAssetService from '@/services/save-asset';
import TeraDirectory from './tera-directory.vue';
import TeraCodeDynamic from './tera-code-dynamic.vue';
Expand All @@ -235,9 +206,8 @@ const editor = ref<VAceEditorInstance['_editor'] | null>(null);
const selectedText = ref('');
const selectionRange = ref<Ace.Range | null>(null);
const progress = ref(0);
const isCodeNamingModalVisible = ref(false);
const showSaveAssetModal = ref(false);
const isDynamicsModalVisible = ref(false);
const newCodeName = ref('');
const newDynamicsName = ref('');
const newDynamicsDescription = ref('');
const programmingLanguage = ref<ProgrammingLanguage>(ProgrammingLanguage.Python);
Expand Down Expand Up @@ -359,37 +329,15 @@ async function saveCode(codeAssetToSave: Code | null = codeAssetCopy.value) {
await refreshCodeAsset(res.id);
toast.success('', `Saved Code Asset`);
highlightDynamics();
isRenamingCode.value = false;
} else {
newCodeName.value = codeName.value;
await saveNewCode();
saveAssetService.saveAs(
new File([codeText.value], setFileExtension(codeName.value, programmingLanguage.value)),
AssetType.Code
);
}
}
async function saveNewCode() {
newCodeName.value = setFileExtension(newCodeName.value, programmingLanguage.value);
const file = new File([codeText.value], newCodeName.value);
const newCode = await uploadCodeToProject(file, progress);
let newAsset;
if (newCode?.id) {
newAsset = await useProjects().addAsset(AssetType.Code, newCode.id);
}
if (!newAsset) {
toast.error('', 'Unable to save file');
return;
}
toast.success('', `File saved as ${codeName.value}`);
codeAsset.value = newCode;
router.push({
name: RouteName.Project,
params: {
pageType: AssetType.Code,
projectId: useProjects().activeProject.value?.id,
assetId: codeAsset?.value?.id
}
});
}
async function refreshCodeAsset(codeId: string) {
const code = await getCodeAsset(codeId);
if (code) {
Expand Down Expand Up @@ -497,34 +445,24 @@ watch(
watch(
() => props.assetId,
async () => {
if (props.assetId === AssetType.Code) {
// FIXME: assetId is 'code' for a newly opened code asset; a hack to get around some weird tab behaviour
isLoading.value = true;
const code = await getCodeAsset(props.assetId);
if (code?.files && Object.keys(code.files)[0]) {
codeAsset.value = code;
codeName.value = code.name ?? '';
const filename = Object.keys(code.files)[0];
codeSelectedFile.value = filename;
codeText.value = (await getCodeFileAsText(props.assetId, filename)) ?? INITIAL_TEXT;
programmingLanguage.value =
code.files[filename].language ?? getProgrammingLanguage(codeName.value);
} else {
codeAsset.value = null;
codeName.value = 'newcode.py';
codeText.value = INITIAL_TEXT;
programmingLanguage.value = ProgrammingLanguage.Python;
} else {
isLoading.value = true;
const code = await getCodeAsset(props.assetId);
if (code && code.files && Object.keys(code.files)[0]) {
codeAsset.value = code;
codeName.value = code.name ?? '';
const filename = Object.keys(code.files)[0];
codeSelectedFile.value = filename;
const text = await getCodeFileAsText(props.assetId, filename);
if (text) {
codeText.value = text;
}
programmingLanguage.value =
code.files[filename].language ?? getProgrammingLanguage(codeName.value);
} else {
codeAsset.value = null;
codeName.value = 'newcode.py';
codeText.value = INITIAL_TEXT;
programmingLanguage.value = ProgrammingLanguage.Python;
}
}
codeAssetCopy.value = cloneDeep(codeAsset.value);
// Remove dynamics of previous file then add the new ones
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
<template>
<Transition name="modal">
<main ref="modal" :style="{ '--z-index': zIndex }" @keyup.enter="$emit('modal-enter-press')">
<main ref="modal" :style="{ '--z-index': zIndex }" @keyup.enter="emit('modal-enter-press')">
<section>
<header>
<slot name="header" />
Expand All @@ -11,7 +11,7 @@
<slot name="footer" />
</footer>
</section>
<aside @click.self="$emit('modalMaskClicked')" />
<aside @click.self="emit('modal-mask-clicked')" />
</main>
</Transition>
</template>
Expand All @@ -33,6 +33,8 @@
import { onMounted, ref } from 'vue';
const emit = defineEmits(['modal-mask-clicked', 'modal-enter-press', 'on-modal-open']);
const modal = ref(null);
defineProps<{
Expand All @@ -53,6 +55,8 @@ onMounted(() => {
});
element.dispatchEvent(event);
}
emit('on-modal-open'); // For triggering a parent event when the modal is opened
});
</script>

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -82,7 +82,7 @@
</div>
</div>
</tera-drilldown>
<tera-save-model-modal
<tera-save-asset-modal
v-if="amr"
:model="amr"
:is-visible="showSaveModelModal"
Expand Down Expand Up @@ -113,7 +113,7 @@ import TeraNotebookJupyterInput from '@/components/llm/tera-notebook-jupyter-inp
import { KernelSessionManager } from '@/services/jupyter';
import { getModelIdFromModelConfigurationId } from '@/services/model-configurations';
import TeraSaveModelModal from '@/page/project/components/tera-save-model-modal.vue';
import TeraSaveAssetModal from '@/page/project/components/tera-save-asset-modal.vue';
import { ModelEditOperationState } from './model-edit-operation';
const props = defineProps<{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -137,7 +137,7 @@
</tera-drilldown-preview>
</template>
</tera-drilldown>
<tera-save-model-modal
<tera-save-asset-modal
v-if="selectedModel"
:model="selectedModel"
:is-visible="showSaveModelModal"
Expand All @@ -157,7 +157,7 @@ import TeraModelDescription from '@/components/model/petrinet/tera-model-descrip
import TeraOperatorPlaceholder from '@/components/operator/tera-operator-placeholder.vue';
import TeraAssetBlock from '@/components/widgets/tera-asset-block.vue';
import { useProjects } from '@/composables/project';
import TeraSaveModelModal from '@/page/project/components/tera-save-model-modal.vue';
import TeraSaveAssetModal from '@/page/project/components/tera-save-asset-modal.vue';
import { getCodeAsset } from '@/services/code';
import { getDocumentAsset } from '@/services/document-assets';
import { KernelSessionManager } from '@/services/jupyter';
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -110,7 +110,7 @@
</tera-drilldown-preview>
</template>
</tera-drilldown>
<tera-save-model-modal
<tera-save-asset-modal
v-if="selectedModel"
:model="selectedModel"
:is-visible="showSaveModelModal"
Expand Down Expand Up @@ -139,7 +139,7 @@ import TeraOperatorPlaceholder from '@/components/operator/tera-operator-placeho
import { useProjects } from '@/composables/project';
import TeraMathEditor from '@/components/mathml/tera-math-editor.vue';
import InputText from 'primevue/inputtext';
import TeraSaveModelModal from '@/page/project/components/tera-save-model-modal.vue';
import TeraSaveAssetModal from '@/page/project/components/tera-save-asset-modal.vue';
import { ModelServiceType } from '@/types/common';
import TeraOutputDropdown from '@/components/drilldown/tera-output-dropdown.vue';
import TeraModelDescription from '@/components/model/petrinet/tera-model-description.vue';
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -104,7 +104,7 @@
</tera-drilldown-preview>
</template>
</tera-drilldown>
<tera-save-model-modal
<tera-save-asset-modal
v-if="stratifiedAmr"
:model="stratifiedAmr"
:is-visible="showSaveModelModal"
Expand All @@ -121,7 +121,7 @@ import TeraDrilldown from '@/components/drilldown/tera-drilldown.vue';
import TeraModelDiagram from '@/components/model/petrinet/model-diagrams/tera-model-diagram.vue';
import TeraOperatorPlaceholder from '@/components/operator/tera-operator-placeholder.vue';
import TeraModelSemanticTables from '@/components/model/tera-model-semantic-tables.vue';
import TeraSaveModelModal from '@/page/project/components/tera-save-model-modal.vue';
import TeraSaveAssetModal from '@/page/project/components/tera-save-asset-modal.vue';
import TeraStratificationGroupForm from '@/components/workflow/ops/stratify-mira/tera-stratification-group-form.vue';
import { createModel, getModel } from '@/services/model';
Expand Down
4 changes: 2 additions & 2 deletions packages/client/hmi-client/src/composables/project.ts
Original file line number Diff line number Diff line change
Expand Up @@ -70,13 +70,13 @@ export function useProjects() {
* If `projectId` is defined, add an asset to that project.
* Otherwise, add an asset to the active project and refresh it.
*
* @param {string} assetType Type of asset to be added, e.g., 'documents'.
* @param {AssetType} assetType Type of asset to be added, e.g., 'documents'.
* @param {string} assetId Id of the asset to be added. This will be the internal id of some asset stored in one of the data service collections.
* @param {Project['id']} [projectId] Id of the project to add the asset to.
* @returns {Promise<string|null>} Id of the added asset, if successful. Null, otherwise.
*/
async function addAsset(
assetType: string,
assetType: AssetType,
assetId: ProjectAsset['id'],
projectId?: Project['id']
): Promise<ProjectAsset['id']> {
Expand Down
Loading

0 comments on commit a1f46f3

Please sign in to comment.