diff --git a/client/src/app/components/organizations/organizations-table/organizations-table.component.html b/client/src/app/components/organizations/organizations-table/organizations-table.component.html
index ed58b633f..8fa006cef 100644
--- a/client/src/app/components/organizations/organizations-table/organizations-table.component.html
+++ b/client/src/app/components/organizations/organizations-table/organizations-table.component.html
@@ -51,17 +51,26 @@
[nzSortFn]="true">
Organization
-
Members |
+
+ Members
+ |
Sub Organizations |
Actions
|
Last Action
|
@@ -97,13 +106,13 @@
+ [tags]="organization.childOrganizations">
- {{ organization.eventCount | number }}
+ {{ organization.activityCount | number }}
|
result$!: Observable>
- connection$!: Observable
+ connection$!: Observable
// PRESENTATION STREAMS
pageInfo$!: Observable
@@ -126,7 +126,7 @@ export class CvcOrganizationsTableComponent implements OnInit {
this.connection$ = this.result$.pipe(
pluck('data', 'organizations'),
filter(isNonNulled)
- ) as Observable
+ ) as Observable
// entity row nodes
this.row$ = this.connection$.pipe(
diff --git a/client/src/app/components/organizations/organizations-table/organizations-table.query.gql b/client/src/app/components/organizations/organizations-table/organizations-table.query.gql
index 8e7846936..48f133dfc 100644
--- a/client/src/app/components/organizations/organizations-table/organizations-table.query.gql
+++ b/client/src/app/components/organizations/organizations-table/organizations-table.query.gql
@@ -32,19 +32,19 @@ query OrganizationsBrowse(
}
}
-fragment OrganizationBrowseTableRowFields on Organization {
+fragment OrganizationBrowseTableRowFields on BrowseOrganization {
id
name
description
- # profileImagePath(size: 256) @include(if: $cardView)
url
memberCount
- eventCount
- subGroups {
- name
+ activityCount
+ mostRecentActivityTimestamp
+ childOrganizations {
id
+ name
}
- mostRecentActivityTimestamp
+ # profileImagePath(size: 256) @include(if: $cardView)
# orgStatsHash @include(if: $cardView) {
# comments
# revisions
diff --git a/client/src/app/generated/civic.apollo-helpers.ts b/client/src/app/generated/civic.apollo-helpers.ts
index 7cfba8731..ee89027c4 100644
--- a/client/src/app/generated/civic.apollo-helpers.ts
+++ b/client/src/app/generated/civic.apollo-helpers.ts
@@ -258,6 +258,35 @@ export type BrowseMolecularProfileEdgeFieldPolicy = {
cursor?: FieldPolicy | FieldReadFunction,
node?: FieldPolicy | FieldReadFunction
};
+export type BrowseOrganizationKeySpecifier = ('activityCount' | 'childOrganizations' | 'createdAt' | 'description' | 'id' | 'memberCount' | 'mostRecentActivityTimestamp' | 'name' | 'parentId' | 'updatedAt' | 'url' | BrowseOrganizationKeySpecifier)[];
+export type BrowseOrganizationFieldPolicy = {
+ activityCount?: FieldPolicy | FieldReadFunction,
+ childOrganizations?: FieldPolicy | FieldReadFunction,
+ createdAt?: FieldPolicy | FieldReadFunction,
+ description?: FieldPolicy | FieldReadFunction,
+ id?: FieldPolicy | FieldReadFunction,
+ memberCount?: FieldPolicy | FieldReadFunction,
+ mostRecentActivityTimestamp?: FieldPolicy | FieldReadFunction,
+ name?: FieldPolicy | FieldReadFunction,
+ parentId?: FieldPolicy | FieldReadFunction,
+ updatedAt?: FieldPolicy | FieldReadFunction,
+ url?: FieldPolicy | FieldReadFunction
+};
+export type BrowseOrganizationConnectionKeySpecifier = ('edges' | 'filteredCount' | 'lastUpdated' | 'nodes' | 'pageCount' | 'pageInfo' | 'totalCount' | BrowseOrganizationConnectionKeySpecifier)[];
+export type BrowseOrganizationConnectionFieldPolicy = {
+ edges?: FieldPolicy | FieldReadFunction,
+ filteredCount?: FieldPolicy | FieldReadFunction,
+ lastUpdated?: FieldPolicy | FieldReadFunction,
+ nodes?: FieldPolicy | FieldReadFunction,
+ pageCount?: FieldPolicy | FieldReadFunction,
+ pageInfo?: FieldPolicy | FieldReadFunction,
+ totalCount?: FieldPolicy | FieldReadFunction
+};
+export type BrowseOrganizationEdgeKeySpecifier = ('cursor' | 'node' | BrowseOrganizationEdgeKeySpecifier)[];
+export type BrowseOrganizationEdgeFieldPolicy = {
+ cursor?: FieldPolicy | FieldReadFunction,
+ node?: FieldPolicy | FieldReadFunction
+};
export type BrowsePhenotypeKeySpecifier = ('assertionCount' | 'evidenceCount' | 'hpoId' | 'id' | 'link' | 'name' | 'url' | BrowsePhenotypeKeySpecifier)[];
export type BrowsePhenotypeFieldPolicy = {
assertionCount?: FieldPolicy | FieldReadFunction,
@@ -1621,19 +1650,6 @@ export type OrganizationFieldPolicy = {
subGroups?: FieldPolicy | FieldReadFunction,
url?: FieldPolicy | FieldReadFunction
};
-export type OrganizationConnectionKeySpecifier = ('edges' | 'nodes' | 'pageCount' | 'pageInfo' | 'totalCount' | OrganizationConnectionKeySpecifier)[];
-export type OrganizationConnectionFieldPolicy = {
- edges?: FieldPolicy | FieldReadFunction,
- nodes?: FieldPolicy | FieldReadFunction,
- pageCount?: FieldPolicy | FieldReadFunction,
- pageInfo?: FieldPolicy | FieldReadFunction,
- totalCount?: FieldPolicy | FieldReadFunction
-};
-export type OrganizationEdgeKeySpecifier = ('cursor' | 'node' | OrganizationEdgeKeySpecifier)[];
-export type OrganizationEdgeFieldPolicy = {
- cursor?: FieldPolicy | FieldReadFunction,
- node?: FieldPolicy | FieldReadFunction
-};
export type OrganizationLeaderboardsKeySpecifier = ('commentsLeaderboard' | 'moderationLeaderboard' | 'revisionsLeaderboard' | 'submissionsLeaderboard' | OrganizationLeaderboardsKeySpecifier)[];
export type OrganizationLeaderboardsFieldPolicy = {
commentsLeaderboard?: FieldPolicy | FieldReadFunction,
@@ -2469,6 +2485,18 @@ export type StrictTypedTypePolicies = {
keyFields?: false | BrowseMolecularProfileEdgeKeySpecifier | (() => undefined | BrowseMolecularProfileEdgeKeySpecifier),
fields?: BrowseMolecularProfileEdgeFieldPolicy,
},
+ BrowseOrganization?: Omit & {
+ keyFields?: false | BrowseOrganizationKeySpecifier | (() => undefined | BrowseOrganizationKeySpecifier),
+ fields?: BrowseOrganizationFieldPolicy,
+ },
+ BrowseOrganizationConnection?: Omit & {
+ keyFields?: false | BrowseOrganizationConnectionKeySpecifier | (() => undefined | BrowseOrganizationConnectionKeySpecifier),
+ fields?: BrowseOrganizationConnectionFieldPolicy,
+ },
+ BrowseOrganizationEdge?: Omit & {
+ keyFields?: false | BrowseOrganizationEdgeKeySpecifier | (() => undefined | BrowseOrganizationEdgeKeySpecifier),
+ fields?: BrowseOrganizationEdgeFieldPolicy,
+ },
BrowsePhenotype?: Omit & {
keyFields?: false | BrowsePhenotypeKeySpecifier | (() => undefined | BrowsePhenotypeKeySpecifier),
fields?: BrowsePhenotypeFieldPolicy,
@@ -2985,14 +3013,6 @@ export type StrictTypedTypePolicies = {
keyFields?: false | OrganizationKeySpecifier | (() => undefined | OrganizationKeySpecifier),
fields?: OrganizationFieldPolicy,
},
- OrganizationConnection?: Omit & {
- keyFields?: false | OrganizationConnectionKeySpecifier | (() => undefined | OrganizationConnectionKeySpecifier),
- fields?: OrganizationConnectionFieldPolicy,
- },
- OrganizationEdge?: Omit & {
- keyFields?: false | OrganizationEdgeKeySpecifier | (() => undefined | OrganizationEdgeKeySpecifier),
- fields?: OrganizationEdgeFieldPolicy,
- },
OrganizationLeaderboards?: Omit & {
keyFields?: false | OrganizationLeaderboardsKeySpecifier | (() => undefined | OrganizationLeaderboardsKeySpecifier),
fields?: OrganizationLeaderboardsFieldPolicy,
diff --git a/client/src/app/generated/civic.apollo.ts b/client/src/app/generated/civic.apollo.ts
index 1fd37bdc6..b3da83f60 100644
--- a/client/src/app/generated/civic.apollo.ts
+++ b/client/src/app/generated/civic.apollo.ts
@@ -680,6 +680,49 @@ export type BrowseMolecularProfileEdge = {
node?: Maybe;
};
+export type BrowseOrganization = {
+ __typename: 'BrowseOrganization';
+ activityCount: Scalars['Int'];
+ childOrganizations: Array;
+ createdAt?: Maybe;
+ description: Scalars['String'];
+ id: Scalars['Int'];
+ memberCount: Scalars['Int'];
+ mostRecentActivityTimestamp?: Maybe;
+ name: Scalars['String'];
+ parentId?: Maybe;
+ updatedAt?: Maybe;
+ url: Scalars['String'];
+};
+
+/** The connection type for BrowseOrganization. */
+export type BrowseOrganizationConnection = {
+ __typename: 'BrowseOrganizationConnection';
+ /** A list of edges. */
+ edges: Array;
+ /** The total number of records in this set. */
+ filteredCount: Scalars['Int'];
+ /** The last time the data in this browse table was refreshed */
+ lastUpdated: Scalars['ISO8601DateTime'];
+ /** A list of nodes. */
+ nodes: Array;
+ /** Total number of pages, based on filtered count and pagesize. */
+ pageCount: Scalars['Int'];
+ /** Information to aid in pagination. */
+ pageInfo: PageInfo;
+ /** The total number of records of this type, regardless of any filtering. */
+ totalCount: Scalars['Int'];
+};
+
+/** An edge in a connection. */
+export type BrowseOrganizationEdge = {
+ __typename: 'BrowseOrganizationEdge';
+ /** A cursor for use in pagination. */
+ cursor: Scalars['String'];
+ /** The item at the end of the edge. */
+ node?: Maybe;
+};
+
export type BrowsePhenotype = {
__typename: 'BrowsePhenotype';
assertionCount: Scalars['Int'];
@@ -4072,30 +4115,6 @@ export type OrganizationProfileImagePathArgs = {
size?: InputMaybe;
};
-/** The connection type for Organization. */
-export type OrganizationConnection = {
- __typename: 'OrganizationConnection';
- /** A list of edges. */
- edges: Array;
- /** A list of nodes. */
- nodes: Array;
- /** Total number of pages, based on filtered count and pagesize. */
- pageCount: Scalars['Int'];
- /** Information to aid in pagination. */
- pageInfo: PageInfo;
- /** The total number of records in this filtered collection. */
- totalCount: Scalars['Int'];
-};
-
-/** An edge in a connection. */
-export type OrganizationEdge = {
- __typename: 'OrganizationEdge';
- /** A cursor for use in pagination. */
- cursor: Scalars['String'];
- /** The item at the end of the edge. */
- node?: Maybe;
-};
-
/** Filter on organization id and whether or not to include the organization's subgroups */
export type OrganizationFilter = {
/** The organization ID. */
@@ -4162,7 +4181,10 @@ export type OrganizationSort = {
};
export enum OrganizationSortColumns {
+ ActivityCount = 'ACTIVITY_COUNT',
Id = 'ID',
+ MemberCount = 'MEMBER_COUNT',
+ MostRecentActivityTimestamp = 'MOST_RECENT_ACTIVITY_TIMESTAMP',
Name = 'NAME'
}
@@ -4294,7 +4316,7 @@ export type Query = {
organization?: Maybe;
organizationLeaderboards: OrganizationLeaderboards;
/** List and filter organizations. */
- organizations: OrganizationConnection;
+ organizations: BrowseOrganizationConnection;
/** Find a phenotype by CIViC ID */
phenotype?: Maybe;
/** Retrieve popover fields for a specific phenotype. */
@@ -7368,9 +7390,9 @@ export type OrganizationsBrowseQueryVariables = Exact<{
}>;
-export type OrganizationsBrowseQuery = { __typename: 'Query', organizations: { __typename: 'OrganizationConnection', totalCount: number, pageInfo: { __typename: 'PageInfo', hasNextPage: boolean, hasPreviousPage: boolean, startCursor?: string | undefined, endCursor?: string | undefined }, edges: Array<{ __typename: 'OrganizationEdge', cursor: string, node?: { __typename: 'Organization', id: number, name: string, description: string, url: string, memberCount: number, eventCount: number, mostRecentActivityTimestamp?: any | undefined, subGroups: Array<{ __typename: 'Organization', name: string, id: number }> } | undefined }> } };
+export type OrganizationsBrowseQuery = { __typename: 'Query', organizations: { __typename: 'BrowseOrganizationConnection', totalCount: number, pageInfo: { __typename: 'PageInfo', hasNextPage: boolean, hasPreviousPage: boolean, startCursor?: string | undefined, endCursor?: string | undefined }, edges: Array<{ __typename: 'BrowseOrganizationEdge', cursor: string, node?: { __typename: 'BrowseOrganization', id: number, name: string, description: string, url: string, memberCount: number, activityCount: number, mostRecentActivityTimestamp?: any | undefined, childOrganizations: Array<{ __typename: 'Organization', id: number, name: string }> } | undefined }> } };
-export type OrganizationBrowseTableRowFieldsFragment = { __typename: 'Organization', id: number, name: string, description: string, url: string, memberCount: number, eventCount: number, mostRecentActivityTimestamp?: any | undefined, subGroups: Array<{ __typename: 'Organization', name: string, id: number }> };
+export type OrganizationBrowseTableRowFieldsFragment = { __typename: 'BrowseOrganization', id: number, name: string, description: string, url: string, memberCount: number, activityCount: number, mostRecentActivityTimestamp?: any | undefined, childOrganizations: Array<{ __typename: 'Organization', id: number, name: string }> };
export type PhenotypePopoverQueryVariables = Exact<{
phenotypeId: Scalars['Int'];
@@ -9673,18 +9695,18 @@ export const OrgPopoverFragmentDoc = gql`
}
`;
export const OrganizationBrowseTableRowFieldsFragmentDoc = gql`
- fragment OrganizationBrowseTableRowFields on Organization {
+ fragment OrganizationBrowseTableRowFields on BrowseOrganization {
id
name
description
url
memberCount
- eventCount
- subGroups {
- name
+ activityCount
+ mostRecentActivityTimestamp
+ childOrganizations {
id
+ name
}
- mostRecentActivityTimestamp
}
`;
export const PhenotypeBrowseTableRowFieldsFragmentDoc = gql`
diff --git a/client/src/app/generated/server.model.graphql b/client/src/app/generated/server.model.graphql
index e213f55ec..156e2029c 100644
--- a/client/src/app/generated/server.model.graphql
+++ b/client/src/app/generated/server.model.graphql
@@ -1123,6 +1123,75 @@ type BrowseMolecularProfileEdge {
node: BrowseMolecularProfile
}
+type BrowseOrganization {
+ activityCount: Int!
+ childOrganizations: [Organization!]!
+ createdAt: ISO8601DateTime
+ description: String!
+ id: Int!
+ memberCount: Int!
+ mostRecentActivityTimestamp: ISO8601DateTime
+ name: String!
+ parentId: Int
+ updatedAt: ISO8601DateTime
+ url: String!
+}
+
+"""
+The connection type for BrowseOrganization.
+"""
+type BrowseOrganizationConnection {
+ """
+ A list of edges.
+ """
+ edges: [BrowseOrganizationEdge!]!
+
+ """
+ The total number of records in this set.
+ """
+ filteredCount: Int!
+
+ """
+ The last time the data in this browse table was refreshed
+ """
+ lastUpdated: ISO8601DateTime!
+
+ """
+ A list of nodes.
+ """
+ nodes: [BrowseOrganization!]!
+
+ """
+ Total number of pages, based on filtered count and pagesize.
+ """
+ pageCount: Int!
+
+ """
+ Information to aid in pagination.
+ """
+ pageInfo: PageInfo!
+
+ """
+ The total number of records of this type, regardless of any filtering.
+ """
+ totalCount: Int!
+}
+
+"""
+An edge in a connection.
+"""
+type BrowseOrganizationEdge {
+ """
+ A cursor for use in pagination.
+ """
+ cursor: String!
+
+ """
+ The item at the end of the edge.
+ """
+ node: BrowseOrganization
+}
+
type BrowsePhenotype {
assertionCount: Int!
evidenceCount: Int!
@@ -6742,51 +6811,6 @@ type Organization {
url: String!
}
-"""
-The connection type for Organization.
-"""
-type OrganizationConnection {
- """
- A list of edges.
- """
- edges: [OrganizationEdge!]!
-
- """
- A list of nodes.
- """
- nodes: [Organization!]!
-
- """
- Total number of pages, based on filtered count and pagesize.
- """
- pageCount: Int!
-
- """
- Information to aid in pagination.
- """
- pageInfo: PageInfo!
-
- """
- The total number of records in this filtered collection.
- """
- totalCount: Int!
-}
-
-"""
-An edge in a connection.
-"""
-type OrganizationEdge {
- """
- A cursor for use in pagination.
- """
- cursor: String!
-
- """
- The item at the end of the edge.
- """
- node: Organization
-}
-
"""
Filter on organization id and whether or not to include the organization's subgroups
"""
@@ -6915,7 +6939,10 @@ input OrganizationSort {
}
enum OrganizationSortColumns {
+ ACTIVITY_COUNT
ID
+ MEMBER_COUNT
+ MOST_RECENT_ACTIVITY_TIMESTAMP
NAME
}
@@ -7954,7 +7981,7 @@ type Query {
Columm and direction to sort evidence on.
"""
sortBy: OrganizationSort
- ): OrganizationConnection!
+ ): BrowseOrganizationConnection!
"""
Find a phenotype by CIViC ID
diff --git a/client/src/app/generated/server.schema.json b/client/src/app/generated/server.schema.json
index 69e19aa40..d55e06ffa 100644
--- a/client/src/app/generated/server.schema.json
+++ b/client/src/app/generated/server.schema.json
@@ -5268,6 +5268,363 @@
"enumValues": null,
"possibleTypes": null
},
+ {
+ "kind": "OBJECT",
+ "name": "BrowseOrganization",
+ "description": null,
+ "fields": [
+ {
+ "name": "activityCount",
+ "description": null,
+ "args": [],
+ "type": {
+ "kind": "NON_NULL",
+ "name": null,
+ "ofType": {
+ "kind": "SCALAR",
+ "name": "Int",
+ "ofType": null
+ }
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
+ "name": "childOrganizations",
+ "description": null,
+ "args": [],
+ "type": {
+ "kind": "NON_NULL",
+ "name": null,
+ "ofType": {
+ "kind": "LIST",
+ "name": null,
+ "ofType": {
+ "kind": "NON_NULL",
+ "name": null,
+ "ofType": {
+ "kind": "OBJECT",
+ "name": "Organization",
+ "ofType": null
+ }
+ }
+ }
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
+ "name": "createdAt",
+ "description": null,
+ "args": [],
+ "type": {
+ "kind": "SCALAR",
+ "name": "ISO8601DateTime",
+ "ofType": null
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
+ "name": "description",
+ "description": null,
+ "args": [],
+ "type": {
+ "kind": "NON_NULL",
+ "name": null,
+ "ofType": {
+ "kind": "SCALAR",
+ "name": "String",
+ "ofType": null
+ }
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
+ "name": "id",
+ "description": null,
+ "args": [],
+ "type": {
+ "kind": "NON_NULL",
+ "name": null,
+ "ofType": {
+ "kind": "SCALAR",
+ "name": "Int",
+ "ofType": null
+ }
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
+ "name": "memberCount",
+ "description": null,
+ "args": [],
+ "type": {
+ "kind": "NON_NULL",
+ "name": null,
+ "ofType": {
+ "kind": "SCALAR",
+ "name": "Int",
+ "ofType": null
+ }
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
+ "name": "mostRecentActivityTimestamp",
+ "description": null,
+ "args": [],
+ "type": {
+ "kind": "SCALAR",
+ "name": "ISO8601DateTime",
+ "ofType": null
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
+ "name": "name",
+ "description": null,
+ "args": [],
+ "type": {
+ "kind": "NON_NULL",
+ "name": null,
+ "ofType": {
+ "kind": "SCALAR",
+ "name": "String",
+ "ofType": null
+ }
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
+ "name": "parentId",
+ "description": null,
+ "args": [],
+ "type": {
+ "kind": "SCALAR",
+ "name": "Int",
+ "ofType": null
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
+ "name": "updatedAt",
+ "description": null,
+ "args": [],
+ "type": {
+ "kind": "SCALAR",
+ "name": "ISO8601DateTime",
+ "ofType": null
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
+ "name": "url",
+ "description": null,
+ "args": [],
+ "type": {
+ "kind": "NON_NULL",
+ "name": null,
+ "ofType": {
+ "kind": "SCALAR",
+ "name": "String",
+ "ofType": null
+ }
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ }
+ ],
+ "inputFields": null,
+ "interfaces": [],
+ "enumValues": null,
+ "possibleTypes": null
+ },
+ {
+ "kind": "OBJECT",
+ "name": "BrowseOrganizationConnection",
+ "description": "The connection type for BrowseOrganization.",
+ "fields": [
+ {
+ "name": "edges",
+ "description": "A list of edges.",
+ "args": [],
+ "type": {
+ "kind": "NON_NULL",
+ "name": null,
+ "ofType": {
+ "kind": "LIST",
+ "name": null,
+ "ofType": {
+ "kind": "NON_NULL",
+ "name": null,
+ "ofType": {
+ "kind": "OBJECT",
+ "name": "BrowseOrganizationEdge",
+ "ofType": null
+ }
+ }
+ }
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
+ "name": "filteredCount",
+ "description": "The total number of records in this set.",
+ "args": [],
+ "type": {
+ "kind": "NON_NULL",
+ "name": null,
+ "ofType": {
+ "kind": "SCALAR",
+ "name": "Int",
+ "ofType": null
+ }
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
+ "name": "lastUpdated",
+ "description": "The last time the data in this browse table was refreshed",
+ "args": [],
+ "type": {
+ "kind": "NON_NULL",
+ "name": null,
+ "ofType": {
+ "kind": "SCALAR",
+ "name": "ISO8601DateTime",
+ "ofType": null
+ }
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
+ "name": "nodes",
+ "description": "A list of nodes.",
+ "args": [],
+ "type": {
+ "kind": "NON_NULL",
+ "name": null,
+ "ofType": {
+ "kind": "LIST",
+ "name": null,
+ "ofType": {
+ "kind": "NON_NULL",
+ "name": null,
+ "ofType": {
+ "kind": "OBJECT",
+ "name": "BrowseOrganization",
+ "ofType": null
+ }
+ }
+ }
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
+ "name": "pageCount",
+ "description": "Total number of pages, based on filtered count and pagesize.",
+ "args": [],
+ "type": {
+ "kind": "NON_NULL",
+ "name": null,
+ "ofType": {
+ "kind": "SCALAR",
+ "name": "Int",
+ "ofType": null
+ }
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
+ "name": "pageInfo",
+ "description": "Information to aid in pagination.",
+ "args": [],
+ "type": {
+ "kind": "NON_NULL",
+ "name": null,
+ "ofType": {
+ "kind": "OBJECT",
+ "name": "PageInfo",
+ "ofType": null
+ }
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
+ "name": "totalCount",
+ "description": "The total number of records of this type, regardless of any filtering.",
+ "args": [],
+ "type": {
+ "kind": "NON_NULL",
+ "name": null,
+ "ofType": {
+ "kind": "SCALAR",
+ "name": "Int",
+ "ofType": null
+ }
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ }
+ ],
+ "inputFields": null,
+ "interfaces": [],
+ "enumValues": null,
+ "possibleTypes": null
+ },
+ {
+ "kind": "OBJECT",
+ "name": "BrowseOrganizationEdge",
+ "description": "An edge in a connection.",
+ "fields": [
+ {
+ "name": "cursor",
+ "description": "A cursor for use in pagination.",
+ "args": [],
+ "type": {
+ "kind": "NON_NULL",
+ "name": null,
+ "ofType": {
+ "kind": "SCALAR",
+ "name": "String",
+ "ofType": null
+ }
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
+ "name": "node",
+ "description": "The item at the end of the edge.",
+ "args": [],
+ "type": {
+ "kind": "OBJECT",
+ "name": "BrowseOrganization",
+ "ofType": null
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ }
+ ],
+ "inputFields": null,
+ "interfaces": [],
+ "enumValues": null,
+ "possibleTypes": null
+ },
{
"kind": "OBJECT",
"name": "BrowsePhenotype",
@@ -32151,152 +32508,6 @@
"enumValues": null,
"possibleTypes": null
},
- {
- "kind": "OBJECT",
- "name": "OrganizationConnection",
- "description": "The connection type for Organization.",
- "fields": [
- {
- "name": "edges",
- "description": "A list of edges.",
- "args": [],
- "type": {
- "kind": "NON_NULL",
- "name": null,
- "ofType": {
- "kind": "LIST",
- "name": null,
- "ofType": {
- "kind": "NON_NULL",
- "name": null,
- "ofType": {
- "kind": "OBJECT",
- "name": "OrganizationEdge",
- "ofType": null
- }
- }
- }
- },
- "isDeprecated": false,
- "deprecationReason": null
- },
- {
- "name": "nodes",
- "description": "A list of nodes.",
- "args": [],
- "type": {
- "kind": "NON_NULL",
- "name": null,
- "ofType": {
- "kind": "LIST",
- "name": null,
- "ofType": {
- "kind": "NON_NULL",
- "name": null,
- "ofType": {
- "kind": "OBJECT",
- "name": "Organization",
- "ofType": null
- }
- }
- }
- },
- "isDeprecated": false,
- "deprecationReason": null
- },
- {
- "name": "pageCount",
- "description": "Total number of pages, based on filtered count and pagesize.",
- "args": [],
- "type": {
- "kind": "NON_NULL",
- "name": null,
- "ofType": {
- "kind": "SCALAR",
- "name": "Int",
- "ofType": null
- }
- },
- "isDeprecated": false,
- "deprecationReason": null
- },
- {
- "name": "pageInfo",
- "description": "Information to aid in pagination.",
- "args": [],
- "type": {
- "kind": "NON_NULL",
- "name": null,
- "ofType": {
- "kind": "OBJECT",
- "name": "PageInfo",
- "ofType": null
- }
- },
- "isDeprecated": false,
- "deprecationReason": null
- },
- {
- "name": "totalCount",
- "description": "The total number of records in this filtered collection.",
- "args": [],
- "type": {
- "kind": "NON_NULL",
- "name": null,
- "ofType": {
- "kind": "SCALAR",
- "name": "Int",
- "ofType": null
- }
- },
- "isDeprecated": false,
- "deprecationReason": null
- }
- ],
- "inputFields": null,
- "interfaces": [],
- "enumValues": null,
- "possibleTypes": null
- },
- {
- "kind": "OBJECT",
- "name": "OrganizationEdge",
- "description": "An edge in a connection.",
- "fields": [
- {
- "name": "cursor",
- "description": "A cursor for use in pagination.",
- "args": [],
- "type": {
- "kind": "NON_NULL",
- "name": null,
- "ofType": {
- "kind": "SCALAR",
- "name": "String",
- "ofType": null
- }
- },
- "isDeprecated": false,
- "deprecationReason": null
- },
- {
- "name": "node",
- "description": "The item at the end of the edge.",
- "args": [],
- "type": {
- "kind": "OBJECT",
- "name": "Organization",
- "ofType": null
- },
- "isDeprecated": false,
- "deprecationReason": null
- }
- ],
- "inputFields": null,
- "interfaces": [],
- "enumValues": null,
- "possibleTypes": null
- },
{
"kind": "INPUT_OBJECT",
"name": "OrganizationFilter",
@@ -32773,6 +32984,24 @@
"description": null,
"isDeprecated": false,
"deprecationReason": null
+ },
+ {
+ "name": "ACTIVITY_COUNT",
+ "description": null,
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
+ "name": "MEMBER_COUNT",
+ "description": null,
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
+ "name": "MOST_RECENT_ACTIVITY_TIMESTAMP",
+ "description": null,
+ "isDeprecated": false,
+ "deprecationReason": null
}
],
"possibleTypes": null
@@ -36866,7 +37095,7 @@
"name": null,
"ofType": {
"kind": "OBJECT",
- "name": "OrganizationConnection",
+ "name": "BrowseOrganizationConnection",
"ofType": null
}
},
diff --git a/server/Gemfile b/server/Gemfile
index 046a1fa9f..63b23dc55 100644
--- a/server/Gemfile
+++ b/server/Gemfile
@@ -31,6 +31,9 @@ gem 'scenic', '~>1.5.4'
#entrez symbol downloads
gem 'net-ftp', '~>0.3.3'
+#NCIt term download
+gem 'rubyzip', '~>2.3.2'
+
#higher performance json encoding
gem 'oj', '~> 3.16.3'
diff --git a/server/Gemfile.lock b/server/Gemfile.lock
index 8ac7bd9fd..1318e8fe5 100644
--- a/server/Gemfile.lock
+++ b/server/Gemfile.lock
@@ -418,6 +418,7 @@ GEM
ffi (~> 1.12)
ruby2_keywords (0.0.5)
ruby_dig (0.0.2)
+ rubyzip (2.3.2)
sanitize (6.0.2)
crass (~> 1.0.2)
nokogiri (>= 1.12.0)
@@ -576,6 +577,7 @@ DEPENDENCIES
rack-mini-profiler (~> 2.0)
rails (~> 7.1)
rinku (~> 2.0.6)
+ rubyzip (~> 2.3.2)
sanitize (~> 6.0.2)
sass-rails (>= 6)
scenic (~> 1.5.4)
diff --git a/server/app/graphql/resolvers/top_level_organizations.rb b/server/app/graphql/resolvers/top_level_organizations.rb
index baa0d155f..e0a40be2d 100644
--- a/server/app/graphql/resolvers/top_level_organizations.rb
+++ b/server/app/graphql/resolvers/top_level_organizations.rb
@@ -4,26 +4,32 @@
class Resolvers::TopLevelOrganizations < GraphQL::Schema::Resolver
include SearchObject.module(:graphql)
- type Types::Entities::OrganizationType.connection_type, null: false
+ type Types::BrowseTables::BrowseOrganizationType.connection_type, null: false
description 'List and filter organizations.'
- scope { Organization.order(:name) }
+ scope { MaterializedViews::OrganizationBrowseTableRow.order(:name) }
option(:id, type: GraphQL::Types::Int, description: 'Exact match filtering on the id of the organization.') do |scope, value |
- scope.where("organizations.id = ?", value)
+ scope.where(id: value)
end
option(:name, type: GraphQL::Types::String, description: 'Substring filtering on the name of the organization.') do |scope, value|
- scope.where("organizations.name ILIKE ?", "%#{value}%")
+ scope.where("name ILIKE ?", "%#{value}%")
end
option :sort_by, type: Types::BrowseTables::OrganizationSortType, description: 'Columm and direction to sort evidence on.' do |scope, value|
case value.column
when 'ID'
- scope.reorder("organizations.id #{value.direction}")
+ scope.reorder("id #{value.direction}")
when 'NAME'
- scope.reorder("organizations.name #{value.direction}")
+ scope.reorder("name #{value.direction}")
+ when 'ACTIVITY_COUNT'
+ scope.reorder("activity_count #{value.direction}")
+ when 'MEMBER_COUNT'
+ scope.reorder("member_count #{value.direction}")
+ when 'MOST_RECENT_ACTIVITY_TIMESTAMP'
+ scope.reorder("most_recent_activity_timestamp #{value.direction}")
end
end
end
diff --git a/server/app/graphql/types/browse_tables/browse_organization_type.rb b/server/app/graphql/types/browse_tables/browse_organization_type.rb
new file mode 100644
index 000000000..795cd33d1
--- /dev/null
+++ b/server/app/graphql/types/browse_tables/browse_organization_type.rb
@@ -0,0 +1,23 @@
+module Types::BrowseTables
+ class BrowseOrganizationType < Types::BaseObject
+ connection_type_class(Types::Connections::BrowseTableConnection)
+
+ field :id, Int, null: false
+ field :name, String, null: false
+ field :url, String, null: false
+ field :description, String, null: false
+ field :parent_id, Int, null: true
+ field :created_at, GraphQL::Types::ISO8601DateTime, null: true
+ field :updated_at, GraphQL::Types::ISO8601DateTime, null: true
+ field :most_recent_activity_timestamp, GraphQL::Types::ISO8601DateTime, null: true
+ field :activity_count, Int, null: false
+ field :member_count, Int, null: false
+ field :child_organizations, [Types::Entities::OrganizationType], null: false
+
+ def child_organizations
+ Array(object.child_organizations)
+ .sort_by { |f| f['child_name'] }
+ .map { |f| { id: f['child_id'], name: f['child_name']} }
+ end
+ end
+end
\ No newline at end of file
diff --git a/server/app/graphql/types/browse_tables/organization_sort_columns.rb b/server/app/graphql/types/browse_tables/organization_sort_columns.rb
index 2e3d9bbab..a539093ac 100644
--- a/server/app/graphql/types/browse_tables/organization_sort_columns.rb
+++ b/server/app/graphql/types/browse_tables/organization_sort_columns.rb
@@ -2,5 +2,8 @@ module Types::BrowseTables
class OrganizationSortColumns < Types::BaseEnum
value 'ID'
value 'NAME'
+ value 'ACTIVITY_COUNT'
+ value 'MEMBER_COUNT'
+ value 'MOST_RECENT_ACTIVITY_TIMESTAMP'
end
end
diff --git a/server/app/jobs/update_nci_thesaurus.rb b/server/app/jobs/update_nci_thesaurus.rb
index 50c290228..bdefd86d6 100644
--- a/server/app/jobs/update_nci_thesaurus.rb
+++ b/server/app/jobs/update_nci_thesaurus.rb
@@ -34,7 +34,7 @@ def remove_download
end
def latest_ncit_path
- "https://stars.renci.org/var/NCIt/ncit.obo"
+ "https://evs.nci.nih.gov/ftp1/NCI_Thesaurus/Thesaurus.FLAT.zip"
end
end
diff --git a/server/app/lib/importer/nci_thesaurus_mirror.rb b/server/app/lib/importer/nci_thesaurus_mirror.rb
index d1a4ece59..8368c9a7d 100644
--- a/server/app/lib/importer/nci_thesaurus_mirror.rb
+++ b/server/app/lib/importer/nci_thesaurus_mirror.rb
@@ -1,14 +1,25 @@
+require "csv"
+require "zip"
+
module Importer
class NciThesaurusMirror
attr_reader :parser, :version
def initialize(path, version = Time.now.utc.iso8601)
- @parser = Obo::Parser.new(path)
+ zip_file = Zip::File.open(path)
+ entry = zip_file.glob('*.txt').first
+ csv_text = entry.get_input_stream.read
+ @parser = CSV.parse(
+ csv_text,
+ col_sep: "\t",
+ liberal_parsing: true,
+ headers: ['code', 'concept_iri', 'parents', 'synonyms', 'definition', 'display_name', 'concept_status', 'semantic_type', 'concept_in_subset'],
+ )
@version = version
end
def import
- parser.elements.each do |elem|
+ parser.each do |elem|
if valid_entry?(elem)
create_object_from_entry(elem)
end
@@ -16,33 +27,19 @@ def import
end
def valid_entry?(entry)
- semantic_types = semantic_types(entry)
- obsolete_concepts = obsolete_concepts(entry)
- (entry['id'].present? && entry['name'].present? && entry.respond_to?(:name) && entry.name == 'Term' &&
- (semantic_types & valid_semantic_types).length > 0 &&
- (obsolete_concepts & ['Obsolete_Concept']).length == 0)
- end
-
- def semantic_types(entry)
- matcher = /^NCIT:P106 "(?.+)"/
- entry['property_value'].map { |s| s.match(matcher) }.compact.map { |s| s[:semantic_type] }
+ valid_semantic_types.include?(entry['semantic_type']) && entry['concept_status'].nil?
end
def valid_semantic_types
['Pharmacologic Substance', 'Pharmacological Substance', 'Clinical Drug', 'Therapeutic or Preventive Procedure', 'Hazardous or Poisonous Substance']
end
- def obsolete_concepts(entry)
- matcher = /^NCIT:P310 "(?.+)"/
- entry['property_value'].map { |s| s.match(matcher) }.compact.map { |s| s[:obsolete_concept] }
- end
-
def create_object_from_entry(entry)
- name = Therapy.capitalize_name(entry['name'])
- ncit_id = entry['id'].sub('NCIT:', '')
+ synonyms = entry['synonyms'].split('|').map{|s| Therapy.capitalize_name(s)}
+ name = synonyms.shift()
+ ncit_id = entry['code']
therapy = ::Therapy.where(ncit_id: ncit_id).first_or_initialize
therapy.name = name
- synonyms = process_synonyms(entry['synonym']).uniq
synonyms.each do |syn|
therapy_alias = ::TherapyAlias.where(name: syn).first_or_create
if !therapy.therapy_aliases.map{|a| a.name.downcase}.include?(syn.downcase) && !(syn.downcase == therapy.name.downcase)
@@ -51,25 +48,6 @@ def create_object_from_entry(entry)
end
therapy.save
end
-
- def process_synonyms(synonym_element)
- vals = if synonym_element.blank?
- []
- elsif synonym_element.is_a?(String)
- [extract_synonym(synonym_element)]
- elsif synonym_element.is_a?(Array)
- synonym_element.map { |s| extract_synonym(s) }
- end
- vals.compact
- end
-
- def extract_synonym(value)
- if match_data = value.match(/^"(?.+)" EXACT \[.*\]/)
- Therapy.capitalize_name(match_data[:name])
- else
- nil
- end
- end
end
end
diff --git a/server/app/models/materialized_views/organization_browse_table_row.rb b/server/app/models/materialized_views/organization_browse_table_row.rb
new file mode 100644
index 000000000..4206d2e8c
--- /dev/null
+++ b/server/app/models/materialized_views/organization_browse_table_row.rb
@@ -0,0 +1,2 @@
+class MaterializedViews::OrganizationBrowseTableRow < MaterializedViews::MaterializedView
+end
\ No newline at end of file
diff --git a/server/db/migrate/20240625182325_create_organization_browse_table_rows.rb b/server/db/migrate/20240625182325_create_organization_browse_table_rows.rb
new file mode 100644
index 000000000..dd47443f9
--- /dev/null
+++ b/server/db/migrate/20240625182325_create_organization_browse_table_rows.rb
@@ -0,0 +1,5 @@
+class CreateOrganizationBrowseTableRows < ActiveRecord::Migration[7.1]
+ def change
+ create_view :organization_browse_table_rows, materialized: true
+ end
+end
diff --git a/server/db/schema.rb b/server/db/schema.rb
index 0b3bf90cb..3f99f9f3a 100644
--- a/server/db/schema.rb
+++ b/server/db/schema.rb
@@ -10,7 +10,9 @@
#
# It's strongly recommended that you check this file into your version control system.
+
ActiveRecord::Schema[7.1].define(version: 2024_06_28_151626) do
+
# These are extensions that must be enabled in order to support this database
enable_extension "plpgsql"
@@ -1399,6 +1401,7 @@
LEFT JOIN organizations child ON ((child.parent_id = organizations.id)))
GROUP BY organizations.id;
SQL
+
create_view "user_browse_table_rows", materialized: true, sql_definition: <<-SQL
SELECT users.id,
users.email,
diff --git a/server/db/views/organization_browse_table_rows_v01.sql b/server/db/views/organization_browse_table_rows_v01.sql
new file mode 100644
index 000000000..728b5750d
--- /dev/null
+++ b/server/db/views/organization_browse_table_rows_v01.sql
@@ -0,0 +1,16 @@
+SELECT organizations.id,
+ organizations.name,
+ organizations.url,
+ organizations.description,
+ organizations.parent_id,
+ organizations.created_at,
+ organizations.updated_at,
+ organizations.most_recent_activity_timestamp,
+ COUNT(DISTINCT(activities.id)) as activity_count,
+ COUNT(DISTINCT(affiliations.user_id)) as member_count,
+ json_agg(distinct jsonb_build_object('child_id', child.id, 'child_name', child.name)) FILTER (WHERE child.id IS NOT NULL) as child_organizations
+FROM organizations
+LEFT OUTER JOIN activities on activities.organization_id = organizations.id
+LEFT OUTER JOIN affiliations on affiliations.organization_id = organizations.id
+LEFT OUTER JOIN organizations child on child.parent_id = organizations.id
+GROUP BY organizations.id;
\ No newline at end of file
|