Use standard firstSeed/seedCount fallback for workflows with no name in profile details (#1852)
Fixes #1833 - Add firstSeed and seedCount to workflow information in profile detail API endpoint (tests updated accordingly), update name of model used for limited workflow information to be more accurate - Fix name display in Crawl Workflows list at bottom of Profile detail page to be consistent with rest of application --------- Co-authored-by: Emma Segal-Grossman <hi@emma.cafe>
This commit is contained in:
parent
a85f9496b0
commit
4edc05d503
@ -23,7 +23,7 @@ from .models import (
|
||||
ConfigRevision,
|
||||
CrawlConfig,
|
||||
CrawlConfigOut,
|
||||
CrawlConfigIdNameOut,
|
||||
CrawlConfigProfileOut,
|
||||
CrawlOut,
|
||||
EmptyStr,
|
||||
UpdateCrawlConfig,
|
||||
@ -547,17 +547,24 @@ class CrawlConfigOps:
|
||||
|
||||
return configs, total
|
||||
|
||||
async def get_crawl_config_ids_for_profile(
|
||||
self, profileid: UUID, org: Optional[Organization] = None
|
||||
async def get_crawl_config_info_for_profile(
|
||||
self, profileid: UUID, org: Organization
|
||||
):
|
||||
"""Return all crawl configs that are associated with a given profileid"""
|
||||
query = {"profileid": profileid, "inactive": {"$ne": True}}
|
||||
if org:
|
||||
query["oid"] = org.id
|
||||
|
||||
cursor = self.crawl_configs.find(query, projection=["_id", "name"])
|
||||
results = await cursor.to_list(length=1000)
|
||||
results = [CrawlConfigIdNameOut.from_dict(res) for res in results]
|
||||
results = []
|
||||
|
||||
cursor = self.crawl_configs.find(query, projection=["_id"])
|
||||
workflows = await cursor.to_list(length=1000)
|
||||
for workflow_dict in workflows:
|
||||
workflow_out = await self.get_crawl_config_out(
|
||||
workflow_dict.get("_id"), org
|
||||
)
|
||||
results.append(CrawlConfigProfileOut.from_dict(workflow_out.to_dict()))
|
||||
|
||||
return results
|
||||
|
||||
async def get_running_crawl(
|
||||
|
@ -412,10 +412,12 @@ class CrawlConfigOut(CrawlConfigCore, CrawlConfigAdditional):
|
||||
|
||||
|
||||
# ============================================================================
|
||||
class CrawlConfigIdNameOut(BaseMongoModel):
|
||||
"""Crawl Config id and name output only"""
|
||||
class CrawlConfigProfileOut(BaseMongoModel):
|
||||
"""Crawl Config basic info for profiles"""
|
||||
|
||||
name: str
|
||||
firstSeed: str
|
||||
seedCount: int
|
||||
|
||||
|
||||
# ============================================================================
|
||||
@ -1197,7 +1199,7 @@ class Profile(BaseMongoModel):
|
||||
class ProfileWithCrawlConfigs(Profile):
|
||||
"""Profile with list of crawlconfigs using this profile"""
|
||||
|
||||
crawlconfigs: List[CrawlConfigIdNameOut] = []
|
||||
crawlconfigs: List[CrawlConfigProfileOut] = []
|
||||
|
||||
|
||||
# ============================================================================
|
||||
|
@ -336,9 +336,7 @@ class ProfileOps:
|
||||
|
||||
return Profile.from_dict(res)
|
||||
|
||||
async def get_profile_with_configs(
|
||||
self, profileid: UUID, org: Optional[Organization] = None
|
||||
):
|
||||
async def get_profile_with_configs(self, profileid: UUID, org: Organization):
|
||||
"""get profile for api output, with crawlconfigs"""
|
||||
|
||||
profile = await self.get_profile(profileid, org)
|
||||
@ -369,16 +367,14 @@ class ProfileOps:
|
||||
except:
|
||||
return None
|
||||
|
||||
async def get_crawl_configs_for_profile(
|
||||
self, profileid: UUID, org: Optional[Organization] = None
|
||||
):
|
||||
"""Get list of crawl config id, names for that use a particular profile"""
|
||||
async def get_crawl_configs_for_profile(self, profileid: UUID, org: Organization):
|
||||
"""Get list of crawl configs with basic info for that use a particular profile"""
|
||||
|
||||
crawlconfig_names = await self.crawlconfigs.get_crawl_config_ids_for_profile(
|
||||
crawlconfig_info = await self.crawlconfigs.get_crawl_config_info_for_profile(
|
||||
profileid, org
|
||||
)
|
||||
|
||||
return crawlconfig_names
|
||||
return crawlconfig_info
|
||||
|
||||
async def delete_profile(self, profileid: UUID, org: Organization):
|
||||
"""delete profile, if not used in active crawlconfig"""
|
||||
|
@ -238,6 +238,8 @@ def test_get_profile(admin_auth_headers, default_org_id, profile_id, profile_con
|
||||
assert len(crawl_configs) == 1
|
||||
assert crawl_configs[0]["id"] == profile_config_id
|
||||
assert crawl_configs[0]["name"] == "Profile Test Crawl"
|
||||
assert crawl_configs[0]["firstSeed"] == "https://webrecorder.net/"
|
||||
assert crawl_configs[0]["seedCount"] == 1
|
||||
break
|
||||
except:
|
||||
if time.monotonic() - start_time > time_limit:
|
||||
|
@ -1,12 +1,12 @@
|
||||
import { localized, msg, str } from "@lit/localize";
|
||||
import { html, nothing } from "lit";
|
||||
import { html, nothing, type TemplateResult } from "lit";
|
||||
import { customElement, property, query, state } from "lit/decorators.js";
|
||||
import { ifDefined } from "lit/directives/if-defined.js";
|
||||
import { when } from "lit/directives/when.js";
|
||||
import { capitalize } from "lodash/fp";
|
||||
import queryString from "query-string";
|
||||
|
||||
import type { Profile } from "./types";
|
||||
import type { Profile, ProfileWorkflow } from "./types";
|
||||
|
||||
import { TailwindElement } from "@/classes/TailwindElement";
|
||||
import type { Dialog } from "@/components/ui/dialog";
|
||||
@ -339,17 +339,16 @@ export class BrowserProfilesDetail extends TailwindElement {
|
||||
if (this.profile?.crawlconfigs?.length) {
|
||||
return html`<ul>
|
||||
${this.profile.crawlconfigs.map(
|
||||
({ id, name }) => html`
|
||||
(workflow) => html`
|
||||
<li
|
||||
class="border-x border-b first:rounded-t first:border-t last:rounded-b"
|
||||
>
|
||||
<a
|
||||
class="block p-2 transition-colors focus-within:bg-neutral-50 hover:bg-neutral-50"
|
||||
href=${`${this.navigate.orgBasePath}/workflows/crawl/${id}`}
|
||||
href=${`${this.navigate.orgBasePath}/workflows/crawl/${workflow.id}`}
|
||||
@click=${this.navigate.link}
|
||||
>
|
||||
${name ||
|
||||
html`<span class="text-neutral-400">${msg("(no name)")}</span>`}
|
||||
${this.renderWorkflowName(workflow)}
|
||||
</a>
|
||||
</li>
|
||||
`,
|
||||
@ -362,6 +361,31 @@ export class BrowserProfilesDetail extends TailwindElement {
|
||||
</div>`;
|
||||
}
|
||||
|
||||
private renderWorkflowName(workflow: ProfileWorkflow) {
|
||||
if (workflow.name)
|
||||
return html`<span class="truncate">${workflow.name}</span>`;
|
||||
if (!workflow.firstSeed)
|
||||
return html`<span class="truncate font-mono">${workflow.id}</span>
|
||||
<span class="text-neutral-400">${msg("(no name)")}</span>`;
|
||||
const remainder = workflow.seedCount - 1;
|
||||
let nameSuffix: string | TemplateResult<1> = "";
|
||||
if (remainder) {
|
||||
if (remainder === 1) {
|
||||
nameSuffix = html`<span class="ml-2 text-neutral-500"
|
||||
>${msg(str`+${remainder} URL`)}</span
|
||||
>`;
|
||||
} else {
|
||||
nameSuffix = html`<span class="ml-2 text-neutral-500"
|
||||
>${msg(str`+${remainder} URLs`)}</span
|
||||
>`;
|
||||
}
|
||||
}
|
||||
return html`
|
||||
<span class="primaryUrl truncate">${workflow.firstSeed}</span
|
||||
>${nameSuffix}
|
||||
`;
|
||||
}
|
||||
|
||||
private readonly renderVisitedSites = () => {
|
||||
return html`
|
||||
<section class="flex-grow-1 flex flex-col lg:w-[60ch]">
|
||||
|
@ -93,6 +93,13 @@ export type ProfileReplica = {
|
||||
custom?: boolean;
|
||||
};
|
||||
|
||||
export type ProfileWorkflow = {
|
||||
id: string;
|
||||
name: string;
|
||||
firstSeed: string;
|
||||
seedCount: number;
|
||||
};
|
||||
|
||||
export type Profile = {
|
||||
id: string;
|
||||
name: string;
|
||||
@ -105,7 +112,7 @@ export type Profile = {
|
||||
profileId: string;
|
||||
baseProfileName: string;
|
||||
oid: string;
|
||||
crawlconfigs?: { id: string; name: string }[];
|
||||
crawlconfigs?: ProfileWorkflow[];
|
||||
resource?: {
|
||||
name: string;
|
||||
path: string;
|
||||
|
Loading…
Reference in New Issue
Block a user