fix: added pagination in logs and stream page for schema field list (#3093)

This commit is contained in:
Bhargav
2024-03-25 15:12:21 +05:30
committed by GitHub
parent d4b0580205
commit 8dca74b03e
4 changed files with 234 additions and 138 deletions
@@ -251,7 +251,7 @@ describe("Logs testcases", () => {
cy.get('[data-test="menu-link-/streams-item"]').click({ force: true });
cy.get('[data-test="streams-search-stream-input"]').type("e2e_automate");
cy.get('[title="Stream Detail"]').click({ force: true });
cy.get('[title="Stream Detail"]:first').click({ force: true });
cy.get(':nth-child(2) > [data-test="schema-stream-index-select"]').click();
cy.get(".q-virtual-scroll__content").within(() => {
cy.contains("Inverted Index").click();
@@ -261,7 +261,7 @@ describe("Logs testcases", () => {
force: true,
});
cy.get(".col-auto > .q-btn > .q-btn__content").click({ force: true });
cy.get('[title="Explore"]').click({ force: true });
cy.get('[title="Explore"]:first').click({ force: true });
cy.get('[data-test="log-table-column-0-@timestamp"]').should("exist");
});
it("should display error if blank spaces added under stream name and clicked create stream ", () => {
+205 -132
View File
@@ -45,7 +45,8 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
>
No data available.
</div>
<div v-else class="indexDetailsContainer">
<div v-else
class="indexDetailsContainer" style="height: 100vh">
<div class="title" data-test="schema-stream-title-text">
{{ indexData.name }}
</div>
@@ -129,113 +130,133 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
</div>
<!-- Note: Drawer max-height to be dynamically calculated with JS -->
<div class="q-table__container q-table--cell-separator">
<table
class="q-table"
<div
class="q-table__container q-table--cell-separator"
style="margin-bottom: 30px"
>
<q-table
data-test="schema-log-stream-field-mapping-table"
:rows="indexData.schema"
:columns="columns"
:row-key="(row) => 'tr_' + row.name"
:filter="filterField"
:filter-method="filterFieldFn"
:pagination="{ rowsPerPage }"
class="q-table"
id="schemaFieldList"
:rows-per-page-options="[]"
:hidePagination="indexData.schema.length <= rowsPerPage"
dense
>
<thead class="sticky-table-header">
<tr>
<th width="30px">{{ t("logStream.deleteActionLabel") }}</th>
<th>{{ t("logStream.propertyName") }}</th>
<th>{{ t("logStream.propertyType") }}</th>
<th v-if="showFullTextSearchColumn" style="width: 220px">
{{ t("logStream.indexType") }}
</th>
</tr>
</thead>
<tbody>
<tr
v-for="(schema, index) in indexData.schema"
:key="index + '_' + schema.name"
class="list-item"
<template #top-right>
<q-input
data-test="schema-field-search-input"
v-model="filterField"
data-cy="schema-index-field-search-input"
filled
borderless
dense
clearable
debounce="1"
:placeholder="t('search.searchField')"
>
<td class="text-center">
<q-checkbox
v-if="
schema.name !== store.state.zoConfig.timestamp_column
"
:data-test="`schema-stream-delete-${schema.name}-field-fts-key-checkbox`"
v-model="schema.delete"
size="sm"
@click="addDeleteField(schema)"
/>
</td>
<td>{{ schema.name }}</td>
<td>{{ schema.type }}</td>
<td
v-if="showFullTextSearchColumn"
data-test="schema-stream-index-select"
class="text-center"
>
<q-select
v-if="
schema.name !== store.state.zoConfig.timestamp_column
"
v-model="schema.index_type"
:options="streamIndexType"
:popup-content-style="{ textTransform: 'capitalize' }"
color="input-border"
bg-color="input-bg"
class="q-py-sm stream-schema-index-select"
:option-disable="
(_option) => disableOptions(schema, _option)
"
multiple
:max-values="2"
map-options
emit-value
clearable
stack-label
outlined
filled
dense
style="width: 300px"
@update:model-value="markFormDirty(schema.name, 'fts')"
/>
</td>
</tr>
</tbody>
</table>
<template #prepend>
<q-icon name="search" />
</template>
</q-input>
</template>
<template v-slot:body-cell-delete="props">
<q-td class="text-center">
<q-checkbox
v-if="
props.row.name !== store.state.zoConfig.timestamp_column
"
:data-test="`schema-stream-delete-${props.row.name}-field-fts-key-checkbox`"
v-model="props.row.delete"
size="sm"
@click="addDeleteField(props.row)"
/>
</q-td>
</template>
<template v-slot:body-cell-name="props">
<q-td>{{ props.row.name }}</q-td>
</template>
<template v-slot:body-cell-type="props">
<q-td>{{ props.row.type }}</q-td>
</template>
<template v-slot:body-cell-index_type="props">
<q-td
data-test="schema-stream-index-select"
><q-select
v-if="
props.row.name !== store.state.zoConfig.timestamp_column
"
v-model="props.row.index_type"
:options="streamIndexType"
:popup-content-style="{ textTransform: 'capitalize' }"
color="input-border"
bg-color="input-bg"
class="stream-schema-index-select q-py-xs fit q-pa-xs"
size="xs"
:option-disable="
(_option) => disableOptions(props.row, _option)
"
multiple
:max-values="2"
map-options
emit-value
autoclose
clearable
stack-label
outlined
filled
dense
style="width: 300px;"
@update:model-value="markFormDirty(props.row.name, 'fts')"
/>
</q-td>
</template>
<template v-slot:bottom-row>
<q-tr
><q-td colspan="100%">
<div v-if="indexData.schema.length > 0" class="q-mt-sm">
<q-btn
v-bind:disable="deleteFieldList.length == 0"
data-test="schema-delete-button"
class="q-my-sm text-bold btn-delete"
color="warning"
:label="t('logStream.delete')"
text-color="light-text"
padding="sm md"
no-caps
@click="confirmQueryModeChangeDialog = true"
/>
<q-btn
v-bind:disable="!formDirtyFlag"
data-test="schema-update-settings-button"
:label="t('logStream.updateSettings')"
class="q-my-sm text-bold no-border q-ml-md float-right"
color="secondary"
padding="sm xl"
type="submit"
no-caps
/>
<q-btn
v-close-popup="true"
data-test="schema-cancel-button"
class="q-my-sm text-bold float-right q-ml-md"
:label="t('logStream.cancel')"
text-color="light-text"
padding="sm md"
no-caps
/></div></q-td
></q-tr>
</template>
</q-table>
</div>
</div>
<div
v-if="indexData.schema.length > 0"
class="flex q-mt-sm sticky-buttons"
>
<q-btn
v-bind:disable="deleteFieldList.length == 0"
data-test="schema-delete-button"
class="q-my-sm text-bold btn-delete"
color="warning"
:label="t('logStream.delete')"
text-color="light-text"
padding="sm md"
no-caps
@click="confirmQueryModeChangeDialog = true"
/>
<q-btn
v-close-popup="true"
data-test="schema-cancel-button"
class="q-my-sm text-bold"
:label="t('logStream.cancel')"
text-color="light-text"
padding="sm md"
no-caps
/>
<q-btn
v-bind:disable="!formDirtyFlag"
data-test="schema-update-settings-button"
:label="t('logStream.updateSettings')"
class="q-my-sm text-bold no-border q-ml-md"
color="secondary"
padding="sm xl"
type="submit"
no-caps
/>
</div>
</q-form>
<br /><br /><br />
</q-card-section>
</q-card>
<q-card v-else class="column q-pa-md full-height no-wrap">
@@ -296,6 +317,8 @@ export default defineComponent({
const confirmQueryModeChangeDialog = ref(false);
const formDirtyFlag = ref(false);
const loadingState = ref(true);
const rowsPerPage = ref(250);
const filterField = ref("");
const streamIndexType = [
{ label: "Inverted Index", value: "fullTextSearchKey" },
@@ -328,6 +351,7 @@ export default defineComponent({
};
const deleteFields = async () => {
loadingState.value = true;
await streamService
.deleteFields(
store.state.selectedOrganization.identifier,
@@ -335,6 +359,7 @@ export default defineComponent({
deleteFieldList.value
)
.then(async (res) => {
loadingState.value = false;
if (res.data.code == 200) {
q.notify({
color: "positive",
@@ -359,6 +384,7 @@ export default defineComponent({
}
})
.catch((err: any) => {
loadingState.value = false;
console.log(err);
q.notify({
color: "negative",
@@ -541,6 +567,7 @@ export default defineComponent({
settings.partition_keys.concat(added_part_keys);
}
loadingState.value = true;
await streamService
.updateSettings(
store.state.selectedOrganization.identifier,
@@ -549,6 +576,7 @@ export default defineComponent({
settings
)
.then(async (res) => {
loadingState.value = false;
q.notify({
color: "positive",
message: "Stream settings updated successfully.",
@@ -571,6 +599,7 @@ export default defineComponent({
});
})
.catch((err: any) => {
loadingState.value = false;
q.notify({
color: "negative",
message: err.response.data.message,
@@ -624,6 +653,46 @@ export default defineComponent({
return false;
};
const filterFieldFn = (rows: any, terms: any) => {
var filtered = [];
if (terms != "") {
terms = terms.toLowerCase();
for (var i = 0; i < rows.length; i++) {
if (rows[i]["name"].toLowerCase().includes(terms)) {
filtered.push(rows[i]);
}
}
}
return filtered;
};
const columns = [
{
name: "delete",
label: t("logStream.deleteActionLabel"),
align: "center",
sortable: false,
},
{
name: "name",
label: t("logStream.propertyName"),
align: "center",
sortable: true,
},
{
name: "type",
label: t("logStream.propertyType"),
align: "center",
sortable: true,
},
{
name: "index_type",
label: t("logStream.indexType"),
align: "center",
sortable: false,
},
];
return {
t,
q,
@@ -649,6 +718,10 @@ export default defineComponent({
streamIndexType,
disableOptions,
loadingState,
filterFieldFn,
rowsPerPage,
filterField,
columns,
};
},
created() {
@@ -698,7 +771,7 @@ export default defineComponent({
td {
font-size: 0.875rem;
font-weight: 600;
height: 35px;
height: 25px;
padding: 0px 5px;
}
}
@@ -755,39 +828,39 @@ export default defineComponent({
}
}
.sticky-buttons {
position: sticky;
bottom: 0px;
margin: 0 auto;
background-color: var(--q-accent);
box-shadow: 6px 6px 18px var(--q-accent);
justify-content: right;
width: 100%;
padding-right: 20px;
}
// .sticky-buttons {
// position: sticky;
// bottom: 0px;
// margin: 0 auto;
// background-color: var(--q-accent);
// box-shadow: 6px 6px 18px var(--q-accent);
// justify-content: right;
// width: 100%;
// padding-right: 20px;
// }
.btn-delete {
left: 20px;
position: absolute;
}
// .btn-delete {
// left: 20px;
// position: absolute;
// }
.sticky-table-header {
position: sticky;
top: 0px;
background: var(--q-accent);
z-index: 1;
}
// .sticky-table-header {
// position: sticky;
// top: 0px;
// background: var(--q-accent);
// z-index: 1;
// }
.body--dark {
.sticky-table-header {
background: var(--q-dark);
}
// .body--dark {
// .sticky-table-header {
// background: var(--q-dark);
// }
.sticky-buttons {
background-color: var(--q-dark);
box-shadow: 6px 6px 18px var(--q-dark);
}
}
// .sticky-buttons {
// background-color: var(--q-dark);
// box-shadow: 6px 6px 18px var(--q-dark);
// }
// }
</style>
<style lang="scss">
+5
View File
@@ -54,6 +54,7 @@ const defaultObject = {
runQuery: false,
loading: false,
loadingHistogram: false,
loadingStream: false,
shouldIgnoreWatcher: false,
config: {
splitterModel: 20,
@@ -124,6 +125,7 @@ const defaultObject = {
errorCode: 0,
additionalErrorMsg: "",
stream: {
loading: false,
streamLists: <object[]>[],
selectedStream: { label: "", value: "" },
selectedStreamFields: <any>[],
@@ -359,11 +361,13 @@ const useLogs = () => {
async function loadStreamFileds(streamName: string) {
try {
if (streamName != "") {
searchObj.loadingStream = true;
return await getStream(
streamName,
searchObj.data.stream.streamType || "logs",
true
).then((res) => {
searchObj.loadingStream = false;
return res;
});
} else {
@@ -371,6 +375,7 @@ const useLogs = () => {
}
return;
} catch (e: any) {
searchObj.loadingStream = false;
console.log("Error while loading stream fields");
}
}
+22 -4
View File
@@ -59,12 +59,15 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
"
:filter="searchObj.data.stream.filterField"
:filter-method="filterFieldFn"
:pagination="{ rowsPerPage: 10000 }"
:pagination="{ rowsPerPage }"
hide-header
hide-bottom
:wrap-cells="searchObj.meta.resultGrid.wrapCells"
class="field-table full-height"
id="fieldList"
:rows-per-page-options="[]"
:hidePagination="
searchObj.data.stream.selectedStreamFields.length <= rowsPerPage
"
>
<template #body-cell-name="props">
<q-tr :props="props">
@@ -104,7 +107,9 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
:name="
props.row.isInterestingField ? 'info' : 'info_outline'
"
:class="store.state.theme === 'dark' ? '' : 'light-dimmed'"
:class="
store.state.theme === 'dark' ? '' : 'light-dimmed'
"
style="margin-right: 0.375rem"
size="1.1rem"
:title="
@@ -212,7 +217,9 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
? 'info'
: 'info_outline'
"
:class="store.state.theme === 'dark' ? '' : 'light-dimmed'"
:class="
store.state.theme === 'dark' ? '' : 'light-dimmed'
"
style="margin-right: 0.375rem"
size="1.1rem"
:title="
@@ -402,6 +409,15 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
<q-icon name="search" />
</template>
</q-input>
<q-tr v-if="searchObj.loadingStream == true">
<q-td colspan="100%" class="text-bold"
style="opacity: 0.7">
<div class="text-subtitle2 text-weight-bold">
<q-spinner-hourglass size="20px" />
{{ t("confirmDialog.loading") }}
</div>
</q-td>
</q-tr>
</template>
</q-table>
</div>
@@ -468,6 +484,7 @@ export default defineComponent({
{ label: t("search.logs"), value: "logs" },
{ label: t("search.enrichmentTables"), value: "enrichment_tables" },
];
const rowsPerPage = ref(250);
const filterStreamFn = (val: string, update: any) => {
update(() => {
@@ -785,6 +802,7 @@ export default defineComponent({
handleQueryData,
onStreamChange,
addToInterestingFieldList,
rowsPerPage,
};
},
});